How to implement Constructor injection into Xamarin Forms App? - c#

I would like to create a Xamarin app that makes use of the dependency injection pattern. My current problem is that I just cannot get it to work with xamarin in any other way than as a dependency locator anti-pattern, while I want an actual constructor injection. I have tried everything I could find, from Prism templates to tinyIoC, but the ViewModels and Views simply require a parameterless constructor. What am I missing?
The following are some sources that were helpful but did not resolve my issue
Xamarin DependencyService with Parameterized Constructor
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns/dependency-injection
https://github.com/windows-toolkit/MVVM-Samples
My app is a fresh xamarin forms template generated by VS2019, I only added a few libraries but those should not interfere in any way. Xamarin clearly provides a built-in dependency locator, but that is not what I wanted to use. I also saw a few templates that achieved what I wanted, but they were too big for me to find out how exactly they achieved that.
Ideally, I would like to use Microsoft MVVM Toolkit, but that is not a strict requirement. I would also like the implementation to be as simple as possible, as I am just starting with xamarin development.
An example of what I would like to achieve:
public class AboutViewModel : BaseViewModel
{
public AboutViewModel(ITest testService)
{
Title = "About";
OpenWebCommand = new Command(async () => await Browser.OpenAsync("https://aka.ms/xamarin-quickstart"));
}
public ICommand OpenWebCommand { get; }
}
public interface ITest
{
void Test();
}
class TestService : ITest
{
public void Test()
{
Debug.WriteLine("Test successful");
}
}

Ok, I found out I had this in my AboutPage.xaml
<ContentPage.BindingContext>
<vm:AboutViewModel />
</ContentPage.BindingContext>
Seems like a simple way to initialize viewModel in view except it can only accept parameterless constructors. That is what was causing my problems. Moving the ViewModel initialization into the code behind solved everything, though I would still prefer to just pass it through codebehind constructor.
This is the result now:
public AboutPage()
{
InitializeComponent();
BindingContext = Ioc.Default.GetRequiredService<AboutViewModel>();
}

Related

WebView2 and MVVM in WPF - PostWebMessage

I have created a web application using angular and now I want to load it in a WPF application using WebView2 (not electron). That all works well. However, I also want to be able to send messages via the WebView2 using:
webView.CoreWebView2.PostWebMessageAsString(message)
I also want to adhere to MVVM. I've created a View:
{
public AngularView()
{
InitializeComponent();
InitializeAsync();
}
public void PostMessage(string message)
{
webView.CoreWebView2.PostWebMessageAsString(message);
}
private async void InitializeAsync()
{
await webView.EnsureCoreWebView2Async();
}
}
And an AngularViewModel. Now I'd like to call PostMessage(message) from my ViewModel when a ICommand is triggered, like when button is pushed on the UI. I know that the ViewModel shouldn't know about the View, so how is the best way to go about this?
Furthermore, I'd also like to have moved my PostMessage(message) method to a WebViewService.cs class, but again, how does the service know about the CoreWebView2 property of the webView in the AngularView.
You should abstract away the view/control, for example by introducing an interface that the view implements:
public interface IWebComponent
{
void Post(string message);
}
You could then inject the view model with this interface:
public AngularViewModel(IWebComponent webComponent)
{
_webComponent = webComponent;
}
In this case the view model knows only about an interface and doesn't have any dependency upon the actual view implementation. And you can easily mock the interface in your unit tests and benefit from everything else that the MVVM design pattern brings.

How to handle dependency injection in a WPF/MVVM application

