How do I use a Unity IoC container with Template10?

I have an app based on Template10 and want to handle my dependency injection using IoC. I am leaning toward using Unity for this. My app is divided into three assemblies:

  • UI (Universal app)
  • UI Logic (Universal Library)
  • Core Logic (Portable Library).
  • I have these questions:

  • Should I use a single container for the whole app, or create one for each assembly?
  • Where should I create the container(s) and register my services?
  • How should different classes in the various assemblies access the container(s)? Singleton pattern?
  • I have read a lot about DI and IoC but I need to know how to apply all the theory in practice, specifically in Template10.

    The code to register:

    // where should I put this code?
    var container = new UnityContainer();
    container.RegisterType<ISettingsService, RoamingSettingsService);
    

    And then the code to retrieve the instances:

    var container = ???
    var settings = container.Resolve<ISettingsService>();
    

    I not familiar with Unity Container .

    My example is using LightInject , you can apply similar concept using Unity . To enable DI on ViewModel you need to override ResolveForPage on App.xaml.cs on your project.

    public class MainPageViewModel : ViewModelBase
    {
        ISettingsService _setting;
        public MainPageViewModel(ISettingsService setting)
        {
           _setting = setting;
        }
     }
    
    
    [Bindable]
    sealed partial class App : Template10.Common.BootStrapper
    {
        internal static ServiceContainer Container;
    
        public App()
        {
            InitializeComponent();
        }
    
        public override async Task OnInitializeAsync(IActivatedEventArgs args)
        {
            if(Container == null)
                Container = new ServiceContainer();
    
            Container.Register<INavigable, MainPageViewModel>(typeof(MainPage).FullName);
            Container.Register<ISettingsService, RoamingSettingsService>();
    
            // other initialization code here
    
            await Task.CompletedTask;
        }
    
        public override INavigable ResolveForPage(Page page, NavigationService navigationService)
        {
            return Container.GetInstance<INavigable>(page.GetType().FullName);
        }
    }
    

    Template10 will automaticaly set DataContext to MainPageViewModel , if you want to use {x:bind} on MainPage.xaml.cs :

    public class MainPage : Page
    {
        MainPageViewModel _viewModel;
    
        public MainPageViewModel ViewModel
        {
          get { return _viewModel??(_viewModel = (MainPageViewModel)this.DataContext); }
        }
    }
    

    here is a small example how i use Unity and Template 10.

    1. Create a ViewModel

    I also created a DataService class to create a list of people. Take a look at the [Dependency] annotation.

    public class UnityViewModel : ViewModelBase
    {
        public string HelloMessage { get; }
    
        [Dependency]
        public IDataService DataService { get; set; }
    
        private IEnumerable<Person> people;
        public IEnumerable<Person> People
        {
            get { return people; }
            set { this.Set(ref people, value); }
        }
    
        public UnityViewModel()
        {
            HelloMessage = "Hello !";
        }
    
        public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode,
            IDictionary<string, object> suspensionState)
        {
            await Task.CompletedTask;
            People = DataService.GetPeople();
        }
    }
    

    2. Create a Class to create and fill your UnityContainer

    Add the UnityViewModel and the DataService to the unityContainer. Create a property to resolve the UnityViewModel.

    public class UnitiyLocator
    {
        private static readonly UnityContainer unityContainer;
    
        static UnitiyLocator()
        {
            unityContainer = new UnityContainer();
            unityContainer.RegisterType<UnityViewModel>();
            unityContainer.RegisterType<IDataService, RuntimeDataService>();
        }
    
        public UnityViewModel UnityViewModel => unityContainer.Resolve<UnityViewModel>();
    }
    

    3. Add the UnityLocator to your app.xaml

    <common:BootStrapper x:Class="Template10UWP.App"
                     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                     xmlns:common="using:Template10.Common"
                     xmlns:mvvmLightIoc="using:Template10UWP.Examples.MvvmLightIoc"
                     xmlns:unity="using:Template10UWP.Examples.Unity">
    
    
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="StylesCustom.xaml" />
                <ResourceDictionary>
                    <unity:UnitiyLocator x:Key="UnityLocator"  />
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
    
            <!--  custom resources go here  -->
    
        </ResourceDictionary>
    </Application.Resources>
    

    4. Create the page

    Use the UnityLocator to set the UnityViewModel as DataContext and bind the properties to the controls

    <Page
    x:Class="Template10UWP.Examples.Unity.UnityMainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Template10UWP.Examples.Unity"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Source={StaticResource UnityLocator}, Path=UnityViewModel}"
    mc:Ignorable="d">
    
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding HelloMessage}" HorizontalAlignment="Center"
                   VerticalAlignment="Center" />
    
        <ListBox Grid.Row="1" ItemsSource="{Binding People}" DisplayMemberPath="FullName">
    
        </ListBox>
    </Grid>
    

    The DataService will be injected automatically when the page resolves the UnityViewModel.

    Now to your questions

  • This depends on how the projects depend on each other. I am not sure what´s the best solution, but i think i would try to use one UnityContainer and place it in the core library.

  • I hope my examples answered this question

  • I hope my examples answered this question

  • 链接地址: http://www.djcxy.com/p/34242.html

    上一篇: 如何在clang中为codecompletion创建一个虚拟文件

    下一篇: 如何在Template10中使用Unity IoC容器?