I am fairly new to DI with Autofac and wonder if the following is possible
I want to create a generic controller and action that receives an
injected type.
I do not want an instance of the injected type, but just need its
type, which would be an inplementation of an expected interface.
I would also like to pass that generic type on to a ViewModel, but that is another subject altogether, however if some genious out there can solve both that would be excellent.
public ContractorController<T> : Controller
where T : IContractor{
public ViewResult New() {
var vNewModel = new NewViewModel<T>();
return View(vNewModel);
}
}
This controller should be called through
http://mysite.com/Contractor/New
I have been looking into registering generics with AutoFac, but it
seems that the problem is that the AutofacControllerFactory only implements GetControllerInstance(), expecting the controller Type passed to it from either GetController() or CreateController(), not sure which or what the diffirence is between them. These methods receive the controller's name as a string from RoutData and return the corresponding .NET type which, give the url, http://mysite.com/Contractor/New is controller=Contractor and thus ContractorController cannot be matched by GetController() or CreateController() and therfore passing null to GetControllerInstance() which mean AutofacControllerFactory does not attempt to resolve the type.
I figured that I would have to create a custom Controller Factory
deriving from AutofacControllerFactory, override GetController() or CreateController() and
perform my own mapping from the controller names to the generic types.
Something like
if (controllerName == "Contractor")
return System.Type.GetType(
"UI.Controllers." + controllerName + "Controller`1");
When I debug this I can see that this code is finding the generic controller and returning it.
I thought I could then just register the types like
builder.RegisterType<FakeContractor>().As<IContractor>();
builder.RegisterGeneric(typeof(ContractorController<>));
But I am getting the following error
The Autofac service
'UI.Controllers.ContractorController`1'
representing controller
'ContractorManagement.UI.Controllers.ContractorController`1'
in path '/Contractor/New' has not been registered.
So I think I may be barking up the wrong tree.
Can anyone please shed some light on how I can do this without pulling
my teeth
Thank you
I'm not entirely sure why you want a controller using a generic. Using a generic on a Controller isn't really supported in Mvc - or at least the supporting routing path would be involved. Perhaps you can provide more info on the reasoning behind the approach?
What it looks like is that you want a controller that supports model binding against varying types. The next question is whether these types vary across a common interface or base class.
If that's the case, for Mvc2 check out the IocModelBinder information. This will work with Autofac quite well. This will allow the type to be model bound on post or get allowing you to inject services with autofac.
If you want to vary the types by a common base - supporting a variety of concrete view model - then check out the DerivedTypeModelBinder in MvcContrib. There is a version that works in Mvc 1, 2 and now MvcContrib for Mvc3 has a good sample app to accompany it. The Mvc3 implementation is also faster - speed wasn't a problem before, it's just a more efficient identification process.
Maybe it's not a direct answer to your question, but this is the only possible way to use generic controllers that I ever seen and used:
public abstract class ContractorControllerBase<T> : Controller where T : IContractor {
public ViewResult New() {
var vNewModel = new NewViewModel<T>();
return View(vNewModel);
}
}
public class FakeContractorController : ContractorControllerBase<FakeContractor> {
}
Related
In a current WebApi project I have a generic controller:
public class EntityController<T>
where T : Entity { }
It's created at runtime with a specified type if the controller name in the route matches a type name.
For example: /api/user/ initialises controller EntityController<User>.
To accomplish this, I'm using a custom ControllerSelector:
internal class ControllerSelector : DefaultHttpControllerSelector
{
... other members omitted for clarity
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
string controllerName = base.GetControllerName(request);
HttpControllerDescriptor descriptor;
Type controllerType = typeof(EntityController<>).MakeGenericType(_entityTypes[controllerName]);
descriptor = new HttpControllerDescriptor(_configuration, controllerName, controllerType);
_descriptorCache.TryAdd(controllerName, descriptor);
return descriptor;
}
... other members omitted for clarity
}
It appears this method is not going to work in .Net Core.
I've found and tried these examples but they don't appear to solve my problem:
This question simply changes the route values.
This question prints out the controller names have already been loaded (but the title suggests it's what I need).
Another question suggested creating instances of all the possible generic controllers so they could be picked up by the dependency registration engine but this doesn't feel right.
Other questions started pointing to towards a custom IRouter but the implementations seemed far too convoluted for what was easily achieved in the previous version.
So, using .Net Core, how can I control the creation of controllers to create a generic controller on the fly?
What is best way to get injections in base controller when using C# StructureMap.Mvc?
I can think of these 2 ways and don't know which is better.
From controller arguments to base controller arguments
(Nice approach but becomes a mess when there are many controllers with many properties to be injected)
Don't use child controller and initiate all injections using ObjectFactory.CreateInstance() in base controller constructor
(Very less code and manageable but not considered as good practice when Controller Injection is available)
thanks in advance.
I think bother approaches are fine and you can use the mix of both. Of course depending in the situation.
A. I believe if your child Controller require a dependency to be injected, then use the Constructor injection. This way you Controller's constructor API is explicit and it should state what has been injected into the Controller. Easy to read, and easy for discoverability. If you try to hide your DI types in a factory you lose this nice API/discoverability. Use property injection when the dependencies are optional if you think so. You don't really have pass these to the base Controller unless all your Child Controllers use them.
If you think you overloading the types in your Controller, try to aggreagate those interfaces to a single types.
B. It is not advisable to directly use the Structure map ObjectFactory in your Controller. Your Controllers should be agnostics of any infrastructure DI work. You can make use a generic factory (in infrastructure) to create types which uses the ObjectFactory within. If your DI types are required by the base Controller you may use this factory to resolve those types.
The ideas, inject types only when/where they need. Avoid injecting types to Controllers when they don't use/need.
Another option you available to you is setter injection via StructureMap's ObjectFactory.BuildUp() method.
It's worth mentioning that in StructureMap 3.1 the ObjectFactory has been deprecated in favour of injecting an instance of IContainer.
The examples would look like this:
StructureMap 3.0 and below:
public class BaseController {
protected IMyExampleServer MyExampleService { get; set; };
public BaseController() {
ObjectFactory.BuildUp(this);
}
....
}
StructureMap 3.1+:
public class BaseController {
protected IMyExampleServer MyExampleService { get; set; };
public BaseController(IContainer container) {
container.ObjectFactory.BuildUp(this);
}
....
}
Using StructureMap 3.1 would mean you'd only need to inject an instance of IContainer into your derived controller rather than each individual dependency that your base class requires.
kinda new to MVC, and kinda new with Ninject. Playing around...
I've defined ninject in my MVC application as follows:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind(
x => x.FromThisAssembly()
.SelectAllClasses()
.BindAllInterfaces()
);
}
I have controller with a form and this ActionResult:
public ActionResult Index(IMember Member)
{
return View();
}
and it's returning an error: "Cannot create an instance of an interface."
Now I understand that it might not like the interface but isn't Ninject supposed to inject the real class in there? do I need to put in the actual class? if so, doesn't that take the point out of using interfaces and building a lossly-cuppuled apps?
BTW in my Index.cshtml file I have the following as the first line:
#model IMember
Thanks
You seem to be confusing constructor dependency injection with action method parameters, they are not the same thing.
In your case you seem to want Ninject to somehow inject a concrete IMember implementation whenever a client (browser, etc) calls the Index action.
Bear in mind that any parameters that are going to be passed into an Action method are going to be coming from the client and not from the framework, so it wouldn't make sense to do this.
I am sure there is a hack you could do to make it work for e.g decorate the parameter with [Inject] or something but you've already lost at that point because you have just "revealed your sources" to the controller which is against the point of Inverting control - you might as well just pass the Ninject IKernel to the controller.
Anyway in your case, Ninject will only inject into the Controller constructor (assuming you have correctly wired it up) and in that respect, Doug's answer here is actually correct - if that IMember is some kind of controller dependency, then you must inject it into the constructor, and store it in for e.g. a private member so that you can later refer to it from within action methods.
If the IMember is not a controller dependency but is instead just a model-bound parameter that you want passed to your controller, then Dependency Injection is not the answer - the parameter should be coming from the caller.
Also, there might be another problem even if you do end up using constructor injection.
The convention-based binding you are using requires that there is a single class called Member that implements IMember, i.e that the class name differs from the interface name only by lack of the initial "I". If this isn't the case for your class, then the convention-based binding will not work anyway and you need to use something explicit like
kernel.Bind<IMember>.To<MyMemberImplementationClassName>();
Hope that helps.
Is your RegisterServices method in the NinjectWebCommon.cs file located in the App_Start folder?
You'll also need to pass the Member object into the view kind of like below:
public class HomeController : Controller
{
private IMember _member;
public HomeController(IMember member)
{
_member = member;
}
public ActionResult Index()
{
return View(_member);
}
}
I am newbie in asp.net mvc. I heard the word ASP.NET MVC generic controller, can anyone easily explain what it is? I have worked with the default controller before but now I want to able to visualize the kind of purpose ASP.NET MVC generic controller does. It will be very helpful if some one can explain the situations when a developer has to think about using ASP.NET MVC generic controller. Concepts and code about how to implement it will be greatly appreciated. Thanks
You usually create a generic class to abstract away operations you can perform on a range of types, for example Entity Framework models containing an ID. In that case you can move all duplicate code into a base class.
For an MVC controller, a generic base controller may look like this:
public abstract class GenericController<T>
where T : class
{
public virtual ActionResult Details(int id)
{
var model = _repository.Set<T>().Find(id);
return View(model);
}
}
And an implementation like this:
public class FooController : GenericController<Foo>
{
}
Now when someone requests /Foo/Details/42, the entitiy is pulled from the _repository's Set<Foo>(), without having to write anything for that in the FooController.
This way you can create a basic "CRUD" controller that lets you easily extend your application with Create, Read, Update and Delete operations for new models.
I have the following Interface
interface IProfileRepo {
}
And it's implementation
public class DBProfileRepo : IProfileRepo {
string _specialValue;
public DBProfileRepo(IAuthorizedController authController) {
_specialValue = authController.SomeValue;
}
}
My binding is
Bind<IProfileRepo>()
.To<DBProfileRepo>()
.InRequestScope();
My MVC controller which implements IAuthorizedController, is receiving this injection of DBProfileRepo, however, DBProfileRepo requires this controller as a constructor argument. How can I do this?
I am using Ninject 2.2.1.0
You have circular dependency between your objects and this is something you should avoid when designing your object hierarchy. A repository should not require a controller instance, that simply doesn't make sense. A repository is a data access class which could be reused in different kind of applications such as Desktop or Silverlight where there are no controllers. It is the controller which should require a repository and that's pretty much all.
If you need to pass some information to this repository which is available only in the controller, like for example a request parameter, simply design an object and pass this object to the repository method from the controller but don't pass an entire controller.