I am starting a new desktop application and I want to build it using MVVM and WPF.
I am also intending to use TDD.
The problem is that I don´t know how I should use an IoC container to inject my dependencies on my production code.
Suppose I have the folowing class and interface:
public interface IStorage
{
bool SaveFile(string content);
}
public class Storage : IStorage
{
public bool SaveFile(string content){
// Saves the file using StreamWriter
}
}
And then I have another class that has IStorage as a dependency, suppose also that this class is a ViewModel or a business class...
public class SomeViewModel
{
private IStorage _storage;
public SomeViewModel(IStorage storage){
_storage = storage;
}
}
With this I can easily write unit tests to ensure that they are working properly, using mocks and etc.
The problem is when it comes to use it in the real application. I know that I must have an IoC container that links a default implementation for the IStorage interface, but how would I do that?
For example, how would it be if I had the following xaml:
<Window
... xmlns definitions ...
>
<Window.DataContext>
<local:SomeViewModel />
</Window.DataContext>
</Window>
How can I correctly 'tell' WPF to inject dependencies in that case?
Also, suppose I need an instance of SomeViewModel from my C# code, how should I do it?
I feel I am completely lost in this, I would appreciate any example or guidance of how is the best way to handle it.
I am familiar with StructureMap, but I am not an expert. Also, if there is a better/easier/out-of-the-box framework, please let me know.
I have been using Ninject, and found that it's a pleasure to work with. Everything is set up in code, the syntax is fairly straightforward and it has a good documentation (and plenty of answers on SO).
So basically it goes like this:
Create the view model, and take the IStorage interface as constructor parameter:
class UserControlViewModel
{
public UserControlViewModel(IStorage storage)
{
}
}
Create a ViewModelLocator with a get property for the view model, which loads the view model from Ninject:
class ViewModelLocator
{
public UserControlViewModel UserControlViewModel
{
get { return IocKernel.Get<UserControlViewModel>();} // Loading UserControlViewModel will automatically load the binding for IStorage
}
}
Make the ViewModelLocator an application wide resource in App.xaml:
<Application ...>
<Application.Resources>
<local:ViewModelLocator x:Key="ViewModelLocator"/>
</Application.Resources>
</Application>
Bind the DataContext of the UserControl to the corresponding property in the ViewModelLocator.
<UserControl ...
DataContext="{Binding UserControlViewModel, Source={StaticResource ViewModelLocator}}">
<Grid>
</Grid>
</UserControl>
Create a class inheriting NinjectModule, which will set up the necessary bindings (IStorage and the viewmodel):
class IocConfiguration : NinjectModule
{
public override void Load()
{
Bind<IStorage>().To<Storage>().InSingletonScope(); // Reuse same storage every time
Bind<UserControlViewModel>().ToSelf().InTransientScope(); // Create new instance every time
}
}
Initialize the IoC kernel on application startup with the necessary Ninject modules (the one above for now):
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
IocKernel.Initialize(new IocConfiguration());
base.OnStartup(e);
}
}
I have used a static IocKernel class to hold the application wide instance of the IoC kernel, so I can easily access it when needed:
public static class IocKernel
{
private static StandardKernel _kernel;
public static T Get<T>()
{
return _kernel.Get<T>();
}
public static void Initialize(params INinjectModule[] modules)
{
if (_kernel == null)
{
_kernel = new StandardKernel(modules);
}
}
}
This solution does make use of a static ServiceLocator (the IocKernel), which is generally regarded as an anti-pattern, because it hides the class' dependencies. However it is very difficult to avoid some sort of manual service lookup for UI classes, since they must have a parameterless constructor, and you cannot control the instantiation anyway, so you cannot inject the VM. At least this way allows you to test the VM in isolation, which is where all the business logic is.
If anyone has a better way, please do share.
EDIT:
Lucky Likey provided an answer to get rid of the static service locator, by letting Ninject instantiate UI classes. The details of the answer can be seen here
In your question you set the value of the DataContext property of the view in XAML. This requires that your view-model has a default constructor. However, as you have noted, this does not work well with dependency injection where you want to inject dependencies in the constructor.
So you cannot set the DataContext property in XAML and also do dependency injection. Instead you have other alternatives.
If you application is based on a simple hierarchical view-model you can construct the entire view-model hierarchy when the application starts (you will have to remove the StartupUri property from the App.xaml file):
public partial class App {
protected override void OnStartup(StartupEventArgs e) {
base.OnStartup(e);
var container = CreateContainer();
var viewModel = container.Resolve<RootViewModel>();
var window = new MainWindow { DataContext = viewModel };
window.Show();
}
}
This is based around an object graph of view-models rooted at the RootViewModel but you can inject some view-model factories into parent view-models allowing them to create new child view-models so the object graph does not have to be fixed. This also hopefully answers your question suppose I need an instance of SomeViewModel from my cs code, how should I do it?
class ParentViewModel {
public ParentViewModel(ChildViewModelFactory childViewModelFactory) {
_childViewModelFactory = childViewModelFactory;
}
public void AddChild() {
Children.Add(_childViewModelFactory.Create());
}
ObservableCollection<ChildViewModel> Children { get; private set; }
}
class ChildViewModelFactory {
public ChildViewModelFactory(/* ChildViewModel dependencies */) {
// Store dependencies.
}
public ChildViewModel Create() {
return new ChildViewModel(/* Use stored dependencies */);
}
}
If your application is more dynamic in nature and perhaps is based around navigation you will have to hook into the code that performs the navigation. Each time you navigate to a new view you need to create a view-model (from the DI container), the view itself and set the DataContext of the view to the view-model. You can do this view first where you pick a view-model based on a view or you can do it view-model first where the view-model determines which view to use. A MVVM framework provides this key functionality with some way for you to hook your DI container into the creation of view-models but you can also implement it yourself. I am a bit vague here because depending on your needs this functionality may become quite complex. This is one of the core functions you get from a MVVM framework but rolling your own in a simple application will give you a good understanding what MVVM frameworks provide under the hood.
By not being able to declare the DataContext in XAML you lose some design-time support. If your view-model contains some data it will appear during design-time which can be very useful. Fortunately, you can use design-time attributes also in WPF. One way to do this is to add the following attributes to the <Window> element or <UserControl> in XAML:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:MyViewModel, IsDesignTimeCreatable=True}"
The view-model type should have two constructors, the default for design-time data and another for dependency injection:
class MyViewModel : INotifyPropertyChanged {
public MyViewModel() {
// Create some design-time data.
}
public MyViewModel(/* Dependencies */) {
// Store dependencies.
}
}
By doing this you can use dependency injection and retain good design-time support.
What I'm posting here is an improvement to sondergard's Answer, because what I'm going to tell doesn't fit into a Comment :)
In Fact I am introducing a neat solution, which avoids the need of a ServiceLocator and a wrapper for the StandardKernel-Instance, which in sondergard's Solution is called IocContainer. Why? As mentioned, those are anti-patterns.
Making the StandardKernel available everywhere
The Key to Ninject's magic is the StandardKernel-Instance which is needed to use the .Get<T>()-Method.
Alternatively to sondergard's IocContainer you can create the StandardKernel inside the App-Class.
Just remove StartUpUri from your App.xaml
<Application x:Class="Namespace.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
...
</Application>
This is the App's CodeBehind inside App.xaml.cs
public partial class App
{
private IKernel _iocKernel;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
_iocKernel = new StandardKernel();
_iocKernel.Load(new YourModule());
Current.MainWindow = _iocKernel.Get<MainWindow>();
Current.MainWindow.Show();
}
}
From now on, Ninject is alive and ready to fight :)
Injecting your DataContext
As Ninject is alive, you can perform all kinds of injections, e.g Property Setter Injection or the most common one Constructor Injection.
This is how you inject your ViewModel into your Window's DataContext
public partial class MainWindow : Window
{
public MainWindow(MainWindowViewModel vm)
{
DataContext = vm;
InitializeComponent();
}
}
Of course you can also Inject an IViewModel if you do the right bindings, but that is not a part of this answer.
Accessing the Kernel directly
If you need to call Methods on the Kernel directly (e.g. .Get<T>()-Method),
you can let the Kernel inject itself.
private void DoStuffWithKernel(IKernel kernel)
{
kernel.Get<Something>();
kernel.Whatever();
}
If you would need a local instance of the Kernel you could inject it as Property.
[Inject]
public IKernel Kernel { private get; set; }
Allthough this can be pretty useful, I would not recommend you to do so. Just note that objects injected this way, will not be available inside the Constructor, because it's injected later.
According to this link you should use the factory-Extension instead of injecting the IKernel (DI Container).
The recommended approach to employing a DI container in a software system is that the Composition Root of the application be the single place where the container is touched directly.
How the Ninject.Extensions.Factory is to be used can also be red here.
I go for a "view first" approach, where I pass the view-model to the view's constructor (in its code-behind), which gets assigned to the data context, e.g.
public class SomeView
{
public SomeView(SomeViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
}
This replaces your XAML-based approach.
I use the Prism framework to handle navigation - when some code requests a particular view be displayed (by "navigating" to it), Prism will resolve that view (internally, using the app's DI framework); the DI framework will in turn resolve any dependencies that the view has (the view model in my example), then resolves its dependencies, and so on.
Choice of DI framework is pretty much irrelevant as they all do essentially the same thing, i.e. you register an interface (or a type) along with the concrete type that you want the framework to instantiate when it finds a dependency on that interface. For the record I use Castle Windsor.
Prism navigation takes some getting used to but is pretty good once you get your head around it, allowing you to compose your application using different views. E.g. you might create a Prism "region" on your main window, then using Prism navigation you would switch from one view to another within this region, e.g. as the user selects menu items or whatever.
Alternatively take a look at one of the MVVM frameworks such as MVVM Light. I've got no experience of these so can't comment on what they're like to use.
Install MVVM Light.
Part of the installation is to create a view model locator. This is a class which exposes your viewmodels as properties. The getter of these properties can then be returned instances from your IOC engine. Fortunately, MVVM light also includes the SimpleIOC framework, but you can wire in others if you like.
With simple IOC you register an implementation against a type...
SimpleIOC.Default.Register<MyViewModel>(()=> new MyViewModel(new ServiceProvider()), true);
In this example, your view model is created and passed a service provider object as per its constructor.
You then create a property which returns an instance from IOC.
public MyViewModel
{
get { return SimpleIOC.Default.GetInstance<MyViewModel>; }
}
The clever part is that the view model locator is then created in app.xaml or equivalent as a data source.
<local:ViewModelLocator x:key="Vml" />
You can now bind to its 'MyViewModel' property to get your viewmodel with an injected service.
Hope that helps. Apologies for any code inaccuracies, coded from memory on an iPad.
Canonic DryIoc case
Answering an old post, but doing this with DryIoc and doing what I think is a good use of DI and interfaces (minimal use of concrete classes).
The starting point of a WPF app is App.xaml, and there we tell what is the inital view to use; we do that with code behind instead of the default xaml:
remove StartupUri="MainWindow.xaml" in App.xaml
in codebehind (App.xaml.cs) add this override OnStartup:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
DryContainer.Resolve<MainWindow>().Show();
}
that's the startup point; that's also the only place where resolve should be called.
the configuration root (according to Mark Seeman's book Dependency injection in .NET; the only place where concrete classes should be mentionned) will be in the same codebehind, in the constructor:
public Container DryContainer { get; private set; }
public App()
{
DryContainer = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient());
DryContainer.Register<IDatabaseManager, DatabaseManager>();
DryContainer.Register<IJConfigReader, JConfigReader>();
DryContainer.Register<IMainWindowViewModel, MainWindowViewModel>(
Made.Of(() => new MainWindowViewModel(Arg.Of<IDatabaseManager>(), Arg.Of<IJConfigReader>())));
DryContainer.Register<MainWindow>();
}
Remarks and few more details
I used concrete class only with the the view MainWindow;
I had to specify which contructor to use (we need to do that with DryIoc) for the ViewModel, because the default constructor needs to exist for the XAML designer, and the constructor with injection is the actual one used for the application.
The ViewModel constructor with DI:
public MainWindowViewModel(IDatabaseManager dbmgr, IJConfigReader jconfigReader)
{
_dbMgr = dbmgr;
_jconfigReader = jconfigReader;
}
ViewModel default constructor for design:
public MainWindowViewModel()
{
}
The codebehind of the view:
public partial class MainWindow
{
public MainWindow(IMainWindowViewModel vm)
{
InitializeComponent();
ViewModel = vm;
}
public IViewModel ViewModel
{
get { return (IViewModel)DataContext; }
set { DataContext = value; }
}
}
and what is needed in the view (MainWindow.xaml) to get a design instance with ViewModel:
d:DataContext="{d:DesignInstance local:MainWindowViewModel, IsDesignTimeCreatable=True}"
Conclusion
We hence got a very clean and minimal implementation of a WPF application with a DryIoc container and DI while keeping design instances of views and viewmodels possible.
Use the Managed Extensibility Framework.
[Export(typeof(IViewModel)]
public class SomeViewModel : IViewModel
{
private IStorage _storage;
[ImportingConstructor]
public SomeViewModel(IStorage storage){
_storage = storage;
}
public bool ProperlyInitialized { get { return _storage != null; } }
}
[Export(typeof(IStorage)]
public class Storage : IStorage
{
public bool SaveFile(string content){
// Saves the file using StreamWriter
}
}
//Somewhere in your application bootstrapping...
public GetViewModel() {
//Search all assemblies in the same directory where our dll/exe is
string currentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var catalog = new DirectoryCatalog(currentPath);
var container = new CompositionContainer(catalog);
var viewModel = container.GetExport<IViewModel>();
//Assert that MEF did as advertised
Debug.Assert(viewModel is SomViewModel);
Debug.Assert(viewModel.ProperlyInitialized);
}
In general, what you would do is have a static class and use the Factory Pattern to provide you with a global container (cached, natch).
As for how to inject the view models, you inject them the same way you inject everything else. Create an importing constructor (or put a import statement on a property/field) in the code-behind of the XAML file, and tell it to import the view model. Then bind your Window's DataContext to that property. Your root objects you actually pull out of the container yourself are usually composed Window objects. Just add interfaces to the window classes, and export them, then grab from the catalog as above (in App.xaml.cs... that's the WPF bootstrap file).
I would suggest to use the ViewModel - First approach
https://github.com/Caliburn-Micro/Caliburn.Micro
see:
https://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Conventions
use Castle Windsor as IOC container.
All About Conventions
One of the main features of Caliburn.Micro is manifest in its ability to remove the need for boiler plate code by acting on a series of conventions. Some people love conventions and some hate them. That’s why CM’s conventions are fully customizable and can even be turned off completely if not desired. If you are going to use conventions, and since they are ON by default, it’s good to know what those conventions are and how they work. That’s the subject of this article.
View Resolution (ViewModel-First)
Basics
The first convention you are likely to encounter when using CM is related to view resolution. This convention affects any ViewModel-First areas of your application. In ViewModel-First, we have an existing ViewModel that we need to render to the screen. To do this, CM uses a simple naming pattern to find a UserControl1 that it should bind to the ViewModel and display. So, what is that pattern? Let’s just take a look at ViewLocator.LocateForModelType to find out:
public static Func<Type, DependencyObject, object, UIElement> LocateForModelType = (modelType, displayLocation, context) =>{
var viewTypeName = modelType.FullName.Replace("Model", string.Empty);
if(context != null)
{
viewTypeName = viewTypeName.Remove(viewTypeName.Length - 4, 4);
viewTypeName = viewTypeName + "." + context;
}
var viewType = (from assmebly in AssemblySource.Instance
from type in assmebly.GetExportedTypes()
where type.FullName == viewTypeName
select type).FirstOrDefault();
return viewType == null
? new TextBlock { Text = string.Format("{0} not found.", viewTypeName) }
: GetOrCreateViewType(viewType);
};
Let’s ignore the “context” variable at first. To derive the view, we make an assumption that you are using the text “ViewModel” in the naming of your VMs, so we just change that to “View” everywhere that we find it by removing the word “Model”. This has the effect of changing both type names and namespaces. So ViewModels.CustomerViewModel would become Views.CustomerView. Or if you are organizing your application by feature: CustomerManagement.CustomerViewModel becomes CustomerManagement.CustomerView. Hopefully, that’s pretty straight forward. Once we have the name, we then search for types with that name. We search any assembly you have exposed to CM as searchable via AssemblySource.Instance.2 If we find the type, we create an instance (or get one from the IoC container if it’s registered) and return it to the caller. If we don’t find the type, we generate a view with an appropriate “not found” message.
Now, back to that “context” value. This is how CM supports multiple Views over the same ViewModel. If a context (typically a string or an enum) is provided, we do a further transformation of the name, based on that value. This transformation effectively assumes you have a folder (namespace) for the different views by removing the word “View” from the end and appending the context instead. So, given a context of “Master” our ViewModels.CustomerViewModel would become Views.Customer.Master.
Another simple solution is to create a murkup extension that resolves your view model by its type:
public class DISource : MarkupExtension {
public static Func<Type, object, string, object> Resolver { get; set; }
public Type Type { get; set; }
public object Key { get; set; }
public string Name { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider) => Resolver?.Invoke(Type, Key, Name);
}
You can adjust this extension to any DI container in the following manner:
protected override void OnStartup(StartupEventArgs e) {
base.OnStartup(e);
DISource.Resolver = Resolve;
}
object Resolve(Type type, object key, string name) {
if(type == null)
return null;
if(key != null)
return Container.ResolveKeyed(key, type);
if(name != null)
return Container.ResolveNamed(name, type);
return Container.Resolve(type);
}
Use it in XAML as simple as that:
DataContext="{local:DISource Type=viewModels:MainViewModel}"
This way, you will be able to easily assign DataContext to your view and automatically inject all required parameters directly to your view model using your DI container. With this technique, you don't have to pass your DI container or other parameters to the View constructor.
DISource doesn't depend on a container type, so you can use it with any Dependency Injection Framework. It's sufficient to set the DISource.Resolver property to a method that knows how to use your DI container.
I described this technique in greater detail at Dependency Injection in a WPF MVVM Application
Remove the startup uri from your app.xaml.
App.xaml.cs
public partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
IoC.Configure(true);
StartupUri = new Uri("Views/MainWindowView.xaml", UriKind.Relative);
base.OnStartup(e);
}
}
Now you can use your IoC class to construct the instances.
MainWindowView.xaml.cs
public partial class MainWindowView
{
public MainWindowView()
{
var mainWindowViewModel = IoC.GetInstance<IMainWindowViewModel>();
//Do other configuration
DataContext = mainWindowViewModel;
InitializeComponent();
}
}

