views:

2755

answers:

4

I'm trying to create a webapplication where I want to be able to plug-in separate assemblies. I'm using MVC preview 4 combined with Unity for dependency injection, which I use to create the controllers from my plugin assemblies. I'm using WebForms (default aspx) as my view engine.

If I want to use a view, I'm stuck on the ones that are defined in the core project, because of the dynamic compiling of the ASPX part. I'm looking for a proper way to enclose ASPX files in a different assembly, without having to go through the whole deployment step. Am I missing something obvious? Or should I resort to creating my views programmatically?


Update: I changed the accepted answer. Even though Dale's answer is very thorough, I went for the solution with a different virtual path provider. It works like a charm, and takes only about 20 lines in code altogether I think.

+7  A: 

This is what I would recommend. I would just structure my views in the core project in a manner to accomplish what you want. Come up with a naming convention for your views for use and then create controls or partial views for reuse.

I would then leverage the IViewLocator interface to change where to look for the views. After that, you can set your ViewLocator when you create your controller using the unity logic you put in, based on the criteria you want to use.

First, you will want to create a ViewLocator based on the structure you came up with.

public class CustomViewLocator : ViewLocator
{
        private string _area;

        public CustomViewLocator(string area)
        {
            _area = area;
        }

     protected override string GetMasterLocation(RequestContext requestContext, string masterName)
     {
      RegisterMasterLocationFormats();
      return base.GetMasterLocation(requestContext, masterName);
     }

     protected override string GetViewLocation(RequestContext requestContext, string viewName)
     {
      RegisterViewLocationFormats();
      return base.GetViewLocation(requestContext, viewName);
     }

     private void RegisterViewLocationFormats()
     {
      if (!String.IsNullOrEmpty(_area))
      {
       ViewLocationFormats = new[]
                {
                    "~/Views/" + _area + "/{1}/{0}.aspx",
                    "~/Views/" + _area + "/{1}/{0}.ascx"
                };
      }
     }

     private void RegisterMasterLocationFormats()
     {
      if (!String.IsNullOrEmpty(_area))
      {
       MasterLocationFormats = new[]
                {
                    "~/Views/" + _area + "/{1}/{0}.master",
                    "~/Views/" + _area + "/Layouts/{0}.master"
                };
      }
     }

    }

Then in your ControllerFactory, inside the CreateController method that you are using with unity, use this line to set your ViewLocator for the controller.

public IController CreateController(RequestContext context, string controllerName)
{
  var controller = null;  // Unity logic to retrieve controller.

  // Set the ViewLocator
  if (controller != null)
   ((WebFormViewEngine)controller.ViewEngine).ViewLocator = new CustomViewLocator("Structure1");

  return controller;
}

Right now there really isn't a good way to implement what you want, but what I outlined above is probably the simplest route.

Dale Ragan
This isn't accurate any more. There is no ViewLocator in version 1.0.
Jakub Šturc
+4  A: 

Essentially this is the same issue as people had with WebForms and trying to compile their UserControl ASCX files into a DLL. I found this http://www.codeproject.com/KB/aspnet/ASP2UserControlLibrary.aspx that might work for you too.

Joseph Kingry
+1  A: 
protected void Application_Start()
{
    WebFormViewEngine engine = new WebFormViewEngine();

    engine.ViewLocationFormats = new[] { "~/bin/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" };
    engine.PartialViewLocationFormats = engine.ViewLocationFormats;

    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(engine);

    RegisterRoutes(RouteTable.Routes);
}

Set the 'Copy to output' property of your view to 'Copy always'

weelink
A: 

An addition to all you who are still looking for the holy grail: I've come a bit closer to finding it, if you're not too attached to the webforms viewengine.

I've recently tried out the Spark viewengine. Other than being totally awesome and I wouldn't go back to webforms even if I was threathened, it also provides some very nice hooks for modularity of an application. The example in their docs is using Windsor as an IoC container, but I can't imagine it to be a lot harder if you want to take another approach. Read it here.

Erik van Brakel