在《[设计篇]》篇中我们通过对View引擎的总体介绍讲述了从ViewResult的 创建到View呈现的原理,为了让读者对View引擎及其View呈现机制具有一个深刻的认识,我们自定义一个简单的用于呈现静态HTML的 StaticFileViewEngine。在一个通过Visual Studio的ASP.NET MVC项目模板创建的空Web应用中,我们定义了如下一个针对于静态HTML内容呈现的自定义StaticFileView。 StaticFileView实现了IView接口,在实现的Render方法中读取制定文件的内容写入作为参数的TextWriter。
1:publicclass StaticFileView:IView
2: {
3:publicstring FileName { get; private set; }
4:public StaticFileView(string fileName)
5: {
6:this.FileName = fileName;
7: }
8:publicvoid Render(ViewContext viewContext, TextWriter writer)
9: {
10:byte[] buffer;
11:using (FileStream fs = new FileStream(this.FileName, FileMode.Open))
12: {
13: buffer = newbyte[fs.Length];
14: fs.Read(buffer, 0, buffer.Length);
15: }
16: writer.Write(Encoding.UTF8.GetString(buffer));
17: }
18: }
由于StaticFileView中定义的内容完全是静态的,所以缓存显得很有必要。我们只需要基于Controller和View名称对View实施缓存,为此我们定义了如下一个作为Key的数据类型ViewEngineResultCacheKey。
1:internalclass ViewEngineResultCacheKey
2: {
3:publicstring ControllerName { get; private set; }
4:publicstring ViewName { get; private set; }
5:
6:public ViewEngineResultCacheKey(string controllerName, string viewName)
7: {
8:this.ControllerName = controllerName ?? string.Empty;
9:this.ViewName = viewName ?? string.Empty;
10: }
11:publicoverrideint GetHashCode()
12: {
13:returnthis.ControllerName.ToLower().GetHashCode() ^ this.ViewName.ToLower().GetHashCode();
14: }
15:
16:publicoverridebool Equals(object obj)
17: {
18: ViewEngineResultCacheKey key = obj as ViewEngineResultCacheKey;
19:if (null == key)
20: {
21:returnfalse;
22: }
23:return key.GetHashCode() == this.GetHashCode();
24: }
25: }
具 有如下定义的StaticFileViewEngine代表StaticFileView对应的ViewEngine。我们通过一个字典类型的字段 viewEngineResults作为对ViewEngineResult的缓存,而View的获取操作最终实现在InternalFindView方 法中。通过StaticFileView表示的View定义在一个以View名称作为文件名的文本文件中,该文件的扩展名为.shtml(Static HTML)。
1:publicclass StaticFileViewEngine : IViewEngine
2: {
3:private Dictionary<ViewEngineResultCacheKey, ViewEngineResult> viewEngineResults = new Dictionary<ViewEngineResultCacheKey, ViewEngineResult>();
4:privateobject syncHelper = newobject();
5:public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
6: {
7:returnthis.FindView(controllerContext, partialViewName, null, useCache);
8: }
9:
10:public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
11: {
12:string controllerName = controllerContext.RouteData.GetRequiredString("controller");
13: ViewEngineResultCacheKey key = new ViewEngineResultCacheKey(controllerName, viewName);
14: ViewEngineResult result;
15:if (!useCache)
16: {
17: result = InternalFindView(controllerContext, viewName, controllerName);
18: viewEngineResults[key] = result;
19:return result;
20: }
21:if(viewEngineResults.TryGetValue(key, out result))
22: {
23:return result;
24: }
25:lock (syncHelper)
26: {
27:if (viewEngineResults.TryGetValue(key, out result))
28: {
29:return result;
30: }
31:
32: result = InternalFindView(controllerContext, viewName, controllerName);
33: viewEngineResults[key] = result;
34:return result;
35: }
36: }
37:
38:private ViewEngineResult InternalFindView(ControllerContext controllerContext, string viewName, string controllerName)
39: {
40:string[] searchLocations = newstring[]
41: {
42:string.Format( "~/views/{0}/{1}.shtml", controllerName, viewName),
43:string.Format( "~/views/Shared/{0}.shtml", viewName)
44: };
45:
46:string fileName = controllerContext.HttpContext.Request.MapPath(searchLocations[0]);
47:if (File.Exists(fileName))
48: {
49:returnnew ViewEngineResult(new StaticFileView(fileName), this);
50: }
51: fileName = string.Format(@"viewsShared{0}.shtml", viewName);
52:if (File.Exists(fileName))
53: {
54:returnnew ViewEngineResult(new StaticFileView(fileName), this);
55: }
56:returnnew ViewEngineResult(searchLocations);
57: }
58:
59:publicvoid ReleaseView(ControllerContext controllerContext, IView view)
60: { }
61: }
发表回复