1

Resolved

View activation process unification

description

Currently we have two different places with different code that implements view instantiation logic.

PrecompiledMvcView.Render
This code is used to create an instance of ordinary view. It:
  1. Tries to resolve IViewPageActivator through DependencyResolver and use it to create instance of needed view class.
  2. If activator could not be resolved, it uses DependencyResolver to resolve required class instance.
  3. If previous steps failed (object is still uninitialized), it uses Activator.CreateInstance as a fallback mechanism.
object instance = null;
if (DependencyResolver.Current != null)
{
    var viewPageActivator = DependencyResolver.Current.GetService<IViewPageActivator>();
    if (viewPageActivator != null)
        instance = viewPageActivator.Create(viewContext.Controller.ControllerContext, _type);
    else
        instance = DependencyResolver.Current.GetService(_type);
}
if (instance == null)
    instance = Activator.CreateInstance(_type);

WebViewPage webViewPage = instance as WebViewPage;
PrecompiledMvcViewEngine.CreateInstance
The code below is used to instantiate specific views: _ViewStart & Layouts. Its logic:
  1. Tries to resolve instance of a class class through DependencyResolver if it has been set.
  2. If dependency resolver is null, it uses Activator.CreateInstance
if (_mappings.TryGetValue(virtualPath, out type))
{
    if (DependencyResolver.Current != null)
    {
        return DependencyResolver.Current.GetService(type);
    }
    return Activator.CreateInstance(type);
}
This logic does not use IViewPageActivator. Moreover, DependencyResolver.GetService could return null.

I use Autofac and its ASP.NET MVC integration. It uses explicit service registration, so if some class have not been registered explicitly, it could not be resolved (DependencyResolver returns null). Before precompiled view engine, all things were ok, because default RazorViewEngine implementation uses DefaultViewPageActivator class and it use Activator.CreateInstance as a fallback:
return _resolverThunk().GetService(type) ?? Activator.CreateInstance(type);
I suggest to unify this logic and incapsulate it in the similar default activator class. And use it in PrecompiledMvcView.Render and PrecompiledMvcViewEngine.CreateInstance methods. See my pull request.

comments

davidebbo wrote Apr 26, 2013 at 5:24 AM

Fixed in changeset b0a2e6258e987bc8c8b27759df48fa52817cf37d