The tutorial by the msdn (source) recommends using an IDependencyResolver:
IDependencyResolver resolver = DependencyResolver.Current;
IDependencyResolver newResolver = new UnityDependencyResolver(container, resolver);
DependencyResolver.SetResolver(newResolver);
I was under the impression that IDependencyResolver does not properly manage object lifetime because it lacks a release method, and also that is conceptually a service locator anti-pattern (source).
How could I refactor this tutorial to not use IDependencyResolver?
Use Unity.Mvc3, there is a HierarchicalLifetimeManager that can manage lifetime for objects implementing IDispoable.
Its not an anti pattern if you resolve only at the composition root here, which basically with MVC is via constructor injection in the controller.
http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx
Note this doesn't have to be a custom controller factory you create, unity will inject automatically for you. See my code here:
http://completedevelopment.blogspot.com/2011/12/using-dependency-injection-with-mvc.html
Related
I had a webapi in which I was using app.CreatePerOwinContext in startup.cs file but I want to migrate that webapi to .net core 2.1. So I have stuck at this point as I can't fine any alternate for CreatePerOwinContext.
Here is my webapi code:
public static UserManager<IdentityUser> Create(IdentityFactoryOptions<UserManager<IdentityUser>> options, IOwinContext context)
{
var manager = new UserManager<IdentityUser>(new UserStore());
return manager;
}
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext<UserManager<IdentityUser>>(Create);
...
}
So how can I convert the above code in .net core 2.1?
That method was used as a service locator to load up dependencies and then access them throughout your code. Service location on its own is considered an anti-pattern, and is not recommended for use in the vast majority of real world situations.
Instead, people use IOC containers now to manage their dependency injection. In ASP.NET MVC Core, there's now a lightweight and "good enough" IOC container provided for you as part of the framework.
Microsoft provides an overview in this article, but the short version is that in your Startup.cs you register your dependency tree under ConfigureServices (usually using an extension method so Startup.cs doesn't get too large).
After you've registered your dependencies, you load them either through property injection, constructor injection, or method parameter injection. This results in cleaner code that is more maintainable than standard service location.
Edit:
If you truly insist on managing a service locator either because the technical debt is acceptable or because the business case warrants the current design, then I suggest you transition your work from OwinContext over to HttpContext.
In ASP.NET Core, you access the HttpContext by injecting the HttpContextAccessor into your class, and changing your OwinContext calls to pull from the key value store in HttpContext.
Instructions for injecting HttpContextAccessor can be found in this SO answer. Simply store KVPs using HttpContext.Current.Application["myObject"].
I don't recommend doing this, but I'm willing to share it because I understand the reality of deadlines vs the idealism of architecture.
Does anyone have an example of the new abstract method CreateContainerExtension that is in Prism.Wpf 7.1.0.172-pre? We are using the common service locator and have essentially bypassed IOC in Prism because we need to resolve things before the Bootstrapper has run.
You should remember that Prism is open source and the source code is in itself a form of documentation.
If you're using the classic Bootstrapper, you'll notice that it has been deprecated in favor of PrismApplication. Since your question is extremely vague as to what container you're even trying to use, it's impossible to tell exactly which Container Extension to use, but I will provide an example using Unity for your reference.
Whether you look at the UnityBootstraper or the Unity PrismApplication, you'll see that it simply returns an instance of the UnityContainerExtension.
protected override IContainerExtension CreateContainerExtension()
{
return new UnityContainerExtension();
}
Is it possible to inject dependencies into an MVC ViewPage (must support layout pages) without using DependencyResolver?
I would rather not use DependencyResolver at all (I had major problems when injecting NH sessions into ActionFilters in the past (leaking all over the place)). However, I'm not sure if there is an alternative?
The other complexity I have is that the DependencyResolver needs to be tenant aware (each tenant has its own (StructureMap) container). I'm currently doing this by passing in a lazy instance of my tenant container resolver (seems this is necessary otherwise the resolver is cached):
public SmDependencyResolver(Func<ISiteContainerResolver> containerResolver)
{
this.containerResolver = containerResolver;
}
public object GetService(Type serviceType)
{
var container = containerResolver().Resolve();
If I end up using DependencyResolver should I ditch my StructureMap controller factory since it looks like DependencyResolver handles this too?
Thanks
Ben
Given that the DependencyResolver is used by so many aspects of the ASP.NET MVC framework for dependency injection your life will be easier if you use it - as you say it means you don't need your own versions of things like the controller factory.
That said, the framework is very flexible and it is always open for you to plug in your own version of things - I just prefer to create as little of my own code as possible on the KISS principle.
Using Ninject 2 MVC 3. Correct me if i am wrong but ive seen two way of using Ninject in an MVC 3 application. We can use a new controller factory which is like ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()); or using NinjectHttpApplication and then configure the kernel.
I was wondering what difference between use of a controller factory and NinjectHttpApplication to configure the binding for DI?
And what are the best place to setup DI ?
NinjectHttpApplication calls ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()) internally.
But additionally it sets up various bindings and provides many new features. In other words it's less work and adds new features. Best you read my blog post about the MVC3 extension. http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/
I was using the default AspNetSqlMembershipProvider in my application. Authentication is performed via an AuthenticationService (since I'm also supporting other forms of membership like OpenID).
My AuthenticationService takes a MembershipProvider as a constructor parameter and I am injecting the dependency using StructureMap like so:
For<MembershipProvider>().Use(Membership.Provider);
This will use the MembershipProvider configured in web.config. All this works great.
However, now I have rolled my own MembershipProvider that makes use of a repository class. Since the MembershipProvider isn't exactly IoC friendly, I added the following code to the MembershipProvider.Initialize method:
_membershipRepository = ObjectFactory.GetInstance<IMembershipRepository>();
However, this raises an exception, like StructureMap hasn't been initialized (cannot get instance of IMembershipRepository). However, if I remove the code and put breakpoints at my MembershipProvider's initialize method and my StructureMap bootstrapper, it does appear that StructureMap is configured before the MembershipProvider is initialized.
My only workaround so far is to add the above code to each method in the MembershipProvider that needs the repository. This works fine, but I am curious as to why I can't get my instance in the Initialize method. Is the MembershipProvider performing some internal initialization that runs before any of my own application code does?
Thanks
Ben
Yes, the provider is initialized by the ASP.Net runtime when the AppDomain is spun up, far in advance of any execution of your code.
You will need to choose another point to do your composition, perhaps in Global.Application_???.