Achieving DI without 3rd party framework

I am writing a plugin as part of a plugin architecture. The way plugins are created is via reflection and CreateInstance. Therefore the default constructor is called. This code I cannot touch and I am trying to find a sensible way to use DI without the ability to use a framework.
I believe I have 3 options:
i) Poor Man's DI (PMDI)
ii) Factory Pattern
iii) TinyIOC or similar (one cs file that handles DI)
I started looking at PMDI but then a dependency needed another dependency so I ended up with something similar to this which is ugly and could get worse:
public MyMainPluginClass() : this(new Repo(new Logger()))
{
}
public MyMainPluginClass(IRepo repo)
{
}
I then moved onto the idea of a Factory Pattern but could not find any decent demo code. I assume I would have something like this:
public static FactoryUtility
{
public static IRepo GetRepo()
{
return new Repo(GetLogger());
}
public static ILogger GetLogger()
{
return new Logger();
}
}
public MyMainPluginClass() : this(FactoryUtility.GetRepo())
{
}
public MyMainPluginClass(IRepo repo)
{
}
Is that how it would look?
I then came across TinyIOC which is one class that does all the dependency registering but I believe it requires to be setup in a Program.cs which I don't have in a class library. If someone has any experience using this could it be used like so:
public MyMainPluginClass()
{
var container = TinyIoCContainer.Current;
container.AutoRegister();
var implementation = container.Resolve<IRepo>();
MyMainPluginClass(implementation);
}
public MyMainPluginClass(IRepo repo)
{
}
Are there any alternative approaches to achieve DI without using a 3rd party library and if not which approach would choose from above?
NOTE: The code above has not been compiled and is just an idea of what I think would work. Please post corrections if they are valid approaches.
Since you're using .NET 4, you might want to consider using MEF, as it's built into the framework itself. This looks like fairly straightforward DI, which MEF handles well, as it's intended mainly for extensibility.
For details, see the Learn More page on the MEF CodePlex site.
I went with TinyIOC in the end. Unfortunately the plugin's constructor gets called several times before its actually up and running. I simply set a boolean to prevent registration being called several times and therefore it allows me to simply auto-register dependencies and off we go.
public MyMainPluginClass() : this(FactoryUtility.SetupIOC())
{
}
public MyMainPluginClass(IRepo repo)
{
}
public static class FactoryUtility
{
private static bool Initialized = false;
public static IRepo SetupIOC()
{
var container = TinyIoCContainer.Current;
if (!Initialized)
{
container.AutoRegister(new[] { Assembly.GetExecutingAssembly() });
Initialized = true;
}
var result = container.Resolve<IRepo>();
return result;
}
}
If I absolutely don't want to add a dependency to a DI container, I like to use my own TinyIOC (sorry about the name, didn't know it was taken), which for small projects gives me the same semantics as using a container, but clocks in at below 200 LOC.
If you are interested, here is the code: https://gist.github.com/ad7608e2ae10b0f04229

