Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity.MVC4 lazy<T> is not working in ASP.NET MVC app

I am using ASP.NET MVC 4 application.

Home controller’s constructor is parameterized with 2 parameter(Iservice1 service1, Iservice2 service2) Not all the code path uses any of the Service (service1, service2), only in some code path I need service1 instance/object or service2 instance/object.

I don’t want to use container.Resolve<<Lazy<IService1>>();

From this link (http://msdn.microsoft.com/en-us/library/dn178463(v=pandp.30).aspx) I understood that unity.mvc 4 use unity 3 which has Lazy loading support, but how to do this in ASP.NET MVC 4.

like image 283
sudhakar kutti Avatar asked Feb 11 '14 18:02

sudhakar kutti


1 Answers

In general, instance constructors should do nothing more than do the proper null checks and store the incoming references. This makes construction of object graphs fast and reliable. Any initialization should be postponed to a later moment in time, the time the component is used for the first time.

This will in -most cases- prevent the need from delaying creation of a component for performance and if this really still is a problem, you might want to consider a container that has better performance.

For those spare moments that you need to delay the creation, don't use a Lazy<T> for this. Injecting Lazy<T> is a leaky abstraction, just as IDisposable is when placed on interfaces. Injecting a Lazy<T> leaks, because in theory, every dependency could be slow or could need to be postponed. To prevent having to make sweeping changes throughout the applications when a slower implementation of a service is introduced, we'd better make every dependency in the application a Lazy<IDependency> up front, because this saves us from having to make changes later on.

But that's of course silly and ugly. But even when the application is small enough that such sweeping change is affordable, why should the consumer know or care about the fact that that service needs lazy initialization? Isn't that an implementation detail? Why are we baking this lazy behavior into the contract of this service? Doing so makes our code and the tests we need to write more complicated. That's unneeded accidental complexity.

So instead of injecting a Lazy<IService1>, you should simply inject an IService1 and implement and register a proxy that implements lazy behavior. That's actually really easy to do as follows:

public class LazyService1Proxy : IService1
{
    private Lazy<IService1> service;

    public LazyService1Proxy(Lazy<IService1> service) => this.service = service;

    void IService1.Method1() => this.service.Value.Method1();

    object IService1.Method2(string foo) => this.service.Value.Method2(foo);
}

This proxy can be registered as follows:

container.Register<IService1>(new InjectionFactory(c => 
    new LazyService1Proxy(
        new Lazy<IService1>(
            () => c.Resolve<RealService1Impl>()))));
like image 144
Steven Avatar answered Sep 29 '22 07:09

Steven