官术网_书友最值得收藏!

Locating views

When asked to return a view (ViewResult), the framework needs first to locate the view file (.cshtml).

The built-in conventions around locating view files are as follows:

  • View files end with the cshtml extension.
  • View filenames should be identical to the view names, minus the extension (for example, a view of Index will be stored in a file named Index.cshtml).
  • View files are stored in a Views folder and inside a folder named after the controller they are returned from—for example, Views\Home.
  • Global or shared views are stored in either the Views folder directly or inside a Shared folder inside of it—for example, Views\Shared.

Actually, this is controlled by the ViewLocationFormats collection of the RazorViewEngineOptions class (Razor is the only included view engine). This has the following entries, by default:

  • /Views/{1}/{0}.cshtml
  • /Views/Shared/{0}.cshtml
The {1} token is replaced by the current controller name and {0} is replaced by the view name. The / location is relative to the ASP.NET Core application folder, not wwwroot.

If you want the Razor engine to look in different locations, all you need to do is tell it; so, through the AddRazorOptions method, that is usually called in sequence to AddMvc, in the ConfigureServices method, like this:

services
.AddMvc()
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/AdditionalViews/{0}.cshtml");
});

The view locations are searched sequentially in the ViewLocationFormats collection until one file is found.

The actual view file contents are loaded through IFileProviders. By default, only one file provider is registered (PhysicalFileProvider), but more can be added through the configuration. The code can be seen in the following snippet:

services
.AddMvc()
.AddRazorOptions(options =>
{
options.FileProviders.Add(new CustomFileProvider());
});

Adding custom file providers may prove useful—for example, if you want to load contents from non-orthodox locations, such as databases, ZIP files, assembly resources, and so on. There are multiple ways to do this. Let's try them in the following subsections.

Using view location expanders

There is an advanced feature by which we can control, per request, the locations to search the view files: it's called view location expanders. View location expanders are a Razor thing, and thus are also configured through AddRazorOptions, as illustrated in the following code snippet:

services
.AddMvc()
.AddRazorOptions(options =>
{
options.ViewLocationExpanders.Add(new ThemesViewLocationExpander
("Mastering"));
});

A view location expander is just some class that implements the IViewExpander contract. For example, imagine you want to have a theme framework that would add a couple of folders to the views search path. You could write it like this:

public class ThemesViewLocationExpander : IViewLocationExpander
{
public ThemesViewLocationExpander(string theme)
{
this.Theme = theme;
}

public string Theme { get; }

public IEnumerable<string> ExpandViewLocations(
ViewLocationExpanderContext context,
IEnumerable<string> viewLocations)
{
var theme = context.Values["theme"];

return viewLocations
.Select(x => x.Replace("/Views/", "/Views/" + theme + "/"))
.Concat(viewLocations);
}

public void PopulateValues(ViewLocationExpanderContext context)
{
context.Values["theme"] = this.Theme;
}
}

The default search locations, as we've seen, are the following:

  • /Views/{1}/{0}.cshtml
  • /Views/Shared/{0}.cshtml

By adding this view location expander, for a theme called Mastering, these will become the following:

  • /Views/{1}/{0}.cshtml
  • /Views/Mastering/{1}/{0}.cshtml
  • /Views/Shared/Mastering/{0}.cshtml
  • /Views/Shared/{0}.cshtml

The IViewLocationExpander interface defines only two methods, as follows:

  • PopulateValues: Used to initialize the view location expander; in this example, I used it to pass some value in the context.
  • ExpandViewLocations: This will be called to retrieve the desired view locations.

View location expanders are queued, so they will be called in sequence, from the registration order; each ExpandViewLocations method will be called with all the locations returned from the previous one.

Both methods, through the context parameter, have access to all the request parameters (HttpContext, RouteData, and so on), so you can be as creative as you like, and define the search locations for the views according to whatever rationale you can think of.

主站蜘蛛池模板: 江都市| 拉萨市| 宁化县| 宜兰县| 荔浦县| 错那县| 岚皋县| 东宁县| 南康市| 隆昌县| 武川县| 望江县| 常宁市| 西乡县| 荃湾区| 集安市| 陵川县| 武乡县| 来安县| 台州市| 崇义县| 侯马市| 中超| 隆林| 澄迈县| 十堰市| 鸡东县| 锡林浩特市| 固安县| 达日县| 佛冈县| 扶余县| 凤山县| 同德县| 海阳市| 河西区| 广水市| 托里县| 古丈县| 贡山| 方城县|