domingo, 31 de octubre de 2010

Using PRISM, WCF Ria Services and MVVM together

In this post, I will introduce the usage of prism within WCF Ria Services and the pattern of design Model-View-ViewModel in a few steps.


There are a lof of advantages to use these three concepts: WCF Ria Services give you a lot of work done about the wcf services and authentication, prism enables to decrease the size of your projects in order to load the application quickly and the MVVM pattern does your code more testable, less complex. Furthermore, you will be able to separate the implementation of your project more efficiently using more resources if you apply them.

We start with the steps to apply these concepts:

1.- Create a new Silverlight Business Application.
  (Suggestion) As a suggestion, you may structure the application in Server/Client where:
         - In Server folder will place the server host.
         - In Client, rename the application silverlight project in the same name but ending in .Shell. Also, create a modules folder where all modules will get placed and an util folder where all needed library will get placed too.

2.- For the application silverlight project and all module that will be added, the project must be structured in:
         - View: where every view will be placed in this folder.
         - ViewModel: where every viewmodel of a view will be placed here.

Then, you must include parameters in the constructor for the views or viewmodels of the contexts or entities that you need to receive. For example, in the constructor of the view, there will be a parameter for its view model. These parameters are initialized using Unity.

3.- Add a resource dictionary named ModulesCatalog in the silverlight application. Remember, change the property of this file to Resource. In this resource, all possible modules will be declared:


<cal:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:cal="clr-namespace:Microsoft.Practices.Composite.Modularity;assembly=Microsoft.Practices.Composite">


    <cal:ModuleInfo Ref="SocialSport.Modules.TeamPage.xap"
                      ModuleName="TeamPage"
                      ModuleType="Project.Modules.TeamPage.TeamPageModule, SocialSport.Modules.TeamPage, Version=1.0.0.0"
                      InitializationMode="OnDemand"/>


</cal:ModuleCatalog>


In the Ref attribute, you will type the name of the xap of the module that it will be added in the ClientBin directory of the server host.

In ModuleName, you will name to the module in order to link it when you want to load the module.

In ModuleType, you will include a reference to the initializer class of the module. This will be explained below.

4.- Add a bootstrapper class in the silverlight application with the next code:


namespace Project
{
    using System;
    using System.Windows;
    using Microsoft.Practices.Composite.Modularity;
    using Microsoft.Practices.Composite.UnityExtensions;
    using Microsoft.Practices.Unity;
    using SocialSport.Utils.Controls;
    using SocialSport.ViewModels;


    public partial class Bootstrapper : UnityBootstrapper
    {
        private App _app;


        public Bootstrapper(App app)
        {
            _app = app;


            if (_app.IsRunningOutOfBrowser)
            {
                _app.CheckAndDownloadUpdateCompleted +=
                    new CheckAndDownloadUpdateCompletedEventHandler(_app_CheckAndDownloadUpdateCompleted);
                _app.CheckAndDownloadUpdateAsync();
            }
        }


        void _app_CheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ErrorWindow.CreateNew(e.Error);
            }
            else if (e.UpdateAvailable)
            {
                // InformationWindow.Create("Application was successfully updated, please restart it.", "Application updated");
            }
        }


        protected override void ConfigureContainer()
        {
            base.ConfigureContainer();
        }


        protected override IModuleCatalog GetModuleCatalog()
        {
            return ModuleCatalog.CreateFromXaml(
                        new Uri("/Project;component/ModuleCatalog.xaml",
                        UriKind.Relative));
        }


        protected override DependencyObject CreateShell()
        {
            ShellViewModel viewModel = this.Container.Resolve<ShellViewModel>();
            ShellViewModel.ModuleCatalog = this.GetModuleCatalog();


            // Use the container to create an instance of the shell.
            ShellView view = this.Container.Resolve<ShellView>();


            // Set it as the roQot visual for the application.
            Application.Current.RootVisual = view;


            return view;
        }
    }
}


Pay attention for including this reference because if you don't, Visual Studio informs that there is a compilation error but not becuase this reference is missing.

using Microsoft.Practices.Unity;

5.- Add the view ShellView in the view folder. This view will be the template where you must declare the place of the regions. Anyway, you can declare other regions inside of other views. As an example:

* Add this reference in the header of the view:

xmlns:regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"

* Definition of the region:


<ContentControl x:Name="MainRegion"
                      regions:RegionManager.RegionName="MainRegion"/>


6.- Create a new application silverlight as a module and add a class named the same that the module name but ending in Module.


namespace Project.Modules.TeamPage
{
    using Microsoft.Practices.Composite.Modularity;
    using Microsoft.Practices.Composite.Regions;
    using Microsoft.Practices.Unity;
    using SocialSport.Web;


    public class TeamPageModule : IModule
    {
        private readonly IRegionManager regionManager;
        private readonly IUnityContainer unityContainer;
        private const string MODULE_NAME = "TeamPage";


        public TeamPageModule(IRegionManager _regionManager, IUnityContainer _unityContainer)
        {
            regionManager = _regionManager;
            unityContainer = _unityContainer;
        }


        public void Initialize()
        {
            unityContainer.RegisterType<AuthenticationContext>(new InjectionConstructor());
            unityContainer.RegisterType<UserRegistrationContext>(new InjectionConstructor());


            IRegion region = regionManager.Regions["MainRegion"];
            MainPage cmView = this.unityContainer.Resolve<MainPage>();
            region.Add(cmView, cmView.GetType().Name);
            region.Activate(cmView);
        }
    }
}


The most important thing here is the blue mark because thanks to that, you are able to communicate with WCF Ria Services. Then, you will be able to include these context in your viewmodel:


public MainPageViewModel(AuthenticationContext authContext) 
        {
            
        }


Using the RegionManager, you can define the view that will place a region using unity.

7.- Finally, in order to activate a module, you have to include in the viewmodel this method:


protected void ActivateModule(string moduleName)
        {
            moduleManager.LoadModule(moduleName);


            var view = regionManager.Regions["MainRegion"].GetView(moduleName + "ModuleView");
            if (view != null)
            {
                regionManager.Regions["MainRegion"].Activate(view);
            }
        }


Then, this method have receive the name of the module that you declared in the ModuleCatalog.xaml and you want to show. You should call to this method using Commanding, included in MVVM pattern.

I suggest to use the galasoft implementation of this pattern because it already includes commading and a lot of very interesing features. http://www.galasoft.ch/mvvm/getstarted/

This post has been done thanks to http://bachelorthesis.zdechovan.com/wcf-ria-services-mvvm-prism-lob-application-introduction/

No hay comentarios:

Publicar un comentario