NET core application to integrate with the third-party IOC/DI framework?

Source: Internet
Author: User
Tags httpcontext webhost

NET core application to integrate with the third-party IOC/DI framework?

We know that the entire ASP. NET core is built on the Servicecollection/serviceprovider-centric di framework, and it even provides extensibility points that allow us to integrate with the third-party di framework. It should be clear to the readers of this comparison that the consolidation of the third-party DI framework can be achieved by returning a serviceprovider to the Configureservices method that defines the startup type. But is it really that simple?

first, the Configureservices method returned serviceprovider seemingly useless!?

We can illustrate this problem with a simple example. We first defined the following one myserviceprovider, which is actually the encapsulation of another serviceprovider. For simplicity, we use a dictionary to store the mapping between the service interface and the implementation type, which can be registered by calling the Registe method. In the GetService method that provides the service instance, if the provided service type has already been registered, we will create and return the corresponding instance object, otherwise we will use the encapsulated serviceprovider to provide the service. To ensure that the service instance can be recycled properly, if the service type implements the IDisposable interface, we will add it to the collection represented by the field _disposables. When the Dispose method of Myserviceprovider is called, the Dispose method provided by these service instances is called.

   1:public class Myserviceprovider:iserviceprovider, IDisposable
   2: {
   3:     private IServiceProvider        _innerserviceprovider;
   4:     private Dictionary<type, type>  _services;
   5:     private list<idisposable>       _disposables;
   
   7: Public     Myserviceprovider (IServiceProvider innerserviceprovider)
   8:     {
   9:         _innerserviceprovider  = Innerserviceprovider;
  Ten:         this._services         = new Dictionary<type, type> ();
  One:         _disposables           = new list<idisposable> ();
  :     }
  
  
  : Public     Myserviceprovider Register<tfrom, tto> () where Tto:tfrom, new ()
  :     {
  :         _services[typeof (tfrom)] = typeof (TTo);
  :         return this;
  :     }
  
  : Public     Object GetService (Type servicetype)
  :     {
  At:         Type implementation;
  :         if (_services. TryGetValue (servicetype, out implementation))
  :         {
  :             Object service = Activator.CreateInstance (Implementation);
  :             IDisposable disposbale = service as IDisposable;
  :             if (null! = Disposbale)
  :             {
  A:                 _disposables. ADD (Disposbale);
  :             }
  :             return service;
  :         }
  :         return _innerserviceprovider.getservice (servicetype);
  :     }
  
  PNS: Public     void Dispose ()
  :     {
  A:         (_innerserviceprovider as IDisposable)? Dispose ();
  Max:         foreach (var it in _disposables)
  In:         {
  A:             it. Dispose ();
  :         }
  :         _disposables. Clear ();
  :     }
  46:}

We use Myserviceprovider in an ASP. NET core application as follows. As in the following code fragment, in the registered Starup type, we let the Configureservices method return a Myserviceprovider object. The mapping between the service interface Ifoobar and the implementation type Foobar is registered on this Myserviceprovider object. When processing the request, we take advantage of the Requestservices property of the current HttpContext object to get the serviceprovider to service the request processing and try to use it to get the registered Ifoobar service.

   1:public class Program
   2: {
   3: Public     static void Main (string[] args)
   4:     {
   5:         New Webhostbuilder ()
   6:             . Usekestrel ()
   7:             . Usestartup<startup> ()
   8:             . Build ()
   9:             . Run ();
  Ten:     }
  11:}
  
  13:public class Startup
  14: {
  : Public     IServiceProvider configureservices (iservicecollection services)
  :     {
  :         return new Myserviceprovider (services. Buildserviceprovider ())
  :             . Register<ifoobar, foobar> ();
  :     }
  
  : Public     void Configure (Iapplicationbuilder app)
  :     {
  :         app. Usedeveloperexceptionpage ()
  A:             . Run (Async context = await context. Response.writeasync (context. Requestservices.getrequiredservice<ifoobar> (). GetType (). Name));
  :     }
  26:}
  27:public interface Ifoobar {}
  28:public class Foobar:ifoobar {}