C# ASP.NET Dependency Injection with IoC Container Complications

I apologise for the length, and I know there are some answers on this but I searched a lot and haven't found the right solution,
so please bear with me.
I am trying to create a framework for legacy applications to use DI in ASP.NET webforms. I will probably use Castle Windsor
as the framework.
These legacy applications will use in part an MVP pattern in some places.
A presenter would look something like this:
class Presenter1
{
public Presenter1(IView1 view,
IRepository<User> userRepository)
{
}
}
Now the ASP.NET Page would look something like this:
public partial class MyPage1 : System.Web.UI.Page, IView1
{
private Presenter1 _presenter;
}
Before using DI I would instantiate the Presenter as follows in the OnInit of the page:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
_presenter = new Presenter1(this, new UserRepository(new SqlDataContext()));
}
So now I want to use DI.
First I must create a handler factory to override the construction of my page.
I found THIS really good answer to help:
How to use Dependency Injection with ASP.NET Web Forms
Now I can easily set up my containers in my composition root as Mark Seeman suggest to use the Global.asax
(This means though to create a static container that must be thread safe and sealed not to be able to add further registrations)
Now I can go and declare the constructor injection on the page
public MyPage1() : base()
{
}
public MyPage1(Presenter1 presenter) : this()
{
this._presenter = presenter;
}
Now we run into the first problem, I have a circular dependency.
Presenter1 depends on IView1, But the page depends on the presenter.
I know what some will say now that the design is probably incorrect when you have circular dependencies.
First I dont think the Presenter design is incorrect, by it taking a dependency in the constructor to the View, and I can say this
by looking at plenty of MVP implementations.
Some may suggest changing the Page to a design where Presenter1 becomes a property and then using Property injection
public partial class MyPage1 : System.Web.UI.Page, IView1
{
[Dependency]
public Presenter1 Presenter
{
get; set;
}
}
Some may even suggest removing the dependency to presenter completely and then simply Wiring up via a bunch of events, But this is
not the design I wanted and frankly dont see why I need to make this change to accomodate it.
Anyway regardless of the suggestion, another problem exists:
When the Handler factory gets a page request only a type is available (NOT THE VIEW INTERFACE):
Type pageType = page.GetType().BaseType;
now using this type you can resolve the Page via IoC and its dependencies:
container.Resolve(pageType)
This will then know that there is a property called Presenter1 and be able to inject it.
But Presenter1 needs IView1, but we never resolved IView1 through the container, so the container won't know
to provide the concrete instance the handler factory just created as it was created outside of container.
So we need to hack our handler factory and replace the view interface:
So where the handler factory resolves the page:
private void InjectDependencies(object page)
{
Type pageType = page.GetType().BaseType;
// hack
foreach (var intf in pageType.GetInterfaces())
{
if (typeof(IView).IsAssignableFrom(intf))
{
_container.Bind(intf, () => page);
}
}
// injectDependencies to page...
}
This poses another problem, most containers like Castle Windsor will not allow you to reregister this interface
to the instance it is pointing to now. Also with the container being registered in the Global.asax, it is not thread-safe to
do as the container should be read only at this point.
The other solution is to create a function to rebuild the container on each web request, and then check to see
if the container contains the component IView if not set the instance. But this seems wasteful and goes against suggested use.
The other solution is to create a special Factory called
IPresenterFactory and put the dependency in the page constructor:
public MyPage1(IPresenter1Factory factory) : this()
{
this._presenter = factory.Create(this);
}
The problem is that you now need to create a factory for each presenter and then make a call to the container
to resolve other dependencies:
class Presenter1Factory : IPresenter1Factory
{
public Presenter1Factory(Container container)
{
this._container = container;
}
public Presenter1 Create(IView1 view)
{
return new Presenter1(view, _container.Resolve<IUserRepository>,...)
}
}
This design also seems cumbersome and over complicated, does any one have ideas for a more elegant solution?
Perhaps I misunderstand your problems, but the solution seems fairly simple to me: promote the IView to a property on the Presenter1:
class Presenter1
{
public Presenter1(IRepository<User> userRepository)
{
}
public IView1 View { get; set; }
}
This way you can set the presenter on the view like this:
public Presenter1 Presenter { get; set; }
public MyPage1()
{
ObjectFactory.BuildUp(this);
this.Presenter.View = this;
}
Or without property injection, you can do it as follows:
private Presenter1 _presenter;
public MyPage1()
{
this._presenter = ObjectFactory.Resolve<Presenter1>();
this._presenter.View = this;
}
Constructor injection in Page classes and user controls will never really work. You can get it to work in full trust (as this article shows), but it will fail in partial trust. So you will have to call the container for this.
All DI containers are thread-safe, as long as you don't manually add registrations yourself after the initialization phase and with some containers even that is thread-safe (some containers even forbid registering types after initialization). There would never be a need to do this (except for unregistered type resolution, which most containers support). With Castle however, you need to register all concrete types upfront, which means it needs to know about your Presenter1, before you resolve it. Either register this, change this behavior, or move to a container that allows resolving concrete types by default.

