1

Create a controller:

public abstract class MyBaseController : Controller
{
   public ActionResult MyAction(string id)
   {
      return View();
   }
}

Than create another specific controller that inherit from MyBaseController:

public class MyController : MyBaseController 
{

}

There is a view called MyAction.aspx in the Views/MyBaseController folder Then, call MyController/MyAction method. Following exception will be generated:

The view 'MyAction' or its master could not be found. The following locations were searched: ~/Views/MyController/MyAction.aspx ~/Views/MyController/MyAction.ascx ~/Views/Shared/MyAction.aspx ~/Views/Shared/MyAction.ascx

Can I make MVC.NET to use the view from Views/MyBaseController folder?

Egor4eg
  • 2,678
  • 1
  • 22
  • 41

3 Answers3

3

you should wait for a more finesse answer but this work:

Create a new view engine based on the default one and override the FindViewMethod this way:


 public class MyNewViewEngine : WebFormViewEngine
 {
     public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
     {
        var type = controllerContext.Controller.GetType();

            //Retrieve all the applicable views.
            var applicableViews = from m in type.GetMethods()
                                  where typeof(ActionResult).IsAssignableFrom(m.ReturnType) & m.Name == viewName
                                  select m;

            //Save the original location formats.
            var cacheLocations = ViewLocationFormats;
            var tempLocations = cacheLocations.ToList();

            //Iterate over applicable views and check if they have been declared in the given controller.
            foreach(var view in applicableViews)
            {
                //If not, add a new format location to the ones at the default engine.
                if (view.DeclaringType != type)
                {
                    var newLocation = "~/Views/" + view.DeclaringType.Name.Substring(0, view.DeclaringType.Name.LastIndexOf("Controller")) + "/{0}.aspx";
                    if (!tempLocations.Contains(newLocation))
                        tempLocations.Add(newLocation);
                }
            }

            //Change the location formats.
            ViewLocationFormats = tempLocations.ToArray();

            //Redirected to the default implementation
            var result = base.FindView(controllerContext, viewName, masterName, useCache);

            //Restore the location formats
            ViewLocationFormats = cacheLocations;

            return result;
   }
}

Add the new view engine:


 public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new MyNewViewEngine());
            RegisterRoutes(RouteTable.Routes);
        }
    }

hope this helps

Horacio Nuñez
  • 256
  • 1
  • 7
  • No need to subclass - you can just set the search paths for Views on an existing View Engine by setting `ViewLocationFormats`. – bzlm Oct 21 '10 at 17:26
  • Why the downvote? The code is intended to work with every abstract inheritance chain, not just one that is hard coded. – Horacio Nuñez Oct 21 '10 at 18:06
0

You need to add it to shared because you are in the context of the subcontroller. If you want different behavior for different controllers, then you'll want to put a MyAction view in each of your subcontroller view folders.

To answer your question though, you probably could make it look in base controller folder, but it would require you to write your own request handler which looks in base controller folders. The default implementation only looks in the view folder for the current controller context, then it looks in the shared folder. It sounds like your view is shared however, so the shared folder seems like a good place for it anyway.

Nick Larsen
  • 18,631
  • 6
  • 67
  • 96
  • Thanks for reply. How I can override behavior of my controller in order to find view in base controller folders? – Egor4eg Oct 21 '10 at 13:06
  • 1
    @Egor4eg: Just set `ViewLocationFormats` on your existing ViewEngine. – bzlm Oct 21 '10 at 17:28
0

It is possible, but not very clean.

public class MyController : MyBaseController 
{
   public ActionResult MyAction(string id)
   {
       return View("~/Views/MyBaseController/MyAction.aspx");
   }
}

However if your View (MyAction.aspx) contains a reference to a Partial View, ASP.NET MVC will look for it in the Views/MyController folder (and not find it there!).

If your view is shared across controllers, its best to place it in the Views/Shared folder as recommended by NickLarsen.

Preets
  • 6,792
  • 12
  • 37
  • 38