📜 ⬆️ ⬇️

Silverlight Migration Applications from Prism 2.2 to Prism 4 MEF edition

The time is right when the development of the Prism 4 library for creating modular and flexible Silverlight and WPF applications will be announced. The new version has a large number of changes, improvements and innovations. One of the main innovations is the addition of support for MEF as a container (in the previous version only Unity container was supported).

In this article, I would like to touch upon the issue of migration from Prism 2.2 to Prism 4, taking into account the transition to using the MEF container instead of Unity.

Changes in the naming and composition of assemblies


The development team decided to change the assembly names and namespace names:

Modify build list


When migrating, you should make the following changes to the build list of each project:

Replacing the assembly, you should change the namespace. This can be done using the standard Find and Replace dialog (Ctrl-H), by entering Microsoft.Practices.Composition and Microsoft.Practices.Prism in the appropriate fields. Given that the Microsoft.Practices.Composite.Presentation.dll assembly no longer exists separately, after the previous replacement, you should replace Microsoft.Practices.Prism.Presentation with Microsoft.Practices.Prism

Note:
Do not forget to change the namespace names not only in .cs files, but also in .xaml, and in .config (if required).
')

Unity container replacement


MEF container has certain advantages and disadvantages. They should be aware of before making a decision to migrate to a MEF container.

Disadvantages:

Benefits:


Getting rid of the Unity container should start by removing all the IUnityContainer occurrences as a class constructor or public property. If other parameters are passed to the constructor from the container (constructor injection), then we leave them, and we mark the constructor with the [ImportingConstructor] attribute.

Example:
//Prism 2.2 <br> public class SampleClass<br>{<br> private readonly IRegionManager regionManager;<br> private readonly IUnityContainer container;<br><br> public SampleClass(IUnityContainer container, IRegionManager regionManager)<br> {<br> this .container = container;<br> this .regionManager = regionManager;<br> }<br>}<br><br> //Prism 4 <br>[Export( typeof (SampleClass))]<br> public class SampleClass<br>{<br> private readonly IRegionManager regionManager;<br><br> [ImportingConstructor]<br> public SampleClass(IRegionManager regionManager)<br> {<br> this .regionManager = regionManager;<br> }<br>}<br> <br> * This source code was highlighted with Source Code Highlighter .


Further, all classes that were somehow created through the container should be marked with the [Export] attribute (you can use [InheritedExport] for interfaces), and the class registration code in the container should be removed at the same time.

The next step is to change the syntax of the modules. Each module must be marked with the [ModuleExport(typeof(<ModuleType>))] attribute (the definition of this attribute is in the Microsoft.Practices.Prism.MefExtensions.dll assembly).

Example:
//Prism 2.2 <br> public class SampleModule : IModule<br>{<br> public void Initialize()<br> {<br> Register();<br> }<br><br> public void Register()<br> {<br> container.RegisterType<ISampleViewModel, SampleViewModel>();<br> }<br>}<br><br> //Prism 4 <br>[ModuleExport( typeof (SampleClass))]<br> public class SampleModule : IModule<br>{<br> public void Initialize()<br> {<br> ...<br> }<br>}<br><br>[InheritedExport]<br> public interface ISampleViewModel<br>{<br> ...<br>} <br><br> * This source code was highlighted with Source Code Highlighter .

The next step involves changing the Bootstarpper.cs.

Example:
//Prism 4 <br> using System.ComponentModel.Composition;<br> using System.ComponentModel.Composition.Hosting;<br><br> using Microsoft.Practices.Prism.MefExtensions;<br> using Microsoft.Practices.Prism.Regions;<br> using Modularity = Microsoft.Practices.Prism.Modularity;<br><br> namespace Sample.Shell<br>{<br> public class Bootstrapper : MefBootstrapper<br> {<br> protected override DependencyObject CreateShell()<br> {<br> return Container.GetExportedValue<ShellView>();<br> }<br><br> protected override void InitializeShell()<br> {<br> base .InitializeShell();<br> Application.Current.RootVisual = (ShellView) this .Shell;<br> }<br><br> protected override Modularity.IModuleCatalog CreateModuleCatalog()<br> {<br> return Modularity.ModuleCatalog.CreateFromXaml( new Uri ( "/Sample.Shell;component/ModulesCatalog.xaml" , UriKind.Relative));<br> }<br><br> protected override void ConfigureAggregateCatalog()<br> {<br> base .ConfigureAggregateCatalog();<br> AggregateCatalog.Catalogs.Add( new AssemblyCatalog( this .GetType(). Assembly ));<br> }<br> }<br>}<br> <br> * This source code was highlighted with Source Code Highlighter .

A few more features of the transition to the MEF container.

