Autofac equivalent of Ninject's WhenInjectedInto() - asp.net-mvc-3

So we're working on converting some projects at work from Ninject to Autofac, and we've stumbled on something really neat within Ninject that we can't figure out how to do in Autofac. In our application, we have an interface called ISession which is implemented in two different concrete types. One goes to an Oracle database, and the other goes to an MS-SQL database.
We have controllers in our MVC application that need only one concrete implementation of ISession based on which controller they are being injected into. For example:
Bind<IFoo>().To<Foo1>();
Bind<IFoo>().To<Foo2>().WhenInjectedInto<OracleController>();
My question is: how do we achieve the same result in Autofac? When IFoo is injected into any controller, Foo1 should be provided by default, however in one special case, we need Foo2 instead.
Thanks for any help in advance!

With Autofac you can achieve this by doing the registration the other way around. So you should declare that you want to use the "speciel" service when you register the OracleController not when you register the IFoo.
containerBuilder.RegisterType<Foo1>().As<IFoo>();
containerBuilder.RegisterType<Foo2>().Named<IFoo>("oracle");
containerBuilder.RegisterType<OracleController>().WithParameter(ResolvedParameter.ForNamed<IFoo>("oracle"));
The Named registration "oracle" ensures that the default IFoo instance will be Foo1 and you only get Foo2 when you explicitly request it by name.

Related

Use custom model binder from different assembly and instantiate object from same

I have a class library which includes a custom MVC model binder to instantiate various concrete types which derive from an abstract class. The model binder is almost identical to the one described in this post.
It works fine when using it from within the same Visual Studio Solution that also includes an MVC web application for testing.
My problem is that having created a nuget package from the assembly and included it in a totally separate MVC application the model binder no longer works, despite having configured it correctly in Global.asax.cs.
After some hair pulling I recreated the model binder directly in the separate MVC app, and as I was doing so I noticed that the overridden CreateModel() method in the binder is protected. It now gets executed and I suspect the protected keyword has something to do with it but I would like someone to explain why exactly.
Even with the 'local' modelbinder there are more problems. When it executes, and tries to instantiate the concrete object, I get an exception Could not load type XXXX from assembly { separate MVC project assembly name} so it seems the model binder is unable to load types from outside its own assembly.
Can anyone give me more information on why this happens and what I can do to work around it? Bearing in mind I need the model binder and models to reside in the class library not in the MVC assembly.
I had the same problem as you did, binding to models in a different assembly, but I needed a different solution. I used the same model binding example that you linked to, and I also got the same exception: Could not load type XXXX from assembly
I ended up needing to use the AssemblyQualifiedName for each concrete type. So my views contain this:
#Html.Hidden("ModelType", Model.GetType().AssemblyQualifiedName)
Instead of this:
#Html.Hidden("ModelType", Model.GetType())
I'm still wondering why this was necessary, since the default model binder can load types from the assembly in question.
OK so I was being stupid. It turns out that a few assumptions led me on a wild goose chase.
The ModelBinder was executing correctly to start with. My viewmodel had nested properties which were also abstract base types and required the model binder but I hadn't put the hidden fields in the view to identify their concrete type, nor had I added them to the Global.asax configuration. Once I did this everything started to work as expected.

Spring overwriting controller

I provide a highly customisable application to my clients which is working totally by itself. But If one my client wants to overwrite any Controller, I want to replace my implementation by theirs. However just overwriting the controller causes an ambiguous definition of mappings.
I have been using Component Scanning to load beans.
The potential solutions came to my mind are:
Using component scanner with excluding by a custom filter? (This seems not so easy)
Using a xxxxPostProcessor to remove some beans? (How?)
Any help?
If I got your Question properly,
You can differ implementation by changing URL to particular Implementation name
Say Telecom is interface and AirtelImpl and RelianceImpl are Controllers then
Your request mapping
#RequestMapping(value= "/airtel/doBilling")
#RequestMapping(value= "/reliance/doBilling")
In this way, Implementation flow will differ.
I have followed these steps:
Created a custom annotation: #Devoted
Created a custom ImportBeanDefinitionRegistrar. Iterated already registered bean definitions to find out `#Devoted #Controller's and removed them.
Based on a request I will provide implementation details.

Webapi DefaultHttpControllerSelector does not properly resolve my controller

I have an WebApi application that contains some controllers (they are registered using the extension method RegisterApiControllers). This application references another assembly that contains other controllers that I don't want to expose(I have checked that they are not registered in the container). It happens that both have an OrderController, and when I try to access the /api/Order url, I get an exception "Multiple types were found that match the controller named 'order'." and the stack trace shows that I was in DefaultHttpControllerSelector.
I have seen that AutofacControllerFactory used to exist and there was even a ConfigureWebApi that registered it, but it is not anymore present in the default branch.(you can see it here http://alexmg.com/post/2012/03/09/Autofac-ASPNET-Web-API-(Beta)-Integration.aspx)
It seems also that we can not filter the namespace of the route definition in WebApi (it is possible to MVC).
So any idea on how I can use only the Controller registered in my Autofac container and not use the DefaultHttpControllerSelector that seems to scan all referenced assemblies to discover controller?
Thanks
The problem is that registering the controller with autofac is not really related to the routing process. Only once the routing process has identified which controller to dispatch to will Autofac be called to resolve the type.
It looks like, from digging around in the source, that you would need to write a replacement IHttpControllerSelector in order to handle two controllers with the same name. (which really sucks BTW).
You might be able replace the DefaultHttpControllerTypeResolver with an instance that is passed a predicate that filters out the controllers from the assembly that you want to ignore. It's a bit of a kludgy solution but might work.
Actually, you might be able to replace the DefaultHttpControllerTypeResolver completely with one that is based on registrations in your Autofac container. It is a very simple interface, so as long as Autofac have a some kind of discovery mechanism, you should be golden.
public interface IHttpControllerTypeResolver
{
ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver);
}

ASP.NET MVC Views Dependency Injection without DependencyResolver?

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.

ASP.NET MembershipProvider and StructureMap

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_???.

Resources