¿Cómo implemento un RazorViewEngine personalizado para encontrar vistas en ubicaciones no estándar?

Estoy buscando implementar un RazorViewEngine personalizado. Básicamente tengo dos sitios con efectivamente la misma base de código. Las diferencias son que se ven diferentes. Quiero sobrescribir el motor de vista estándar para hacer que MVC se vea en dos ubicaciones separadas para sus vistas, diseños, etc., una para la compañía A y otra para la Compañía B. La empresa A contendrá las vistas maestras y la vista de la compañía B anulará estas maestras. Así que quiero que View Engine busque en la ubicación B una vista, diseño, maestro o parcial si la encuentra y luego la devuelve; si no la encuentra, quiero que sea la predeterminada para las vistas de la compañía A. Obviamente, la compañía A solo mirará en su propia carpeta.

Está bien al quid de la cuestión: he encontrado este sitio: http://www.aspnetwiki.com/mvc-3-razor:extending-the-view-engine

Primera pregunta, ¿es esta la mejor manera de lograr esto?

En segundo lugar, ¿debo anular los CreatePartial , CreateView , FindPartial y FindView ?

Actualizar

Ok, he descubierto la segunda pregunta yo mismo, los métodos que quiero anular son CreateView y CreatePartialView ya que en este punto está construida la cadena de visualización y puedo jugar con ella.

Ok, al final opté por un enfoque detallado aquí: http://weblogs.asp.net/imranbaloch/archive/2011/06/27/view-engine-with-dynamic-view-location.aspx

Gracias a @Adriano por las respuestas y los consejos, pero al final creo que este enfoque se ajusta mejor a mis necesidades. El siguiente enfoque me permite mantener la funcionalidad estándar, pero para crear una nueva ubicación de vista de mayor prioridad para buscar.

 public class Travel2ViewEngine : RazorViewEngine { protected BrandNameEnum BrandName; private string[] _newAreaViewLocations = new string[] { "~/Areas/{2}/%1Views/{1}/{0}.cshtml", "~/Areas/{2}/%1Views/{1}/{0}.vbhtml", "~/Areas/{2}/%1Views//Shared/{0}.cshtml", "~/Areas/{2}/%1Views//Shared/{0}.vbhtml" }; private string[] _newAreaMasterLocations = new string[] { "~/Areas/{2}/%1Views/{1}/{0}.cshtml", "~/Areas/{2}/%1Views/{1}/{0}.vbhtml", "~/Areas/{2}/%1Views/Shared/{0}.cshtml", "~/Areas/{2}/%1Views/Shared/{0}.vbhtml" }; private string[] _newAreaPartialViewLocations = new string[] { "~/Areas/{2}/%1Views/{1}/{0}.cshtml", "~/Areas/{2}/%1Views/{1}/{0}.vbhtml", "~/Areas/{2}/%1Views/Shared/{0}.cshtml", "~/Areas/{2}/%1Views/Shared/{0}.vbhtml" }; private string[] _newViewLocations = new string[] { "~/%1Views/{1}/{0}.cshtml", "~/%1Views/{1}/{0}.vbhtml", "~/%1Views/Shared/{0}.cshtml", "~/%1Views/Shared/{0}.vbhtml" }; private string[] _newMasterLocations = new string[] { "~/%1Views/{1}/{0}.cshtml", "~/%1Views/{1}/{0}.vbhtml", "~/%1Views/Shared/{0}.cshtml", "~/%1Views/Shared/{0}.vbhtml" }; private string[] _newPartialViewLocations = new string[] { "~/%1Views/{1}/{0}.cshtml", "~/%1Views/{1}/{0}.vbhtml", "~/%1Views/Shared/{0}.cshtml", "~/%1Views/Shared/{0}.vbhtml" }; public Travel2ViewEngine() : base() { Enum.TryParse(Travel2.WebUI.Properties.Settings.Default.BrandName, out BrandName); AreaViewLocationFormats = AppendLocationFormats(_newAreaViewLocations, AreaViewLocationFormats); AreaMasterLocationFormats = AppendLocationFormats(_newAreaMasterLocations, AreaMasterLocationFormats); AreaPartialViewLocationFormats = AppendLocationFormats(_newAreaPartialViewLocations, AreaPartialViewLocationFormats); ViewLocationFormats = AppendLocationFormats(_newViewLocations, ViewLocationFormats); MasterLocationFormats = AppendLocationFormats(_newMasterLocations, MasterLocationFormats); PartialViewLocationFormats = AppendLocationFormats(_newPartialViewLocations, PartialViewLocationFormats); } private string[] AppendLocationFormats(string[] newLocations, string[] defaultLocations) { List viewLocations = new List(); viewLocations.AddRange(newLocations); viewLocations.AddRange(defaultLocations); return viewLocations.ToArray(); } protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { return base.CreateView(controllerContext, viewPath.Replace("%1", BrandName.ToString()), masterPath); } protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) { return base.CreatePartialView(controllerContext, partialPath.Replace("%1", BrandName.ToString())); } protected override bool FileExists(ControllerContext controllerContext, string virtualPath) { return base.FileExists(controllerContext, virtualPath.Replace("%1", BrandName.ToString())); } } 

luego regístrese en Gloabal.asax

 protected void Application_Start(object sender, EventArgs e) { RegisterRoutes(RouteTable.Routes); //Register our customer view engine to control T2 and TBag views and over ridding ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new Travel2ViewEngine()); } 

Sí, ese es el camino, pero no es necesario anular esos métodos. RazorViewEngine hereda de VirtualPathProviderViewEngine para que pueda usar sus propiedades para establecer la ubicación de sus vistas.

Para ver un ejemplo, lea Creación de su primer MVC ViewEngine y Cómo establecer una ruta predeterminada (A un área) en MVC .

Aquí está mi respuesta: agregue esto a su global.ascx

  ViewEngines.Engines.Clear(); var customEngine = new RazorViewEngine(); customEngine.PartialViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml", "~/Views/Partial/{0}.cshtml", "~/Views/Partial/{1}/{0}.cshtml" }; customEngine.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml", "~/Views/Controller/{1}/{0}.cshtml" }; customEngine.MasterLocationFormats = new string[] { "~/Views/Shared/{0}.cshtml", "~/Views/Layout/{0}.cshtml" }; ViewEngines.Engines.Add(customEngine); 

esas son las carpetas donde la cuchilla revisa sus puntos de vista.

Hazme saber si esto funciona.