ApplicationLifetimeObjects

Topics: Bootstrappers & IoC, Framework Services
Oct 13, 2013 at 6:44 PM
Edited Oct 13, 2013 at 6:50 PM
Hi people, I'm implementing a windows azure notification hub, the example works fine, but when I changed to use the bootstrap of Caliburn, the notification only work if the application is active.

http://www.windowsazure.com/en-us/manage/services/notification-hubs/get-started-notification-hubs-wp8

To work with bootstraper I have to remove/commented the next code in the App.xml
  <Application.ApplicationLifetimeObjects>
        <!--Required object that handles lifetime events for the application-->
        <shell:PhoneApplicationService
            Launching="Application_Launching" Closing="Application_Closing"
            Activated="Application_Activated" Deactivated="Application_Deactivated"/>
    </Application.ApplicationLifetimeObjects>
After remove this snippet of code, and move the creation of Channel of communication with notification hub to Bootstrap code, the notification only reached when application is active
        public Bootstrapper()
        {

            Debug.WriteLine("Bootstrapper: Construtor");
            Start();
            var pa = new PhoneApplicationServiceAdapter(this.PhoneService, this.RootFrame);
            pa.Launching += (s, evt) => { AcquirePushChannel(); };
        }

        #region Notificação implementação        
        protected override void OnLaunch(object sender, Microsoft.Phone.Shell.LaunchingEventArgs e)
        {
            //AcquirePushChannel();
            base.OnLaunch(sender, e);
        }
        protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
        {
            //AcquirePushChannel();
            base.OnStartup(sender, e);
        }
        private void AcquirePushChannel()
        {
            var CurrentChannel = HttpNotificationChannel.Find("MyPushChannel");

            if (CurrentChannel == null)
            {
                CurrentChannel = new HttpNotificationChannel("MyPushChannel");

                Debug.WriteLine("Abrindo conexão com azure");
                //Estabelece conexão com o canal
                CurrentChannel.Open();
                CurrentChannel.BindToShellTile();
                CurrentChannel.BindToShellToast();
            }

            CurrentChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(async (o, args) =>
            {
                Debug.WriteLine("Evento recebido: {0}", args.ChannelUri.ToString());
                var hub = new NotificationHub("myhub", "<CONNECTION TO HUB>");
                await hub.RegisterNativeAsync(args.ChannelUri.ToString());
            });

            CurrentChannel.ShellToastNotificationReceived += (s, evt) =>
            {
                //Criar mensagem de notificação aqui
                var message = String.Join(",", evt.Collection.Values.ToArray());
                Debug.WriteLine("ShellToastNotificationReceived recebido: {0}", message);
                //eventAggregator.Publish(new MessageFromHub(message));
            };
            CurrentChannel.HttpNotificationReceived += (s, evt) =>
            {
                Debug.WriteLine("HttpNotificationReceived recebido: {0}", evt.Notification.Body);
                string message;

                using (System.IO.StreamReader reader = new System.IO.StreamReader(evt.Notification.Body))
                {
                    message = reader.ReadToEnd();
                }
                Debug.WriteLine("HttpNotificationReceived message: {0}", message);
                //eventAggregator.Publish(new MessageFromHub(message));
            };

            CurrentChannel.ErrorOccurred += (s, evt) =>
            {
                Debug.WriteLine("Error recebido: {0}", evt.Message);
            };
            CurrentChannel.ConnectionStatusChanged += (s, evt) =>
            {
                Debug.WriteLine("ConnectionStatusChanged recebido: {0}", evt.ConnectionStatus);
            };

            Debug.WriteLine("Acquire called");

        }
        #endregion
I think I'm doing something wrong, can someone help me?
Oct 14, 2013 at 5:40 AM
Edited Oct 14, 2013 at 5:45 AM
Did you look at the examples for Windows Phone bootstrap wireup? I think you might be alittle confused as to how to wire up the bootstrap...
public class BootStrapper : PhoneBootstrapper
{
      PhoneContainer _container;
     protected override void Configure()
      {
            _container = new PhoneContainer();

            if (!Execute.InDesignMode)
                _container.RegisterPhoneServices(RootFrame);

           _container.PerRequest<MainWindowViewModel>();
           //... SIngleton etc...
          // .. .RegisterSingleton(...) etc
          // ... .RegisterIntance( ... ) etc..
    }

     protected override object GetInstance(Type service, string key)
        {
            return _container.GetInstance(service, key);
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return _container.GetAllInstances(service);
        }

