c# - mvc - ninject
¿Cómo uso un contenedor Unity IoC con Template10? (2)
Tengo una aplicación basada en Template10 y quiero manejar mi inyección de dependencia usando IoC. Me inclino por utilizar Unity para esto. Mi aplicación está dividida en tres ensamblajes:
- UI (aplicación universal)
- UI Logic (Biblioteca universal)
- Core Logic (Biblioteca portátil).
Tengo estas preguntas:
- ¿Debo usar un solo contenedor para toda la aplicación o crear uno para cada ensamblaje?
- ¿Dónde debería crear los contenedores y registrar mis servicios?
- ¿Cómo deben acceder las diferentes clases en los diferentes ensambles al contenedor (es)? Patrón Singleton?
He leído mucho sobre DI y IoC, pero necesito saber cómo aplicar toda la teoría en la práctica, específicamente en Template10.
El código para registrarse:
// where should I put this code?
var container = new UnityContainer();
container.RegisterType<ISettingsService, RoamingSettingsService);
Y luego el código para recuperar las instancias:
var container = ???
var settings = container.Resolve<ISettingsService>();
No estoy familiarizado con Unity Container
.
Mi ejemplo es usar LightInject
, puede aplicar un concepto similar usando Unity
. Para habilitar DI en ViewModel
, debe anular ResolveForPage
en App.xaml.cs
en su proyecto.
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
configurará automáticamente DataContext
en MainPageViewModel
, si desea usar {x:bind}
en MainPage.xaml.cs
:
public class MainPage : Page
{
MainPageViewModel _viewModel;
public MainPageViewModel ViewModel
{
get { return _viewModel??(_viewModel = (MainPageViewModel)this.DataContext); }
}
}
Aquí hay un pequeño ejemplo de cómo uso la Unidad y la Plantilla 10.
1. Crea un ViewModel
También creé una clase DataService para crear una lista de personas. Eche un vistazo a la anotación [Dependencia].
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. Crea una clase para crear y llenar tu UnityContainer
Agregue UnityViewModel y DataService a unityContainer. Crea una propiedad para resolver el 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. Agregue el UnityLocator a su 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="Styles/Custom.xaml" />
<ResourceDictionary>
<unity:UnitiyLocator x:Key="UnityLocator" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
<!-- custom resources go here -->
</ResourceDictionary>
</Application.Resources>
4. Crea la página
Utilice UnityLocator para establecer UnityViewModel como DataContext y vincular las propiedades a los controles
<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>
El DataService se inyectará automáticamente cuando la página resuelva UnityViewModel.
Ahora a tus preguntas
Esto depende de cómo los proyectos dependen el uno del otro. No estoy seguro de cuál es la mejor solución, pero creo que trataría de usar un UnityContainer y colocarlo en la biblioteca central.
Espero que mis ejemplos respondan esta pregunta
Espero que mis ejemplos respondan esta pregunta