问题
On ASP.NET 5 a Component view must be in one of two places:
Views/NameOfControllerUsingComponent/Components/ComponentName/Default.cshtml
Views/Shared/Components/ComponentName/Default.cshtml
Is there a way to change this to:
Views/NameOfControllerUsingComponent/Components/ComponentName.cshtml
Views/Shared/Components/ComponentName.cshtml
So basically, remove the folder ComponentName and change the view name from Default.cshtml to ComponentName.cshtml.
For me it makes more sense ... Is it possible?
回答1:
That convention is only applied if you create a view component that derives from the base ViewComponent provided by the framework.
That class defines the View
helpers, which return a ViewViewComponentResult:
public ViewViewComponentResult View<TModel>(string viewName, TModel model)
{
var viewData = new ViewDataDictionary<TModel>(ViewData, model);
return new ViewViewComponentResult
{
ViewEngine = ViewEngine,
ViewName = viewName,
ViewData = viewData
};
}
The ViewViewComponentResult
is where the conventions are defined:
private const string ViewPathFormat = "Components/{0}/{1}";
private const string DefaultViewName = "Default";
public async Task ExecuteAsync(ViewComponentContext context)
{
...
string qualifiedViewName;
if (!isNullOrEmptyViewName &&
(ViewName[0] == '~' || ViewName[0] == '/'))
{
// View name that was passed in is already a rooted path, the view engine will handle this.
qualifiedViewName = ViewName;
}
else
{
// This will produce a string like:
//
// Components/Cart/Default
//
// The view engine will combine this with other path info to search paths like:
//
// Views/Shared/Components/Cart/Default.cshtml
// Views/Home/Components/Cart/Default.cshtml
// Areas/Blog/Views/Shared/Components/Cart/Default.cshtml
//
// This supports a controller or area providing an override for component views.
var viewName = isNullOrEmptyViewName ? DefaultViewName : ViewName;
qualifiedViewName = string.Format(
CultureInfo.InvariantCulture,
ViewPathFormat,
context.ViewComponentDescriptor.ShortName,
viewName);
}
...
}
Notice that if you return from your view component the full path to a view as the view name, then the view component will use the specified view. Something like:
return View("~/Views/Shared/Components/ComponentName.cshtml")
Since there is no way to modify the conventions in ViewViewComponentResult
and your approach would only work for view components with a single view, you could build something using the root view paths approach:
- Create your own
ViewComponent
class extending the existing one. Add new helper methods or hide the existing
View
methods to return a view using a full path:public ViewViewComponentResult MyView<TModel>(TModel model) { var viewName = string.Format( "~/Views/Shared/Components/{0}.cshtml", this.ViewComponentContext.ViewComponentDescriptor.ShortName) return View(viewName, model); }
- If you add new methods you might be able to add them as extension methods of
ViewComponent
instead of having to create your own class.
Another alternative would be creating a class SingleViewViewComponent
copying the code for ViewComponent but replacing the implementation of ViewViewComponentResult View<TModel>(string viewName, TModel model)
. Then when creating your view components, you would inherit from SingleViewViewComponent
instead of ViewComponent
.
来源:https://stackoverflow.com/questions/33527801/change-component-view-location-in-asp-net-5