        protected override void BuildUp(object instance)
        {
            _container.BuildUp(instance);
        }

        protected override void OnActivate(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e)
        {


        }

        protected override void OnLaunch(object sender, Microsoft.Phone.Shell.LaunchingEventArgs e)
        {

        }
}
<Application 
    x:Class="XYZ.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
    xmlns:local="clr-namespace:XYZ"      
    >

    <!--Application Resources-->
    <Application.Resources>

        <local:Bootstrapper x:Key="bootstrapper" />           

    </Application.Resources>
if you want to get some notifications/toasts you might have to implement a backgroundtask to do this while application is not active. Which is a separate dll and some extra configurations for phone app itself, not much to do with CM
Oct 14, 2013 at 4:03 PM
Edited Oct 14, 2013 at 4:04 PM
Hi mvermef, I'm using the default template from Caliburn.Micro.Start,
the code is:
        PhoneContainer container;

        public Bootstrapper()
        {

            Debug.WriteLine("Bootstrapper: Construtor");
            Start();
            var pa = new PhoneApplicationServiceAdapter(this.PhoneService, this.RootFrame);
            pa.Launching += (s, evt) => { AcquirePushChannel(); };
        }

        protected override void Configure()
        {
            Debug.WriteLine("Bootstrapper: Configure");
            
            container = new PhoneContainer();
            if (!Execute.InDesignMode)
                container.RegisterPhoneServices(RootFrame, true);
            //container.RegisterSingleton(typeof(IEventAggregator), "eventAggregator", typeof(EventAggregator));
            container.PerRequest<MainPageViewModel>();

            //container.RegisterSingleton(typeof(INotificationManager), "notificationmanager", typeof(NotificationManager));
            AddCustomConventions();
        }
        #region Implementação padrão

        protected override object GetInstance(Type service, string key)
        {
            var instance = container.GetInstance(service, key);
            if (instance != null)
                return instance;

            throw new InvalidOperationException("Could not locate any instances.");
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return container.GetAllInstances(service);
        }

        protected override void BuildUp(object instance)
        {
            container.BuildUp(instance);
        }

        static void AddCustomConventions()
        {
            ConventionManager.AddElementConvention<Pivot>(Pivot.ItemsSourceProperty, "SelectedItem", "SelectionChanged").ApplyBinding =
                (viewModelType, path, property, element, convention) =>
                {
                    if (ConventionManager
                        .GetElementConvention(typeof(ItemsControl))
                        .ApplyBinding(viewModelType, path, property, element, convention))
                    {
                        ConventionManager
                            .ConfigureSelectedItem(element, Pivot.SelectedItemProperty, viewModelType, path);
                        ConventionManager
                            .ApplyHeaderTemplate(element, Pivot.HeaderTemplateProperty, null, viewModelType);
                        return true;
                    }

                    return false;
                };

            ConventionManager.AddElementConvention<Panorama>(Panorama.ItemsSourceProperty, "SelectedItem", "SelectionChanged").ApplyBinding =
                (viewModelType, path, property, element, convention) =>
                {
                    if (ConventionManager
                        .GetElementConvention(typeof(ItemsControl))
                        .ApplyBinding(viewModelType, path, property, element, convention))
                    {
                        ConventionManager
                            .ConfigureSelectedItem(element, Panorama.SelectedItemProperty, viewModelType, path);
                        ConventionManager
                            .ApplyHeaderTemplate(element, Panorama.HeaderTemplateProperty, null, viewModelType);
                        return true;
                    }

                    return false;
                };
        }
        #endregion  
In App.xaml:
<Application
    x:Class="RecursosOnline.Mobile.Store.WP8.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:caliburnMicro="clr-RecursosOnline.Mobile.Store.WP8">

    <!--Application Resources-->
    <Application.Resources>
        <local:LocalizedStrings xmlns:local="clr-RecursosOnline.Mobile.Store.WP8" x:Key="LocalizedStrings"/>
        <caliburnMicro:Bootstrapper x:Key="bootstrapper" />
    </Application.Resources>

    <Application.ApplicationLifetimeObjects>
        <!--Required object that handles lifetime events for the application-->
        <!--<shell:PhoneApplicationService
            Launching="Application_Launching" Closing="Application_Closing"
            Activated="Application_Activated" Deactivated="Application_Deactivated"/>-->

    </Application.ApplicationLifetimeObjects>

</Application>
I imagine that libraries azure make the implementation of tasks in the background, because it works without Caliburn, will investigate a bit more.

Thank you!