ASP.NET MVC 4 视图页去哪里儿
前戏
在mvc中,执行完action之后,会返回一个actionresult对象,之后再执行该对象的executeresult方法,这也就是【view的呈现】的入口!
【view的呈现】包括了:根据模版去寻找请求的视图页、编译视图页、再执行视图页的内容。本篇就来介绍寻找视图页的详细过程,其中涉及到了mvc 4的一个新特性--“手机视图页”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public abstract class viewresultbase : actionresult
{
public override void executeresult(controllercontext context)
{
if (context == null)
{
throw new argumentnullexception("context");
}
if (string.isnullorempty(viewname))
{
viewname = context.routedata.getrequiredstring("action");
}
viewengineresult result = null;
if (view == null)
{
//通过视图引擎去创建视图对象,并将视图对象和该视图相关的信息封装在viewengineresult对象中。
result = findview(context);
view = result.view;
}
textwriter writer = context.httpcontext.response.output;
viewcontext viewcontext = new viewcontext(context, view, viewdata, tempdata, writer);
view.render(viewcontext, writer);
if (result != null)
{
result.viewengine.releaseview(context, view);
}
}
}
public class viewresult : viewresultbase
{
protected override viewengineresult findview(controllercontext context)
{
//寻找当前请求的视图页,如果能找到则创建视图对象。
//遍历每个视图引擎(默认有两个webformengine、razorviewengine),并执行每一个视图引擎的findview方法。
viewengineresult result = viewenginecollection.findview(context, viewname, mastername);
//如果创建了视图对象,即:指定路径中存在相匹配的视图页(.cshtml文件)。
if (result.view != null)
{
return result;
}
//没有创建视图对象,即:指定路径中不存在相匹配的视图页(.cshtml文件)。
stringbuilder locationstext = new stringbuilder();
foreach (string location in result.searchedlocations)
{
locationstext.appendline();
locationstext.append(location);
}
throw new invalidoperationexception(string.format(cultureinfo.currentculture,
mresources.common_viewnotfound, viewname, locationstext));
}
}
viewengineresult result = viewenginecollection.findview(context, viewname, mastername);则是遍历每个视图引擎(默认有两个webformengine、razorviewengine),并执行每一个视图引擎的findview方法。
注:在执行视图引擎的findview方法时,先按照从缓存表中找是否存在请求的视图页,如果没有的话,再进行一次寻找!
下面以razorviewengine为例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public abstract class virtualpathproviderviewengine : iviewengine
{
//usecache先是true,该方法返回的是null。则让usecache=false,再执行一遍。即:先通过缓存去找,如果没有找到的话,就正经的去找。
public virtual viewengineresult findview(controllercontext controllercontext, string viewname, string mastername, bool usecache)
{
if (controllercontext == null)
{
throw new argumentnullexception("controllercontext");
}
if (string.isnullorempty(viewname))
{
throw new argumentexception(mvcresources.common_nullorempty, "viewname");
}
string[] viewlocationssearched;
string[] masterlocationssearched;
string controllername = controllercontext.routedata.getrequiredstring("controller");
//获取视图的路径,这里就是咱们本篇博文的内容的入口点!!!!!!!!!!!!!!!!!!!
//viewlocationformats、areaviewlocationformats定义在派生类razorviewengine类中。
//viewlocationformats:"~/views/{1}/{0}.cshtml","~/views/{1}/{0}.vbhtml", "~/views/shared/{0}.cshtml","~/views/shared/{0}.vbhtml"
//areaviewlocationformats:"~/areas/{2}/views/{1}/{0}.cshtml", "~/areas/{2}/views/{1}/{0}.vbhtml", "~/areas/{2}/views/shared/{0}.cshtml","~/areas/{2}/views/shared/{0}.vbhtml"
string viewpath = getpath(controllercontext, viewlocationformats, areaviewlocationformats, "viewlocationformats", viewname, controllername, cachekeyprefixview, usecache, out viewlocationssearched);
string masterpath = getpath(controllercontext, masterlocationformats, areamasterlocationformats, "masterlocationformats", mastername, controllername, cachekeyprefixmaster, usecache, out masterlocationssearched);
if (string.isnullorempty(viewpath) || (string.isnullorempty(masterpath) && !string.isnullorempty(mastername)))
{
return new viewengineresult(viewlocationssearched.union(masterlocationssearched));
}
return new viewengineresult(createview(controllercontext, viewpath, masterpath), this);
}
}
啪啪啪
getpath方法在寻找【视图页】时,首先将当前请求的controller和action的名称添加到地址格式化器中,这样就有了要寻找的地址(们),之后就来检查格式化后的地址是否真的存在指定的【视图页】。如果是通过手机端来请求,则会对格式化之后的地址进行再进行处理(如:index.cshtml修改为index.mobile.cshtml),之后再检查新地址下是否存在【视图页】。
注:默认情况下会先检查是否为手机端访问!