Our company is using Ninject for DI. I have to create a WPF App with MVVM and want to use Catel.
Because our services which have the DB DataContext are injected with Ninject, I don't know where to start.
I've started with a prepared skeleton project.
This is what App.xaml.cs contains:
public partial class App : Application
{
public IKernel Container;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
ConfigureContainer();
ComposeObjects();
Current.MainWindow.Show();
}
private void ConfigureContainer()
{
var modules = new INinjectModule[]
{
new ServiceModule()
};
Container = new StandardKernel(modules);
}
private void ComposeObjects()
{
Current.MainWindow = Container.Get<MainWindow>();
Current.MainWindow.Title = "DI with Ninject";
}
}
The ServiceModule is inherited from NinjectModule.
With that code I can use this constructor of my MainWindow:
public MainWindow(IAuthenticationService authenticationService)
{
InitializeComponent();
ViewModel = new MainWindowViewModel(authenticationService);
DataContext = ViewModel;
}
The IAuthenticationService is injected via App.xaml.cs and Ninject. In my opinion this solution is hard to maintain, because if I need a new service, I have to add it to the constructor of my MainWindow.
Now I need the same thing to work with Catel, but I haven't found something in the documentation.
EDIT:
I've found on the documentation that I can register an external IoC container.
How do I create my own component (doc: Replacing the default components) which works with the Ninject's standard kernel?
Also is this a good approach of DI or are there better solutions?
Please see the recommended approach on how to replace the default IoC components:
https://catelproject.atlassian.net/wiki/display/CTL/Replacing+the+default+components
To create your own component, let the Ninject kernel implement the right interface (for example, IDependencyResolver or IServiceLocator) and all should be set.
Related
i'm trying to develop from scratch a WPF app with the use of Simpleinjector as a IOC container.
I'm new on this topic and i have some issue regards lifetime of object and hot use them correctly.
I started the app by following the WPF integration guide on simpleinjector manual.
But i don't understand how to receive a new instance every time a service needed it
As i ask in my previous post i need to receive a new unitOfWork every time a service need it.
as #Steven say on my previous post
Do note that transient means "allways a new instance is resolved when it is requested from the container." If you're not requesting it again, you will be operating on the same instance, which might explain the ObjectDisposedException.
In the other post i found a solutin but i think it's a little bit over-complicated and it's to create a factory and inject this instead of the instance because i want to call the container.getInstance only on the startup method and not on the service by passing the container as a dependency
It's the only way i have to achieve this or there is something that i don't understand on how to develop in DI way?
Example of code:
public class HeaderViewModelFactory : IWpfRadDispenserViewModelFactory<HeaderviewModel>
{
private readonly ProductionService _service;
public HeaderViewModelFactory(ProductionService service)
{
_service = service;
}
public HeaderviewModel CreateViewModel()
{
return new HeaderviewModel(_service);
}
}
public class HeaderviewModel : ViewModelBase
{
private readonly ProductionService _service;
public HeaderviewModel(ProductionService service)
{
_service = service;
CreateData();
}
private void CreateData()
{
_service.CreateTestCycle();
}
}
public class CycleService : GenericDataService<Cycle>
{
private readonly IUnitOfWork<WpfRadDispenserDbContext> _uowContext;
public CycleService(IUnitOfWork<WpfRadDispenserDbContext> uowContext)
: base(uowContext)
{
_uowContext = uowContext;
}
public void CreateTestCycle()
{
var cycleDataService = new GenericDataService<Cycle>(_uowContext);
var vialDataService = new GenericDataService<Vial>(_uowContext);
Cycle c = new Cycle();
c.BatchName = "test";
Vial v = new Vial();
v.Name = "Test Vial";
c.Vials.Add(v);
_uowContext.CreateTransaction(IsolationLevel.ReadCommitted);
try
{
vialDataService.Create(v);
_uowContext.Persist();
var list = vialDataService.GetAll();
cycleDataService.Create(c);
_uowContext.Persist();
_uowContext.Commit();
}
catch (Exception e)
{
Console.WriteLine(e);
_uowContext.RollBack();
throw;
}
finally
{
_uowContext.Dispose();
}
}
}
private static Container Bootstrap()
{
// Create the container as usual.
var container = new Container();
// Register your types:
// Register your windows and view models:
container.Register<WpfRadDispenserDbContextFactory>(Lifestyle.Transient);
container.Register<IUnitOfWork<WpfRadDispenserDbContext>,WpfRadDispenserUOW>();
container.Register(typeof(CycleService));
container.Register<IWpfRadDispenserViewModelFactory<ProductionViewModel>,
ProductionViewModelFactory>(Lifestyle.Transient);
container.Register<IWpfRadDispenserViewModelFactory<AnagraphicViewModel>,
AnagraphicsViewModelFactory>(Lifestyle.Transient);
container.Register<IWpfRadDispenserViewModelFactory<HeaderviewModel>,
HeaderViewModelFactory>(Lifestyle.Transient);
container.Register<IViewModelAbstractFactory,
ViewModelAbstractFactory>(Lifestyle.Transient);
container.Register<INavigator, Navigator>(Lifestyle.Transient);
container.Register<MainWindowViewModel>();
container.Register<MainWindow>();
//container.Options.EnableAutoVerification = false;
//container.Verify();
return container;
}
in this way every time i create a new viewmodel i receive the same service and ovviously the dbcontext it's not present anymore because disposed.
This is not the rela code but only an example that i made to understand how DI works.
Using Abstract Factory pattern is the most common and recommended approach. Using the container in your application directly is widely considered an anti-pattern, like the Service Locator (Service Locator is an Anti-Pattern) for a very good reason.
Abstract factory allows instantiation of objects without introducing a tight coupling to the actual implementation that knows how to create specific instances.
Most IoC frameworks support this pattern natively. Most of the time they provide the generic interface for the factory. You register the instance (the product) with the container and the framework will export a ready-to use factory for you. You add the dependency to this framework interface to your object e.g. constructor. Then you register the generic factory interface. The framework will automatically create the instance of the factory and inject it into the relevant instances e.g., via constructor.
I am not too familiar with Simple Injector, but the framework really keeps things simple. There is no such code generation.
But the pattern is very simple (that's why this is so easy to automate) and in no way complicated.
Example
The interface required to dynamically create the instances of type TInstance:
interface IFactory<TInstance>
{
TInstance Create();
}
The implementation of this factory:
class SaveItemFactory : IFactory<ISaveItem>
{
ISaveItem Create() => new SaveItem();
}
The type that needs to create a dependency dynamically:
interface IItemManager {}
class ItemManager : IItemManager
{
IFactory<ISaveItem> SaveItemFactory { get; }
public ItemManager(IFactory<ISaveItem> itemFactory) => this.SaveItemFactory = itemFactory;
public void SaveData(object data)
{
ISaveItem saveItem = this.SaveItemFactory.Create();
saveItem.SetData(data);
}
}
Configure the container:
public void Run()
{
var container = new SimpleInjector.Container();
container.Register<IFactory<ISaveItem>, SaveItemFactory>(Lifestyle.Singleton);
container.Register<IItemManager, ItemManager>(Lifestyle.Singleton);
IItemManager itemManager = container.GetInstance<IItemManager>();
itemManager.SaveData("Some Data");
}
I was looking into "Dependency Injection" on xamarin forms and found some concepts that use something like ContainerBuilder. The solutions found online such as this, talk about how you can have DI setup and inject them into your view models. However, personally, I didn't find this or the whole concept of view models and binding very tidy for several reasons. I would rather create services that can be reused by the business logic, which seems to make the code a lot cleaner. I felt that implementing an IServiceProvider would result in a much cleaner implementation. I was planning on implementing a service provider something like this:
IServiceProvider Provider = new ServiceCollection()
.AddSingleton<OtherClass>()
.AddSingleton<MyClass>()
.BuildServiceProvider();
Firstly, I am not sure why there are no xamarin examples of these. So, I am not sure if there is anything wrong with going towards this direction. I have looked into ServiceCollection class. The package it is from, Microsoft.Extensions.DependencyInjection, doesn't have "aspnetcore" in its name. It, however, has its owner as "aspnet". I am not entirely sure if ServiceCollection is only meant for web applications or it would make sense to use it for mobile apps.
Is it safe to use IServiceProvider with ServiceCollection as long as I use all singletons? is there any concern (in terms of performance or ram) I am missing?
Update
After the comments from Nkosi, I have taken another look at the link and noticed a couple of things:
The documentation link is dated around the same time Microsoft.Extensions.DependencyInjection was still in beta
All points in the list under "several advantages to using a dependency injection container" in the documentation also apply to DependencyInjection as far as I can see.
Autofac process seems to revolve around ViewModels which I am trying to avoid using.
Update 2
I managed to get DI directly into the behind code of pages with the help of a navigation function something like this:
public static async Task<TPage> NavigateAsync<TPage>()
where TPage : Page
{
var scope = Provider.CreateScope();
var scopeProvider = scope.ServiceProvider;
var page = scopeProvider.GetService<TPage>();
if (navigation != null) await navigation.PushAsync(page);
return page;
}
This implementation uses Splat and some helper/wrapper classes to conveniently access the container.
The way how the services are registered is a bit verbose but it could cover all uses cases I have encountered so far; and the life cycle can be changed quite easily as well, e.g. switching to a lazy creation of a service.
Simply use the ServiceProvider class to retrieve any instances from the IoC container anywhere in your code.
Registering of your Services
public partial class App : Application
{
public App()
{
InitializeComponent();
SetupBootstrapper(Locator.CurrentMutable);
MainPage = new MainPage();
}
private void SetupBootstrapper(IMutableDependencyResolver resolver)
{
resolver.RegisterConstant(new Service(), typeof(IService));
resolver.RegisterLazySingleton(() => new LazyService(), typeof(ILazyService));
resolver.RegisterLazySingleton(() => new LazyServiceWithDI(
ServiceProvider.Get<IService>()), typeof(ILazyServiceWithDI));
// and so on ....
}
Usage of ServiceProvider
// get a new service instance with every call
var brandNewService = ServiceProvider.Get<IService>();
// get a deferred created singleton
var sameOldService = ServiceProvider.Get<ILazyService>();
// get a service which uses DI in its contructor
var another service = ServiceProvider.Get<ILazyServiceWithDI>();
Implementation of ServiceProvider
public static class ServiceProvider
{
public static T Get<T>(string contract = null)
{
T service = Locator.Current.GetService<T>(contract);
if (service == null) throw new Exception($"IoC returned null for type '{typeof(T).Name}'.");
return service;
}
public static IEnumerable<T> GetAll<T>(string contract = null)
{
bool IsEmpty(IEnumerable<T> collection)
{
return collection is null || !collection.Any();
}
IEnumerable<T> services = Locator.Current.GetServices<T>(contract).ToList();
if (IsEmpty(services)) throw new Exception($"IoC returned null or empty collection for type '{typeof(T).Name}'.");
return services;
}
}
Here is my csproj file. Nothing special, the only nuget package I added was Spat
Shared Project csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>portable</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Splat" Version="9.3.11" />
<PackageReference Include="Xamarin.Forms" Version="4.3.0.908675" />
<PackageReference Include="Xamarin.Essentials" Version="1.3.1" />
</ItemGroup>
</Project>
I know the question has been asked 2 years ago, but I might have a solution that could match what you are asking for.
In the past few months I've been working on apps using Xamarin and WPF and I used the Microsoft.Extensions.DependencyInjection package to add constructor dependency injection to my view models, just like an ASP.NET Controller. Which means that I could have something like:
public class MainViewModel : ViewModelBase
{
private readonly INavigationService _navigationService;
private readonly ILocalDatabase _database;
public MainViewModel(INavigationService navigationService, ILocalDatabase database)
{
_navigationService = navigationService;
_database = database;
}
}
To implement this kind of process I use the IServiceCollection to add the services and the IServiceProvider to retrieve the registered services.
What is important to remember, is that the IServiceCollection is the container where you will register your dependencies. Then when building this container, you will obtain a IServiceProvider that will allow you to retrieve a service.
To do so, I usually create a Bootstrapper class that will configure the services and initialize the main page of the application.
The basic implementation
This example show how to inject dependencies into a Xamarin page. The process remains the same for any other class. (ViewModels or other classes)
Create a simple class named Bootstrapper in your project and intitialize a IServiceCollection and IServiceProvider private fields.
public class Bootstrapper
{
private readonly Application _app;
private IServiceCollection _services;
private IServiceProvider _serviceProvider;
public Bootstrapper(Application app)
{
_app = app;
}
public void Start()
{
ConfigureServices();
}
private void ConfigureServices()
{
_services = new ServiceCollection();
// TODO: add services here
_serviceProvider = _services.BuildServiceProvider();
}
}
Here in the ConfigureServices() method we just create a new ServiceCollection where we are going to add our services. (See https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollection?view=dotnet-plat-ext-3.1)
Once our services have been added, we build the service provider that will allow us to retrieve the previously registered services.
Then in your App class constructor, create a new Bootstrapper instance and call the start method to initialize the application.
public partial class App : Application
{
public App()
{
InitializeComponent();
var bootstrapper = new Bootstrapper(this);
bootstrapper.Start();
}
...
}
With this piece of code, you have setup your service container, but we still need to initialize the MainPage of the application. Go back to the bootstrapper's Start() method and create a new instance of the wanted main page.
public class Bootstrapper
{
...
public void Start()
{
ConfigureServices();
// Real magic happens here
var mainPageInstance = ActivatorUtilities.CreateInstance<MainPage>(_serviceProvider);
_app.MainPage = new NavigationPage(mainPageInstance);
}
}
Here we use the ActivatorUtilities.CreateInstance<TInstance>() method to create a new MainPage instance. We give the _serviceProvider as parameter, because the ActivatorUtilities.CreateInstance() method will take care of creating your instance and inject the required services into your object.
Note that this is what ASP.NET Core using to instanciate the controllers with contructor dependency injection.
To test this, create a simple service and try to inject it into your MainPage contructor:
public interface IMySimpleService
{
void WriteMessage(string message);
}
public class MySimpleService : IMySimpleService
{
public void WriteMessage(string message)
{
Debug.WriteLine(message);
}
}
Then register it inside the ConfigureServices() method of the Bootstrapper class:
private void ConfigureServices()
{
_services = new ServiceCollection();
_services.AddSingleton<IMySimpleService, MySimpleService>();
_serviceProvider = _services.BuildServiceProvider();
}
And finally, go to your MainPage.xaml.cs, inject the IMySimpleService and call the WriteMessage() method.
public partial class MainPage : ContentPage
{
public MainPage(IMySimpleService mySimpleService)
{
mySimpleService.WriteMessage("Hello world!");
}
}
There you go, you have successfully registered a service and injected it into your page.
The real magic with constructor injection really occurs using the ActivatorUtilities.CreateInstance<T>() method by passing a service provider. The method will actually check the parameters of your constructor and try to resolve the dependencies by trying to get them from the IServiceProvider you gave him.
Bonus : Register platform specific services
Well this is great right? You are able to inject services into any classes thanks to the ActivatorUtilities.CreateInstance<T>() method, but sometimes you will also need to register some platform specific services (Android or iOS).
With the previous method is not possible to register platform-specific services, because the IServiceCollection is initialized in the Bootstrapper class. No worries, the workaround is really simple.
You just need to extract the IServiceCollection initialization to the platform-specific code. Simply initialize the service collection on the MainActivity.cs of your Android project and in the AppDelegate of your iOS project and pass it to your App class that will forward it to the Bootstrapper:
MainActivity.cs (Android)
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
...
var serviceCollection = new ServiceCollection();
// TODO: add platform specific services here.
var application = new App(serviceCollection);
LoadApplication(application);
}
...
}
AppDelegate.cs (iOS)
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
var serviceCollection = new ServiceCollection();
// TODO: add platform specific services here.
var application = new App(serviceCollection);
LoadApplication(application);
return base.FinishedLaunching(app, options);
}
}
App.xaml.cs (Common)
public partial class App : Application
{
public App(IServiceCollection services)
{
InitializeComponent();
var bootstrapper = new Bootstrapper(this, services);
bootstrapper.Start();
}
...
}
Bootstrapper.cs (Common)
public class Bootstrapper
{
private readonly Application _app;
private readonly IServiceCollection _services;
private IServiceProvider _serviceProvider;
public Bootstrapper(Application app, IServiceCollection services)
{
_app = app;
_services = services;
}
public void Start()
{
ConfigureServices();
var mainPageInstance = ActivatorUtilities.CreateInstance<MainPage>(_serviceProvider);
_app.MainPage = new NavigationPage(mainPageInstance);
}
private void ConfigureServices()
{
// TODO: add services here.
_serviceCollection.AddSingleton<IMySimpleService, MySimpleService>();
_serviceProvider = _services.BuildServiceProvider();
}
}
And that's all, you are now able to register platform-specific services and inject the interface into your pages / view models / classes easily.
In a C# WindowForms application I start an OWIN WebApp that creates a singleton instance of my other class Erp:
public partial class Engine : Form
{
const string url = "http://*:8080"; //49396
private IDisposable webApp;
public Engine()
{
InitializeComponent();
StartServer();
}
private void StartServer()
{
webApp = WebApp.Start<Startup>(url);
Debug.WriteLine("Server started at " + url);
}
private void btnDoSomething(object sender, System.EventArgs e)
{
// needs to call a method in erp
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
Trace.Listeners.Remove("HostingTraceListener");
app.UseCors(CorsOptions.AllowAll);
var builder = new ContainerBuilder();
var config = new HubConfiguration();
builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();
var erp = new Erp();
builder.RegisterInstance<Erp>(erp).SingleInstance();
var container = builder.Build();
config.Resolver = new AutofacDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.MapSignalR(config);
}
}
After the creation of the WebApp I want to retrieve in other part of my code (i.e. in the button's event handler above) the singleton erp instance created.
As far as I understand I need to use the resolve function:
var erp = container.Resolve<Erp>();
but it's not clear to me how to retrieve the container outside the Configuration function.
I wouldn't overthink it. Set a static variable somewhere and just hold onto it.
public static class ContainerProvider
{
public static IContainer Container { get; set; }
}
and in the block in Startup:
var container = builder.Build();
ContainerProvider.Container = container;
config.Resolver = new AutofacDependencyResolver(container);
Now you can get the container wherever you need it.
EDIT: I have just realised the accepted answer is by a co-owner of the Autofac project, which has left me confused as it seems to go against what is in the documentation. I am going to leave the answer for now in hope of clarification.
Just wanted to provide my own answer is because whilst the accepted answer will work; it is generally considered bad practice.
From the Best Practices and Recommendations section in Autofac's documentation:
Use Relationship Types, Not Service Locators
Giving components access to the container, storing it in a public static property, or making functions like Resolve() available on a global “IoC” class defeats the purpose of using dependency injection. Such designs have more in common with the Service Locator pattern.
If components have a dependency on the container (or on a lifetime scope), look at how they’re using the container to retrieve services, and add those services to the component’s (dependency injected) constructor arguments instead.
Use relationship types for components that need to instantiate other components or interact with the container in more advanced ways.
You haven't given a specific scenario of how you want to use it in your code, so I can't provide you with an exact solution, but is there any reason you need to resolve the instance yourself? Could you not just deliver the Erp instance via dependency injection?
If the answer is yes, the following code I adapted from the Windows Forms Integration Guide page in Autofac's documentation demonstrates how this would be done:
public partial class Form1 : Form {
private readonly Erp _erp;
public Form1(Erp erp) {
this._erp = erp;
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
//do stuff with erp here
}
}
Then Autofac, assuming the registration has been setup correctly, should inject the instance into that class.
I hope this helps!
I can't seem to find an solution to this problem. I've seen several questions about this, but none really give me a solution. I am totally new to Autofac and haven't really done much WPF + MVVM, but know the basics.
I have a WPF application (using ModernUI for WPF) which I'm trying to add Autofac to, and I am having a hard time figuring out how to resolve my services within all the views, since they have no access to my container. I have a main view, which is my entry point, where I set up my container:
public partial class MainWindow : ModernWindow
{
IContainer AppContainer;
public MainWindow()
{
SetUpContainer();
this.DataContext = new MainWindowViewModel();
InitializeComponent();
Application.Current.MainWindow = this;
}
private void SetUpContainer()
{
var builder = new ContainerBuilder();
BuildupContainer(builder);
var container = builder.Build();
AppContainer = container;
}
private void BuildupContainer(ContainerBuilder builder)
{
builder.RegisterType<Logger>().As<ILogger>();
...
}
}
The problem I'm having is figuring out how I can resolve my logger and other services within my other views, where I inject all my dependencies through the ViewModel constructor, like so:
public partial class ItemsView : UserControl
{
private ItemsViewModel _vm;
public ItemsView()
{
InitializeComponent();
IFileHashHelper fileHashHelper = new MD5FileHashHelper();
ILibraryLoader libraryLoader = new LibraryLoader(fileHashHelper);
ILogger logger = new Logger();
_vm = new ItemsViewModel(libraryLoader, logger);
this.DataContext = _vm;
}
}
Some views have a ridiculous amount of injected parameters, and this is where I want Autofac to come in and help me clean things up.
I was thinking of passing the container to the ViewModel and storing it as a property on my ViewModelBase class, but I've read that this would be an anti-pattern, and even then I don't know if that would automatically resolve my objects within the other ViewModels.
I managed to put together a simple Console Application using Autofac
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Cleaner>().As<ICleaner>();
builder.RegisterType<Repository>().AsImplementedInterfaces().InstancePerLifetimeScope();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
ICleaner cleaner = container.Resolve<ICleaner>();
cleaner.Update(stream);
}
}
}
but that was simple since it has a single entry point.
I'd like some ideas on how to add Autofac to my WPF app. I'm sure that I'm doing something wrong. Your help is appreciated.
Expanding on my comment above:
I use Autofac with all my WPF MVVM applications, I believe it to be one of the better DI frameworks - this is my opinion, but I think it is valid.
Also for me PRISM should be avoided 99% of the time, it's a 'solution looking for a problem' and since most people don't build dynamically composable runtime solutions in WPF it is not needed, i'm sure people would\will disagree.
Like any architectural patterns there is a setup\configuration phase to the application life-cycle, put simply in your case before the first View (window) is shown there will be a whole of setup done for Dependency Injection, Logging, Exception Handling, Dispatcher thread management, Themes etc.
I have several examples of using Autofac with WPF\MVVM, a couple are listed below, I would say look at the Simple.Wpf.Exceptions example:
https://github.com/oriches/Simple.Wpf.Exceptions
https://github.com/oriches/Simple.Wpf.DataGrid
https://github.com/oriches/Simple.MahApps.Template
You can use a similar technique as your console application:
class Program
{
[STAThread]
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Cleaner>().As<ICleaner>();
builder.RegisterType<Repository>().AsImplementedInterfaces().InstancePerLifetimeScope();
// Add the MainWindowclass and later resolve
build.RegisterType<MainWindow>().AsSelf();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var main = scope.Resolve<MainWindow>();
main.ShowDialog();
}
}
}
Be sure to mark Main with [STAThread]. Then in the project's properties, under the Application tab, set the Startup object to the Program class.
However, I am not certain of the implications of not running App.Run() and of running MainWindow.ShowDialog() instead.
To do the same using App.Run(), do the following:
1) delete StartupUri="MainWindow.xaml" from App.xaml
2) Add the following to App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
var builder = new ContainerBuilder();
builder.RegisterType<Cleaner>().As<ICleaner>();
builder.RegisterType<Repository>().AsImplementedInterfaces().InstancePerLifetimeScope();
// Add the MainWindowclass and later resolve
build.RegisterType<MainWindow>().AsSelf();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var window = scope.Resolve<MainWindow>();
window.Show();
}
}
WPF doesn't have a natural composition root or easy DI integration. Prism is a pretty common set of libraries specifically intended to bridge that for you.
(That's not Autofac specific - it's general guidance for adding DI to WPF apps.)
I have configured Unity in my ASP.NET application and the configuration is loaded when the first request is received in Application_BeginRequest. then the Unity container is stored in the Global.ascx as a property so that my other class can access it:
public static IUnityContainer ContainerHolder { get; set; }
IUnityContainer IContainerAccessor.Container
{
get { return ContainerHolder; }
}
ContainerHolder, holds the container instance across application and Container property allows access to this property in each session.
Then I have a UnityLocator class which enables me access this property across the application:
public static class UnityLocator
{
private static IUnityContainer Container
{
get
{
return ((IContainerAccessor)HttpContext.Current.ApplicationInstance).Container;
}
}
}
Everything works fine!
I have also a method to access the instance from Unity:
UnityLocator.GetInstance<IThemeManager>();
protected Repository(ICustomCacheManager customCacheManager)
{
this.Cache = customCacheManager;
}
protected Repository()
: this(UnityLocator.GetInstance<ICustomCacheManager>())
{
}
this has been used in my app so that I can retrieve an existing instance from Unity so that I can inject it to other classes. For example my view (asp.net page) injects this to its Presenter class as a dependency.
Now, I'd like to configure my Unit tests to run.
How could I do that?! global.ascx doesn't exist there obviously so I thought I should create a BaseTest class and let all my tests inherit it. then at the constructor of this BaseTest class, I build up my instances. Is it the right way to do it?
How to configure unit tests with Unity now?
Thanks
UPDATE:
UnityLocator.GetInstance added.
You shouldn't worry about accessing your IoC container. That is a violation of Unit Tests.
Unit tests you should not worry about any concrete implementation or dependency (other than the class under test).
To me, having your IoC globally available is a bad design choice. You should have your dependencies injected via properties or constructors.
Probably using the global application class for storing the service locator was not a good idea. Why don't you use the built-in ServiceLocator class? It is available from anywhere in the code and doesn't depend on global application / HttpContext.
Whether or not using the container in unit tests is another story. Personally I am not against it as long as you put stub implementations of your services into the container.
Edit: the way to configure your container using ServiceLocator:
private void ConfigureUnity()
{
UnityServiceLocator locator = new UnityServiceLocator( ConfigureUnityContainer() );
ServiceLocator.SetLocatorProvider( () => locator );
}
private IUnityContainer ConfigureUnityContainer()
{
IUnityContainer container = new UnityContainer();
// this loads container's configuration, comment or uncomment
container.LoadConfiguration();
return container;
}
You can then access the container from within the locator like:
var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
In your page, try doing things like this:
public class DepartmentReportPage : Page
{
private readonly DepartmentReportPresenter _presenter;
public DepartmentReportPage()
{
this._presenter =
UnityLocator.GetInstance<DepartmentReportPresenter>();
this._presenter.View = this;
}
}