I have a web forms application (myWebForms)
I have a class library project (myClassLibrary) that has a class called "myClass"
WebForms references myClassLibrary
I have added Autofac references to the web forms application, set the global asax to resolve "myClass" etc...
I can see that in my aspx code behind, the public property I added for AutoFac, is instantiated correctly by AutoFac.
All this is great so far, however, my actual project is a lot more complex than this, and what I need to do is have access to the resolved "myClass"
From within myClassLibrary
How do I achive this? (do I inject the container into myClass from the web forms project?, do I somehow reference the web forms global property, or do I build the container again within myClassLibrary?)
First, I'd recommend checking out the Autofac documentation on web forms and quick starts. I think you may have a lot of questions answered by doing that, though I understand it's a lot. DI is complicated, and I'm afraid that providing just a "quick answer" here may lead you to an incorrect understanding of what's going on.
Autofac quick start
ASP.NET Web Forms Integration
Working example of web forms integration
In general...
You register types with Autofac that you want to inject. This includes all the types your web forms will need as well as all the dependencies those types will need.
Autofac, via its integration, will resolve dependencies and put them in your web forms. If those objects also have dependencies (e.g., constructor parameters), then Autofac will also figure those out automatically and plug them in.
Say your web form needs a property called IEmailSender...
public IEmailSender EmailSender { get; set; }
Your email sender object may need some other dependency, like a network socket factory or something.
public EmailSender(ISocketFactory socketFactory)
You would register both of these in the container. It doesn't matter which assembly they come from. You have to register them into the Autofac container for it to work.
builder.RegisterType<EmailSender>().As<IEmailSender>();
builder.RegisterType<TcpFactory>().As<ISocketFactory>();
When your web form gets the IEmailSender, Autofac will resolve the TcpFactory first, then provide that in the constructor of EmailSender, then that will be handed to your web form.
Again, a lot of this is covered in the docs and examples. While I realize there's a lot and it can be overwhelming, I strongly urge you to walk through that info because it can save you a lot of time and pain in the long run.
Related
According to the Simple Injector documentation on WebForms integration, it says, with code examples, that we are supposed to do property injection into our Pages by utilizing the [Import] attribute. And we enable this behavior by wiring up the Global.asax file according to their code samples. And it does work for Pages. There is nothing in the documentation for UserControls or MasterPages, however.
In scouring StackOverflow for a solid answer, the ubiquitous response is slightly outdated and references creating an HttpModule, providing a link to an example project found in their git repo (SimpleInjector.Integration.Web.Forms). That example project is dead and culled from the repo as of Simple Injector v4.0, though. And it does not utilize the [Import] attribute stuff at all. Definitely confusing.
So without a clear idea of how to move forward, I've attempted to merge the two in order to get this working properly.
I am using the Global.asax bootstrapper approach as detailed in the most recent documentation, and not registering a new HttpModule. I took the container extension methods as defined in the old WebForms integration project, and am calling those in my Bootstrap instead of the old method.
private static void Bootstrap()
{
var container = new Container();
//container.Options.PropertySelectionBehavior = new ImportAttributePropertySelectionBehavior(); //approach from latest documentation
container.Options.PropertySelectionBehavior = new SimpleInjector.Integration.Web.Forms.WebFormsPropertySelectionBehavior(container.Options.PropertySelectionBehavior); //changed to using WebForms integration way
...
//RegisterWebPages(ref container); //approach from latest documentation
container.RegisterPages(); //changed to using WebForms integration extension methods
}
When I first ran it, the container.Verify() complained that every Page implements IDisposable and that they're being registered as Transient (this perplexes me because the original bootstrapping seemed to also register Pages as Transient, but does Verify did not throw any errors).
So, to fix this, I modified the RegisterPages extension method to default to Lifestyle.Scoped, which removed the Verify errors.
private static void RegisterBatchAsConcrete(this Container container, IEnumerable<Type> types)
{
foreach (Type concreteType in types)
{
//container.Register(concreteType); //originally registering Transient
container.Register(concreteType, concreteType, Lifestyle.Scoped);
}
}
And it seems to work now, at least for Pages. Before moving forward with getting this working for UserControls and MasterPages, I would like to know answers to the following:
Questions
Is this the right approach? Am I going to run into issues (performance, or otherwise) because I changed the Page, MasterPage, and UserControl registration from Transient to Scoped lifestyle? Are there any other gotcha's I'm not thinking of?
Why does Verify have a problem with Tranisent Lifestyle with the RegisterPages extension method call vs. the new RegisterWebPages method?
Should I actually be using the Import attribute, or no? The new approach uses the ImportAttributePropertySelectionBehavior, while the old approach utilizes WebFormsPropertySelectionBehavior
That example project is dead and culled from the repo as of Simple Injector v4.0, though.
The SimpleInjector.Integration.Web.Forms) was built a long time ago and was meant to become the solution for integrating Web Forms with Simple Injector. Since the lack of interest from the community (i.e. there were just too few developers interested in integrating Simple Injector with Web Forms), we decided not to invest in publishing this as NuGet package, maintain it, create documentation, fix bugs, have support for it, etc.
Since Web Forms is a legacy technology, we eventually decided to pull the project from the repository, knowing that we could always reference to older branches.
And it does not utilize the [Import] attribute stuff at all. Definitely confusing.
That's not true. [Import] will work as well, but as the documentation describes, you will have to plug in your custom ImportAttributePropertySelectionBehavior.
Why does Verify have a problem with Transient Lifestyle with the RegisterPages extension method call vs. the new RegisterWebPages method?
The integration guide for Web Forms suppresses the DisposableTransientComponent warning, so that's what you'll have to do as well. The reason this does not happen in the integration project is because this project was created during the v2.x timeframe, and at that time, the verification wasn't that strict. The project has never been updated since.
Is this the right approach? Am I going to run into issues (performance, or otherwise) because I changed the Page, MasterPage, and UserControl registration from Transient to Scoped lifestyle? Are there any other gotcha's I'm not thinking of?
You should absolutely not register your classes and user controlers as scoped, because you will run into serious trouble, really quickly. Especially for user controls, it is really common to have multiple instances of the same control in the page. Registering them as Scoped causes the same instance to be placed at multiple places in the page, which will obviously cause trouble (if it works at all).
So you should definately keep user controls (and pages probably as well) registered as Transient, and suppress the DisposableTransientComponent warning instead. DisposableTransientComponent can be suppressed, because ASP.NET will dispose everything for you when the request ends.
Should I actually be using the Import attribute, or no? The new approach uses the ImportAttributePropertySelectionBehavior, while the old approach utilizes WebFormsPropertySelectionBehavior
The ImportAttributePropertySelectionBehavior implements Explicit Property Injection using the [Import] attribute, while WebFormsPropertySelectionBehavior implements Implicit Property Injection.
That decision what to use is up to you, but Explicit Property Injection should in general be preferred, because of the downsides of Implicit Property Injection (that the documentation describes).
I'm building a new asp.net webapi application that may use asp.net MVC controllers later.
I'm going to use Unity as an IOC + Lifetime resolver to handle my objects.
I want all my types to be resolved in one place.
I've read about the IDependencyResolver which provides a service-locator(I know it's an anti-pattern) and it seems to fit my goals.
I've tried to find the "scope" of this IDependencyResolver and couldn't.
What I did see is that's he's under System.Web.Mvc - that kinda made me think about his "scope".
When does he "start" his job in the asp.net application lifecycle?
Will he resolve HttpModules as well? Or does he "kick in"
My Global.asax code will look something like this:
ApplicationUnityResolver resolver = new ApplicationUnityResolver(ApplicationContainer._container, DependencyResolver.Current);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
DependencyResolver.SetResolver(resolver);
My ApplicationUnityResolver is:
System.Web.Mvc.IDependencyResolver and System.Web.Http.Dependencies.IDependencyResolver
I think it is fairly early in the MVC pipeline the DependencyResolver get instantiated. MVC framework internally use the DependencyResolver. As you know the DependencyResolver finds and create instance of Controllers, during the Controller creation. Which is right after the IRouteHandler i.e MvcRouteHandler get invoked - fairly early in the life cycle.
But it is well after the HttpModules get created, I think you are out of luck using the DependencyResolver to register HttpModules.
I don't think you cannot customize the scope of the IDependencyResolver. It is just Service Locator type container which helps you to plugin your own dependency resolution mechanism.
Yes IDependencyResolver is an anti-pattern and I personally don't like it. Actually
Mark Seemann has a really good article on the IDependencyResolver. I'm sure this would point you to the right direction.
You better off using the Composition Root pattern to register dependencies in a single location.
Is it possible to do property injection with the OrchardCMS?
I know that Orchard uses Autofac and that Autofac does do property injection, but I need to know how to do property injection for the IOrchardServices interface.
Our team is looking at Orchard but our code base is all in ASP.NET 4.0 WebForms and so we will continue to serve aspx pages and slowly migrate those said pages into Orchard as time permits.
With that, we'll need a way to get access to the OrchardServices object. I'm thinking that this is something I'd have to come up on my own. Does any one have any good examples of performing property injection in Orchard?
It's pretty simple - look into the source how it's done with ILogger interfaces and do the same for IOrchardServices. The source file is Orchard.Framework/Logging/LoggingModule.cs. It's exactly what you are looking for, I guess.
Everything is being done via Autofac module (implementation of Autofac.Module class). What that class does is to:
register the implementation of ILogger interfaces (Load method) and
get properties of the processed object and set appropriate ones to object resolved from the container (AttachToComponentRegistration method).
Pretty simple. Autofac modules are a nice way to plug into the DI process.
It would be enough just to copy that source file to your custom Orchard module and changing ILogger to IOrchardServices (and, of course the registered class). The class I mentioned makes use of factory pattern to create instances, but you can change that to simple object creation via new and get rid of the factory-related things.
The code in its derivatives MultiServiceResolver and SingleServiceResolver are highly compact and can somebody explain what they are doing or their purposes are and the role played by them in dependency resolution?
They're the ones responsible of going to the DependencyResolver and ask it to resolve the types they asks for (i/e IViewEngine or IControllerFactory).
more info about the DependencyResolver can be found here:
http://bradwilson.typepad.com/blog/2010/10/service-location-pt5-idependencyresolver.html
Basically SingleServiceResolver calls GetSingleService from the dependencyResolver, and MultiServiceResolver calls GetServices. You can set your own DependencyResolver to use your own IOC container (AutoFac/Ninject/StructureMap etc.) using the SetResolver method in the DependencyResolver static class. by default (If you don't override it) the resolver doesn't resolve any types.
Basically this decouples the implementations of some types (i/e ViewEngines/Collection or ValueProviderFactories/ValueProviderFactoryCollections) that use the ServiceLocator pattern in the ASP.NET MVC pipeline from the ASP.NET MVC implementation and the DependencyResolver static class.
Recently, I've created a blog post that a little explains MultiServiceResolver and SingleServiceResolver.
http://www.beletsky.net/2011/08/inside-aspnet-mvc-iresolver-and-its.html
I'm working on an ASP.Net website along with a supporting Class Library for my Business Logic, Data Access code, etc.
I'm EXTREMELY new and unfamiliar with the Unity Framework and Dependency Injection as a whole. However, I've managed to get it working by following the source code for the ASP.NET 3.5 Portal Starter Kit on codeplex. But herein lies the problem:
The Class Library is setup with Unity and several of my classes have [Dependency] attributes on their properties (I'm exclusively using property setter injections for this). However, the Global.asax is telling Unity how to handle the injections....in the Class Library.
Is this best practice or should the Class Library be handle it's own injections so that I can re-use the library with other websites, webapps or applications? If that is indeed the case, where would the injection code go in this instance?
I'm not sure how clear the question is. Please let me know if I need to explain more.
Though not familiar with Unity (StructureMap user) The final mappings should live in the consuming application. You can have the dll you are using define those mappings, but you also want to be able to override them when needed. Like say you need an instance of IFoo, and you have one mapped in your Class Library, but you've added a new one to use that just lives in the website. Having the mappings defined in the site allows you to keep things loosely coupled, or else why are you using a DI container?
Personally I try and code things to facilitate an IOC container but never will try and force an IOC container into a project.
My solution breakdown goes roughly:
(Each one of these are projects).
Project.Domain
Project.Persistence.Implementation
Project.Services.Implementation
Project.DIInjectionRegistration
Project.ASPNetMVCFrontEnd (I use MVC, but it doesn't matter).
I try to maintain strict boundaries about projects references. The actual frontend project cannot contain any *.Implementation projects directly. (The *.implementation projects contain the actual implementations of the interfaces in domain in this case). So the ASPNetMVCFrontEnd has references to the Domain and the DIInjectionWhatever and to my DI container.
In the Project.DIInjectionWhatever I tie all the pieces together. So this project has all the references to the implementations and to the DI framework. It contains the code that does the registering of components. Autofac lets me breakdown component registration easily, so that's why I took this approach.
In the example here I don't have any references to the container in my implementation projects. There's nothing wrong with it, and if your implementation requires it, then go ahead.