Unity - resolving without resolve()

I would like to just markup a property with an attribute [DoInjection] and have unity do the injection. I don't want to have to use prop = Unity.Resolve(type). Thats a pain and messy. Does unity provide attributes to do this or do I have to build my own?
Edit: register in App.Main
ISessionFactory sf = new SessionFactory();
container.RegisterType<IRepository, CustomerRepository>(new InjectionConstructor(sf.CurrentUoW));
container.RegisterInstance<IUnitOfWork>(sf.CurrentUoW);
Using [Dependancy] on IUnitOfWork propery in ClassX other class but it's always null. Do I need to build ClassX instance using Unity to get this to work? It looks like I do have to. I don't like that.
Unity has a DependencyAttribute you can use for this:
public class MyObject
{
private SomeOtherObject _dependentObject;
[Dependency]
public SomeOtherObject DependentObject
{
get { return _dependentObject; }
set { _dependentObject = value; }
}
}
http://msdn.microsoft.com/en-us/library/ff650198.aspx
Based on your question, it sounds like you might be trying to use Unity in the wrong spot and your design sense was telling you it didn't feel right. You should only see Unity where you bootstrap your application. That's your Main method in a console app or Global.asax in a web or wcf app. The idea is to keep relying on dependencies all the way up the chain until you get to where you bootstrap and resolve just that one top level object using your IoC container. In a console app, I do this:
class Program
{
static void Main(string[] args)
{
using (var container = new UnityContainer())
{
container
.AddExtension(new ConfigureForConsole(args))
.Resolve<MyApplication>()
.Execute();
}
}
}
http://www.agileatwork.com/console-application-with-ioc/
In this case, MyApplication is my top level object (it doesn't need to be an interface here). The ConfigureForConsole is just a one-off custom container extension that has all the RegisterType lines in there. Alternatively you could initialize the container from App.Config here. The idea though is that your Main method has almost nothing in it. Another benefit of this approach is that it makes your code more portable. I find that console apps usually turn into windows services and keeping things clean here makes that transition pretty painless.

Categories

Resources