Example 1:
//Prism 2.2 <br> private void RegisterTypes()<br>{<br> SampleType sampleType = new SampleType(...);<br> Container.RegisterInstance<ISampleType>(sampleType);<br><br> Container.RegisterType<ISingletonSampleType, SingletonSampleType>( new ContainerControlledLifetimeManager());<br>}<br><br> //Prism 4 <br>[Export]<br>[PartCreationPolicy(CreationPolicy.Shared)]<br> public class SampleType : ISampleType<br>{<br>...<br>}<br><br>[Export]<br>[PartCreationPolicy(CreationPolicy.Shared)]<br> public class SingletonSampleType : ISingletonSampleType<br>{<br>...<br>}<br> <br> * This source code was highlighted with Source Code Highlighter .

Example 2:
//Prism 2.2 <br> private void Foo()<br>{<br> List <ISampleType> samples = new List <ISampleType>();<br> for ( int i = 0; i == 10; i++)<br> {<br> ISampleType sampleTypeInstance = Container.ResolveInstance<ISampleType>();<br> samples.Add(sampleTypeInstance);<br> }<br>}<br><br> //Prism 4 <br>[Import]<br> public ExportFactory<ISampleType> SampleTypeFactory<br>{<br> get ;<br> set ;<br>}<br><br> private void Foo()<br>{<br> List <ISampleType> samples = new List <ISampleType>();<br> for ( int i = 0; i == 10; i++)<br> {<br> ISampleType sampleTypeInstance = SampleTypeFactory.CreatExport().Value;<br> samples.Add(sampleTypeInstance);<br> }<br>}<br> <br> * This source code was highlighted with Source Code Highlighter .

Changes in ViewModel


All ViewModel (or their common ancestor) should be inherited from the NotificationObject class. This class implements the INotifyPropertyChanged interface and implements another version of the RaisePropertyChanged() method, which accepts not the property's string name, but the property itself. It is highly desirable to abandon the old implementation of RaisePropertyChanged() and start using the new one.

Example:
//Prism 2.2 <br> public class SampleViewModel : ISampleViewModel<br>{<br> private SamplePropertyType sampleProperty;<br> public SamplePropertyType SampleProperty<br> {<br> get <br> {<br> return sampleProperty;<br> }<br> set <br> {<br> sampleProperty = value ;<br> this .RaisePropertyChanged( "SampleProperty" );<br> }<br> }<br>}<br><br> //Prism 4 <br> public class SampleViewModel : NotificationObject, ISampleViewModel<br>{<br> private SamplePropertyType sampleProperty;<br> public SamplePropertyType SampleProperty<br> {<br> get <br> {<br> return sampleProperty;<br> }<br> set <br> {<br> sampleProperty = value ;<br> this .RaisePropertyChanged(() => SampleProperty);<br> }<br> }<br>}<br> <br> * This source code was highlighted with Source Code Highlighter .

Migration Pitfalls


Duplicate builds

It should be noted that if Prism assemblies fall into several XAP files, an exception will be generated when composing the composition.

Message: Unabled Error in Silverlight Application Code: 4004 Category: ManagedRuntimeError Message: Microsoft.Practices.Prism.Modularity.ModuleTypeLoadingException: Failed to load type for module <ModuleType>. Error was the composition remains unchanged. 13 root causes. The root causes are provided below. Review the CompositionException.Errors property for more detailed information.

1) Microsoft. Prism.MefExtensions.Modularity.MefModuleManager '.
...

In order to avoid this situation, you should set the CopyLocal=False property to all duplicate assemblies or use the plugin for VisualStudio2010 .

Module Catalog Features

When using the module directory, the full qualified name of the assembly referenced should be indicated.

Example:
<!--ModulesCatalog.xaml, Prism 2.2--> <br> < Modularity:ModuleCatalog xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" <br> xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml" <br> xmlns:Modularity ="clr-namespace:Microsoft.Practices.Composite.Modularity; assembly=Microsoft.Practices.Composite" > <br> < Modularity:ModuleInfo <br> Ref ="SampleModule.xap" <br> ModuleName ="SampleModule" <br> ModuleType ="SampleModule.SampleModule, SampleModule, Version=1.0.0.0" /> <br> </ Modularity:ModuleCatalog > <br><br> <!--ModulesCatalog.xaml, Prism 4--> <br> < Modularity:ModuleCatalog xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" <br> xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml" <br> xmlns:Modularity ="clr-namespace:Microsoft.Practices.Prism.Modularity; assembly=Microsoft.Practices.Prism" > <br> < Modularity:ModuleInfo <br> Ref ="SampleModule.xap" <br> ModuleName ="SampleModule" <br> ModuleType ="SampleModule.SampleModule, SampleModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null " /> <br> </ Modularity:ModuleCatalog > <br> <br> * This source code was highlighted with Source Code Highlighter .

Conclusion


With the release of the library release, each developer will make his own decision about the possibility of switching to a new version and changing the container from Unity to MEF. My experience shows that the migration does not take much time, is feasible and will allow you to take advantage of the MEF container.

I wish everyone success in this matter and I believe that my article will be a good help.

Source: https://habr.com/ru/post/106726/


All Articles