The whole application is as simple as it seems to be, but when we launch the app and access the app using the browser, we'll see an error like the one below. The error message indicates that the service interface Ifoobar has not been registered.

second, why?

We clearly registered the mapping between Ifoobar and Foobar in the returned serviceprovider, why did Requestservices return serviceprovider say that the service has not yet been registered? The only explanation is that the serviceprovider returned by the Configureservices method is not the same serviceprovider as HttpContext requestservices. In fact, they are not the same object.

As I said in the two different serviceprovider: The serviceprovider returned by the Configureservices method will be serviceprovider for webhost, and for each request received, Webhost will create a new serviceprovider based on this serviceprovider as the requestservices attribute of the HttpContext, two serviceprovider with parent-child management. As usual, if the serviceprovider returned by Requestservices is created based on the serviceprovider returned by the Configureservices method, it should also be able to recognize the registered service type Ifoobar, So why is there still a mistake?

To understand this problem, you need to know how this so-called "sub-serviceprovider" is created, which involves the concept of servicescope. Simply put, Servicescope is a serviceprovider package that determines the life cycle of the latter. Servicescope is created by Servicescopefactory, which is registered as a service on "parent serviceprovider". When "parent serviceprovider" needs to create "sub-serviceprovider", It calls the GetService method to get the Servicescopefactory object (the service interface used is iservicescopefactory) and uses the latter to create a servicescope, The serviceprovider provided by this servicescope is the "child serviceprovider" that is returned.

But for our Myserviceprovider object, when the GetService method that calls it tries to get the Servicescopefactory object, Obtained is actually the encapsulated Serivceprovider associated servicescopefactory, then naturally created "sub serviceprovider" also has nothing to do with Myserviceprovider.

third, how to solve this problem?

Now that we know the root of the problem, we naturally have a solution. The solution is not complicated, we only need the Myserviceprovider GetService method to return the servicescopefactory that reflects its own service registration. For this we define the following servicescope and corresponding servicescopefactory.

   1:internal class Servicescope:iservicescope
   2: {
   3:     private Myserviceprovider _serviceprovider;
   
   5: Public     servicescope (Iservicescope innserservicescope, Dictionary<type, type> Services)
   6:     {
   7:         _serviceprovider = new Myserviceprovider (innserservicescope.serviceprovider, services);
   8:     }
   9: Public     IServiceProvider serviceprovider
  Ten:     {
  One:         get {return _serviceprovider;}
  :     }
  
  : Public     void Dispose ()
  :     {
  :         _serviceprovider.dispose ();
  :     }
  18:}
  
  20:internal class Servicescopefactory:iservicescopefactory
  21: {
  :     private Iservicescopefactory _innerservicefactory;
  :     private Dictionary<type, type> _services;
  
  : Public     servicescopefactory (iservicescopefactory innerservicefactory, Dictionary<type, Type> services )
  :     {
  :         _innerservicefactory = innerservicefactory;
  :         _services = Services;
  :     }
  : Public     iservicescope Createscope ()
  :     {
  :         return new Servicescope (_innerservicefactory.createscope (), _services);
  :     }
  34:}

In addition to this, we have added a constructor for Myserviceprovider, and the GetService method adds the corresponding code for iservicescopefactory.

   1:public class Myserviceprovider:iserviceprovider, IDisposable
   2: {
   3: Public     myserviceprovider (IServiceProvider innerserviceprovider, Dictionary<type, type> Services)
   4:     {
   5:         _innerserviceprovider = Innerserviceprovider;
   6:         _services = Services;
   7:         _disposables = new list<idisposable> ();
   8:     }
   
  Ten: Public     object GetService (Type servicetype)
  One:     {
  :         if (servicetype = = typeof (Iservicescopefactory))
  :         {
  :             iservicescopefactory innerservicescopefactory = _innerserviceprovider.getrequiredservice< Iservicescopefactory> ();
  :             return new Servicescopefactory (Innerservicescopefactory, _services);
  :         }
  A: ...                 
  :     }
  : ...     
  20:}

NET core application to integrate with the third-party IOC/DI framework?

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.