Bu benim ilgimi çekti ve sonunda onu inceleme şansım oldu. Görünüşe göre diğer insanlar bunun yönlendirmeyle ilgili bir sorun değil , görünümü bulmakla ilgili bir sorun olduğunu anlamadılar. kendisiyle - ve bunun nedeni muhtemelen soru başlığınızın bunun yönlendirme ile ilgili olduğunu belirtmesidir.
Her durumda, bu Görünüm ile ilgili bir sorun olduğu için, istediğinizi elde etmenin tek yolu varsayılan görünüm motorunu geçersiz kılmaktır . Normalde, bunu yaptığınızda, görünüm motorunuzu (yani Spark, NHaml, vb.) Değiştirmek basit bir amaç içindir. Bu durumda, geçersiz kılmamız gereken Görünüm oluşturma mantığı değil , sınıftaki FindPartialView
ve FindView
yöntemleri VirtualPathProviderViewEngine
.
Şanslı yıldızlarınıza, bu yöntemlerin aslında sanal olduğu için teşekkür edebilirsiniz, çünkü içindeki diğer her şey VirtualPathProviderViewEngine
bile erişilebilir değildir - özeldir ve bu , bulma mantığını geçersiz kılmak çok can sıkıcı hale getirir çünkü temelde zaten olan kodun yarısını yeniden yazmanız gerekir. konum önbelleği ve konum biçimleriyle iyi oynamasını istiyorsanız yazılmıştır. Reflektörde biraz kazı yaptıktan sonra nihayet çalışan bir çözüm bulmayı başardım.
Burada yaptığım şey, önce AreaAwareViewEngine
doğrudan VirtualPathProviderViewEngine
yerine doğrudan türetilen bir soyut oluşturmaktır WebFormViewEngine
. Bunu, bunun yerine (veya her neyse) Spark görünümleri oluşturmak istiyorsanız, bu sınıfı temel tür olarak kullanmaya devam edebilmeniz için yaptım.
Aşağıdaki kod oldukça uzun solukludur, bu yüzden size gerçekte ne yaptığının hızlı bir özetini vermek {2}
için: Aynı şekilde alan adına karşılık gelen konum biçimine bir eklemenizi sağlar{1}
denetleyici adına karşılık gelir. Bu kadar! Tüm bu kodu bunun için yazmamız gerekti:
BaseAreaAwareViewEngine.cs
public abstract class BaseAreaAwareViewEngine : VirtualPathProviderViewEngine
{
private static readonly string[] EmptyLocations = { };
public override ViewEngineResult FindView(
ControllerContext controllerContext, string viewName,
string masterName, bool useCache)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(viewName))
{
throw new ArgumentNullException(viewName,
"Value cannot be null or empty.");
}
string area = getArea(controllerContext);
return FindAreaView(controllerContext, area, viewName,
masterName, useCache);
}
public override ViewEngineResult FindPartialView(
ControllerContext controllerContext, string partialViewName,
bool useCache)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(partialViewName))
{
throw new ArgumentNullException(partialViewName,
"Value cannot be null or empty.");
}
string area = getArea(controllerContext);
return FindAreaPartialView(controllerContext, area,
partialViewName, useCache);
}
protected virtual ViewEngineResult FindAreaView(
ControllerContext controllerContext, string areaName, string viewName,
string masterName, bool useCache)
{
string controllerName =
controllerContext.RouteData.GetRequiredString("controller");
string[] searchedViewPaths;
string viewPath = GetPath(controllerContext, ViewLocationFormats,
"ViewLocationFormats", viewName, controllerName, areaName, "View",
useCache, out searchedViewPaths);
string[] searchedMasterPaths;
string masterPath = GetPath(controllerContext, MasterLocationFormats,
"MasterLocationFormats", masterName, controllerName, areaName,
"Master", useCache, out searchedMasterPaths);
if (!string.IsNullOrEmpty(viewPath) &&
(!string.IsNullOrEmpty(masterPath) ||
string.IsNullOrEmpty(masterName)))
{
return new ViewEngineResult(CreateView(controllerContext, viewPath,
masterPath), this);
}
return new ViewEngineResult(
searchedViewPaths.Union<string>(searchedMasterPaths));
}
protected virtual ViewEngineResult FindAreaPartialView(
ControllerContext controllerContext, string areaName,
string viewName, bool useCache)
{
string controllerName =
controllerContext.RouteData.GetRequiredString("controller");
string[] searchedViewPaths;
string partialViewPath = GetPath(controllerContext,
ViewLocationFormats, "PartialViewLocationFormats", viewName,
controllerName, areaName, "Partial", useCache,
out searchedViewPaths);
if (!string.IsNullOrEmpty(partialViewPath))
{
return new ViewEngineResult(CreatePartialView(controllerContext,
partialViewPath), this);
}
return new ViewEngineResult(searchedViewPaths);
}
protected string CreateCacheKey(string prefix, string name,
string controller, string area)
{
return string.Format(CultureInfo.InvariantCulture,
":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}:",
base.GetType().AssemblyQualifiedName,
prefix, name, controller, area);
}
protected string GetPath(ControllerContext controllerContext,
string[] locations, string locationsPropertyName, string name,
string controllerName, string areaName, string cacheKeyPrefix,
bool useCache, out string[] searchedLocations)
{
searchedLocations = EmptyLocations;
if (string.IsNullOrEmpty(name))
{
return string.Empty;
}
if ((locations == null) || (locations.Length == 0))
{
throw new InvalidOperationException(string.Format("The property " +
"'{0}' cannot be null or empty.", locationsPropertyName));
}
bool isSpecificPath = IsSpecificPath(name);
string key = CreateCacheKey(cacheKeyPrefix, name,
isSpecificPath ? string.Empty : controllerName,
isSpecificPath ? string.Empty : areaName);
if (useCache)
{
string viewLocation = ViewLocationCache.GetViewLocation(
controllerContext.HttpContext, key);
if (viewLocation != null)
{
return viewLocation;
}
}
if (!isSpecificPath)
{
return GetPathFromGeneralName(controllerContext, locations, name,
controllerName, areaName, key, ref searchedLocations);
}
return GetPathFromSpecificName(controllerContext, name, key,
ref searchedLocations);
}
protected string GetPathFromGeneralName(ControllerContext controllerContext,
string[] locations, string name, string controllerName,
string areaName, string cacheKey, ref string[] searchedLocations)
{
string virtualPath = string.Empty;
searchedLocations = new string[locations.Length];
for (int i = 0; i < locations.Length; i++)
{
if (string.IsNullOrEmpty(areaName) && locations[i].Contains("{2}"))
{
continue;
}
string testPath = string.Format(CultureInfo.InvariantCulture,
locations[i], name, controllerName, areaName);
if (FileExists(controllerContext, testPath))
{
searchedLocations = EmptyLocations;
virtualPath = testPath;
ViewLocationCache.InsertViewLocation(
controllerContext.HttpContext, cacheKey, virtualPath);
return virtualPath;
}
searchedLocations[i] = testPath;
}
return virtualPath;
}
protected string GetPathFromSpecificName(
ControllerContext controllerContext, string name, string cacheKey,
ref string[] searchedLocations)
{
string virtualPath = name;
if (!FileExists(controllerContext, name))
{
virtualPath = string.Empty;
searchedLocations = new string[] { name };
}
ViewLocationCache.InsertViewLocation(controllerContext.HttpContext,
cacheKey, virtualPath);
return virtualPath;
}
protected string getArea(ControllerContext controllerContext)
{
// First try to get area from a RouteValue override, like one specified in the Defaults arg to a Route.
object areaO;
controllerContext.RouteData.Values.TryGetValue("area", out areaO);
// If not specified, try to get it from the Controller's namespace
if (areaO != null)
return (string)areaO;
string namespa = controllerContext.Controller.GetType().Namespace;
int areaStart = namespa.IndexOf("Areas.");
if (areaStart == -1)
return null;
areaStart += 6;
int areaEnd = namespa.IndexOf('.', areaStart + 1);
string area = namespa.Substring(areaStart, areaEnd - areaStart);
return area;
}
protected static bool IsSpecificPath(string name)
{
char ch = name[0];
if (ch != '~')
{
return (ch == '/');
}
return true;
}
}
Şimdi belirtildiği gibi, bu somut bir motor değil, bu yüzden onu da yaratmalısınız. Bu kısım, neyse ki, çok daha kolay, tek yapmamız gereken varsayılan formatları ayarlamak ve aslında görünümleri oluşturmak:
AreaAwareViewEngine.cs
public class AreaAwareViewEngine : BaseAreaAwareViewEngine
{
public AreaAwareViewEngine()
{
MasterLocationFormats = new string[]
{
"~/Areas/{2}/Views/{1}/{0}.master",
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.master",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
"~/Views/{1}/{0}.master",
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.master"
"~/Views/Shared/{0}.cshtml"
};
ViewLocationFormats = new string[]
{
"~/Areas/{2}/Views/{1}/{0}.aspx",
"~/Areas/{2}/Views/{1}/{0}.ascx",
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.aspx",
"~/Areas/{2}/Views/Shared/{0}.ascx",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.aspx"
"~/Views/Shared/{0}.ascx"
"~/Views/Shared/{0}.cshtml"
};
PartialViewLocationFormats = ViewLocationFormats;
}
protected override IView CreatePartialView(
ControllerContext controllerContext, string partialPath)
{
if (partialPath.EndsWith(".cshtml"))
return new System.Web.Mvc.RazorView(controllerContext, partialPath, null, false, null);
else
return new WebFormView(controllerContext, partialPath);
}
protected override IView CreateView(ControllerContext controllerContext,
string viewPath, string masterPath)
{
if (viewPath.EndsWith(".cshtml"))
return new RazorView(controllerContext, viewPath, masterPath, false, null);
else
return new WebFormView(controllerContext, viewPath, masterPath);
}
}
Standarda birkaç girdi eklediğimizi unutmayın ViewLocationFormats
. Bunlar yeni {2}
girişler, {2}
eşlenir area
biz koymakRouteData
. Ben MasterLocationFormats
yalnız bıraktım , ama tabii ki isterseniz bunu değiştirebilirsiniz.
Şimdi değiştirin global.asax
bu görünüm motorunu kaydetmek :
Global.asax.cs
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new AreaAwareViewEngine());
}
... ve varsayılan rotayı kaydedin:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Area",
"",
new { area = "AreaZ", controller = "Default", action = "ActionY" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
}
Şimdi Oluştur AreaController
az önce referans verdiğimizi :
DefaultController.cs (~ / Controllers / içinde)
public class DefaultController : Controller
{
public ActionResult ActionY()
{
return View("TestView");
}
}
Açıkçası, bunun için dizin yapısına ve görünüme ihtiyacımız var - bunu çok basit tutacağız:
TestView.aspx (~ / Alanlar / AlanZ / Görünümler / Varsayılan / veya ~ / Alanlar / AlanZ / Görünümler / Paylaşılan /)
<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<h2>TestView</h2>
This is a test view in AreaZ.
Ve bu kadar. Sonunda bitirdik .
Çoğunlukla, sadece almak gerekir BaseAreaAwareViewEngine
ve AreaAwareViewEngine
bunun yapılması için bir sürü kod aldı rağmen ve herhangi bir MVC proje haline bırakın, sadece bir kez yazmak zorunda. Bundan sonra, sadece birkaç satırı düzenleme global.asax.cs
ve site yapınızı oluşturma meselesi .