First, the preface
Dependencyresolver is an important component of MVC, which, by name, is responsible for the resolution of dependent objects, which can be said to be an IOC container used within the MVC framework. The creation of many objects within MVC is done through it, and maybe we don't use it directly, but if you're using unity, AUTOFAC, or looking at some open source projects, you'll always see it. Then let's take a look at how this component works.
Second, understand the working process of dependencyresolver through controller activation
Here is a digression, often interview asked: ASP.net a few core objects is what? The average person would answer: Server, Request, Response, Session, Cookie. But my answer would be HttpApplication, HttpHandler and HttpModule, which is the core type in the piping model, and the entire asp.net process and scalability are built on these objects.
Back to the subject, ASP.net request is to HttpHandler processing, for MVC, is to give a mvchandler, it is responsible for activating controller, if you do not know why, please see here. Here we directly navigate to the Mvchandler PR method:
protected internal virtual IAsyncResult BeginProcessRequest (httpcontextbase
HttpContext, AsyncCallback callback, object state) {IController controller;
Icontrollerfactory Factory;
Processrequestinit (HttpContext, out of controller, out factory); Other Operations//Call controller. Execute method} private void Processrequestinit (HttpContextBase HttpContext, out IController controller, out Icontrollerfact
Ory Factory) {HttpContext currentcontext = httpcontext.current;
Gets the controller name string controllername = RequestContext.RouteData.GetRequiredString ("Controller") from the route; by Controllerbuilder get controllerfactory, the default is Defaultcontrollerfactory factory =
Controllerbuilder.getcontrollerfactory (); Gets controller Object controller = Factory through Controllerfactory.
Createcontroller (RequestContext, controllername); }
Controllerfactory name incredible is used to create controller, we can also implement their own icontrollerfactory, participate in the controller activation process, Specifically, the ControllerBuilder.Current.SetControllerFactory method is invoked globally. Our main concern here is the controller activation process, in fact their creation process is similar. The default use of Controllerfactory is defaultcontrollerfactory. The Createcontroller method of Defaultcontrollerfactory is as follows:
Public virtual IController Createcontroller (RequestContext requestcontext, string controllername)
{
// Gets the controller type
Controllertype = Getcontrollertype (RequestContext, controllername);
IController controller = getcontrollerinstance (RequestContext, controllertype);
return controller;
}
Protected internal virtual IController getcontrollerinstance (RequestContext requestcontext, Type controllertype)
{return
controlleractivator.create (RequestContext, Controllertype);
}
You can see that it creates a IController object through a controlleractivator, using Defaultcontrolleractivator by default. Similar to Controllerfactory, we can implement Icontrolleractivator, participate in the controller activation process, Specifically, the controlleractivator is used as the Defaultconrtollerfactory constructor parameter, The ControllerBuilder.Current.SetControllerFactory method is then invoked globally. You can see that the controller activation process for MVC is flexible and provides a variety of ways for us to customize the activation process. The defaultcontrolleractivator definition is as follows:
private class Defaultcontrolleractivator:icontrolleractivator {private Func<id
Ependencyresolver> _resolverthunk; Public Defaultcontrolleractivator (): this (null) {} public defaultcontrolleractivator (Idependencyresolver Res
Olver) {if (resolver = = null) {_resolverthunk = () => dependencyresolver.current;
else {_resolverthunk = () => resolver; } public IController Create (RequestContext requestcontext, Type controllertype) {try {return (IC Ontroller) (_resolverthunk (). GetService (controllertype)?
Activator.CreateInstance (Controllertype)); The catch (Exception ex) {}}}
The _resolverthunk here is a delegate to get the Idepencyresolver object, and the actual dependencyresolver.current is obtained. We can also implement our own idependencyresolver, participate in the controller activation process, specifically in the global call Dependencyresolver static method Setresolver method. It should be noted that the Dependencyresolver type (here is the type, while the Dependencyresolver mentioned elsewhere is the meaning of the component) does not implement the Idependencyresolver interface. I think it would be more appropriate to name it Dependencyresolvercontainer. The Idepdencyresolver interface is defined as follows:
Public interface Idependencyresolver
{
object GetService (Type servicetype);
Ienumerable<object> getservices (Type servicetype);
}
The default dependencyresolver.current uses the Defaultdependencyresolver type, which is the same as the controllerfactory and controlleractivator design, and if we customize it, use , otherwise the default is used. The defaultdependencyresolver definition is as follows:
Private class Defaultdependencyresolver:idependencyresolver
{Public
object GetService (Type servicetype)
{
if (Servicetype.isinterface | | servicetype.isabstract)
{return
null;
}
Try
{
//If controller type creates controller instance object return
activator.createinstance (servicetype);
}
Catch
{return
null;
}
}
Public ienumerable<object> getservices (Type servicetype)
{return
enumerable.empty<object> () ;
}
}
As you can see, MVC completes the creation of the Controller object through Dependencyresolver. The benefit of creating an object through Dependencyresolver is that it reduces the coupling between objects; In addition, by implementing the Idependencyresolver interface, we can fully control the creation of objects, such as moving the dependencies of objects into the configuration file, and so on.
Through the above we also know that there are three types of default: Defaultcontrollerfactory, Defaultcontrolleractivator and Defaultdependencyresolver, correspond to three interfaces respectively: Icontrollerfactory, Icontrolleractivator, Idependencyresolver. They are designed to be similar, are provided to an external interface, if the external implementation of the process itself, then use, otherwise the default. In fact, this is one of the three ways we participate in the controller activation process.
Third, realize Idependencyresolver interface
Next, an example is given to prove the above process. The requirement we implement is to implement the Controller constructor injection service by implementing the Idependencyresolver interface. Such as:
public class Homecontroller:controller
{
private iuserservice _service;
Public HomeController (Iuserservice service)
{
_service = service;
}
Public ActionResult Index ()
{return
Content (_service). GetUserName ());
}
HomeController only relies on the Iuserservice interface and does not depend on the specific object.
Next we implement the Idependencyresolver interface, there are many ways to implement dependency injection, where we use unity. As follows:
public class Unitydependencyresolver:idependencyresolver
{Public
object GetService (Type servicetype)
{
if (servicetype = null)
{
throw new ArgumentNullException ("servicetype");
}
Return (Servicetype.isclass &&!servicetype.isabstract)
| | Ioc.isregistered (servicetype)? Ioc.getservice (servicetype): null;
}
Public ienumerable<object> getservices (Type servicetype)
{
if (servicetype = = null)
{
throw new ArgumentNullException ("servicetype");
}
Return (Servicetype.isclass &&!servicetype.isabstract)
| | Ioc.isregistered (servicetype)? Ioc.getservices (servicetype): null;
}
Here needs to be judged (Servicetype.isclass &&!servicetype.isabstract) | | Ioc.isregistered (ServiceType) because, as we said earlier, many objects within MVC are created by dependencyresolver components, such as the Iconrtollerfactoy above, So here we are only responsible for parsing the registered type or class (Non-abstract Class).
The IOC class is very simple here, as follows:
public class Ioc
{
private static Iunitycontainer _container = new UnityContainer ();
public static void Registertype<tfrom,tto> ()
where Tto:tfrom
{
_container. Registertype<tfrom, tto> ();
public static object GetService (type type)
{return
_container. Resolve (type);
}
public static ienumerable<object> getservices (type type)
{return
_container. ResolveAll (type);
}
public static bool Isregistered (type type)
{return
_container. Isregistered (type);
}
}
Then, in the Application_Start method, register the service and set Iocdependencyresolver:
Ioc.registertype<iuserservice, userservice> ();
Dependencyresolver.setresolver (New Iocdependencyresolver ());
Run to see the HomeController constructor Iuserservice is the UserService type.
Iv. Summary
In fact, we can achieve the same goal by implementing Icontrollerfactory or Icontrolleractivator in the above example, but using idependencyresolver would be a little simpler, And most of the IOC frameworks already offer such functionality. For example, the above unitydependencyresolver do not have their own definition, Unity for MVC already has such a type, can be used directly. If the use of AUTOFAC can be: Dependencyresolver.setresolver (new Autofacdependencyresolver (container));
The above is the entire content of this article, I hope to help you learn.