내 mvc 프로젝트에 대해 다음 레이아웃이 있습니다.
- / 컨트롤러
- /데모
- / Demo / DemoArea1Controller
- / 데모 / DemoArea2Controller
- 기타…
- /견해
- /데모
- /Demo/DemoArea1/Index.aspx
- /Demo/DemoArea2/Index.aspx
그러나 내가 이것을 가지고있을 때 DemoArea1Controller
:
public class DemoArea1Controller : Controller
{
public ActionResult Index()
{
return View();
}
}
일반적인 검색 위치와 함께 “뷰 ‘인덱스’또는 해당 마스터를 찾을 수 없습니다.”오류가 발생합니다.
“Demo”네임 스페이스의 컨트롤러가 “Demo”뷰 하위 폴더에서 검색하도록 지정하려면 어떻게해야합니까?
답변
WebFormViewEngine을 쉽게 확장하여 찾고자하는 모든 위치를 지정할 수 있습니다.
public class CustomViewEngine : WebFormViewEngine
{
public CustomViewEngine()
{
var viewLocations = new[] {
"~/Views/{1}/{0}.aspx",
"~/Views/{1}/{0}.ascx",
"~/Views/Shared/{0}.aspx",
"~/Views/Shared/{0}.ascx",
"~/AnotherPath/Views/{0}.ascx"
// etc
};
this.PartialViewLocationFormats = viewLocations;
this.ViewLocationFormats = viewLocations;
}
}
Global.asax.cs에서 Application_Start 메서드를 수정하여보기 엔진을 등록해야합니다.
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine());
}
답변
이제 MVC 6 IViewLocationExpander
에서는 뷰 엔진을 엉망으로 만들지 않고 인터페이스를 구현할 수 있습니다 .
public class MyViewLocationExpander : IViewLocationExpander
{
public void PopulateValues(ViewLocationExpanderContext context) {}
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
return new[]
{
"/AnotherPath/Views/{1}/{0}.cshtml",
"/AnotherPath/Views/Shared/{0}.cshtml"
}; // add `.Union(viewLocations)` to add default locations
}
}
여기서는 {0}
대상보기 이름, {1}
-컨트롤러 이름 및 {2}
-영역 이름입니다.
자신의 위치 목록을 반환하거나 기본값 viewLocations
( .Union(viewLocations)
) 과 병합 하거나 변경 ( viewLocations.Select(path => "/AnotherPath" + path)
) 할 수 있습니다.
MVC에서 사용자 지정보기 위치 확장기를 등록하려면 파일의 ConfigureServices
메서드에 다음 줄을 추가 Startup.cs
합니다.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new MyViewLocationExpander());
});
}
답변
실제로 경로를 생성자에 하드 코딩하는 것보다 훨씬 쉬운 방법이 있습니다. 다음은 새 경로를 추가하기 위해 Razor 엔진을 확장하는 예입니다. 내가 완전히 확신하지 못하는 한 가지는 여기에 추가하는 경로가 캐시 될지 여부입니다.
public class ExtendedRazorViewEngine : RazorViewEngine
{
public void AddViewLocationFormat(string paths)
{
List<string> existingPaths = new List<string>(ViewLocationFormats);
existingPaths.Add(paths);
ViewLocationFormats = existingPaths.ToArray();
}
public void AddPartialViewLocationFormat(string paths)
{
List<string> existingPaths = new List<string>(PartialViewLocationFormats);
existingPaths.Add(paths);
PartialViewLocationFormats = existingPaths.ToArray();
}
}
그리고 Global.asax.cs
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ExtendedRazorViewEngine engine = new ExtendedRazorViewEngine();
engine.AddViewLocationFormat("~/MyThemes/{1}/{0}.cshtml");
engine.AddViewLocationFormat("~/MyThemes/{1}/{0}.vbhtml");
// Add a shared location too, as the lines above are controller specific
engine.AddPartialViewLocationFormat("~/MyThemes/{0}.cshtml");
engine.AddPartialViewLocationFormat("~/MyThemes/{0}.vbhtml");
ViewEngines.Engines.Add(engine);
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
참고할 사항 : 사용자 지정 위치에는 루트에 ViewStart.cshtml 파일이 필요합니다.
답변
새 경로 만 추가하려는 경우 기본보기 엔진에 추가하고 몇 줄의 코드를 절약 할 수 있습니다.
ViewEngines.Engines.Clear();
var razorEngine = new RazorViewEngine();
razorEngine.MasterLocationFormats = razorEngine.MasterLocationFormats
.Concat(new[] {
"~/custom/path/{0}.cshtml"
}).ToArray();
razorEngine.PartialViewLocationFormats = razorEngine.PartialViewLocationFormats
.Concat(new[] {
"~/custom/path/{1}/{0}.cshtml", // {1} = controller name
"~/custom/path/Shared/{0}.cshtml"
}).ToArray();
ViewEngines.Engines.Add(razorEngine);
동일하게 적용됩니다 WebFormEngine
답변
RazorViewEngine을 서브 클래 싱하거나 완전히 대체하는 대신 기존 RazorViewEngine의 PartialViewLocationFormats 속성을 변경할 수 있습니다. 이 코드는 Application_Start에 있습니다.
System.Web.Mvc.RazorViewEngine rve = (RazorViewEngine)ViewEngines.Engines
.Where(e=>e.GetType()==typeof(RazorViewEngine))
.FirstOrDefault();
string[] additionalPartialViewLocations = new[] {
"~/Views/[YourCustomPathHere]"
};
if(rve!=null)
{
rve.PartialViewLocationFormats = rve.PartialViewLocationFormats
.Union( additionalPartialViewLocations )
.ToArray();
}
답변
마지막으로 확인한 결과, 사용자 고유의 ViewEngine을 구축해야합니다. 그래도 RC1에서 더 쉽게 만들 었는지 모르겠습니다.
첫 번째 RC 이전에 사용한 기본 접근 방식은 내 ViewEngine에서 컨트롤러의 네임 스페이스를 분할하고 부품과 일치하는 폴더를 찾는 것이 었습니다.
편집하다:
돌아와서 코드를 찾았습니다. 다음은 일반적인 아이디어입니다.
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName)
{
string ns = controllerContext.Controller.GetType().Namespace;
string controller = controllerContext.Controller.GetType().Name.Replace("Controller", "");
//try to find the view
string rel = "~/Views/" +
(
ns == baseControllerNamespace ? "" :
ns.Substring(baseControllerNamespace.Length + 1).Replace(".", "/") + "/"
)
+ controller;
string[] pathsToSearch = new string[]{
rel+"/"+viewName+".aspx",
rel+"/"+viewName+".ascx"
};
string viewPath = null;
foreach (var path in pathsToSearch)
{
if (this.VirtualPathProvider.FileExists(path))
{
viewPath = path;
break;
}
}
if (viewPath != null)
{
string masterPath = null;
//try find the master
if (!string.IsNullOrEmpty(masterName))
{
string[] masterPathsToSearch = new string[]{
rel+"/"+masterName+".master",
"~/Views/"+ controller +"/"+ masterName+".master",
"~/Views/Shared/"+ masterName+".master"
};
foreach (var path in masterPathsToSearch)
{
if (this.VirtualPathProvider.FileExists(path))
{
masterPath = path;
break;
}
}
}
if (string.IsNullOrEmpty(masterName) || masterPath != null)
{
return new ViewEngineResult(
this.CreateView(controllerContext, viewPath, masterPath), this);
}
}
//try default implementation
var result = base.FindView(controllerContext, viewName, masterName);
if (result.View == null)
{
//add the location searched
return new ViewEngineResult(pathsToSearch);
}
return result;
}
답변
다음과 같이 시도하십시오.
private static void RegisterViewEngines(ICollection<IViewEngine> engines)
{
engines.Add(new WebFormViewEngine
{
MasterLocationFormats = new[] {"~/App/Views/Admin/{0}.master"},
PartialViewLocationFormats = new[] {"~/App/Views/Admin//{1}/{0}.ascx"},
ViewLocationFormats = new[] {"~/App/Views/Admin//{1}/{0}.aspx"}
});
}
protected void Application_Start()
{
RegisterViewEngines(ViewEngines.Engines);
}