首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET MVC View 呈現機制實戰:自訂 StaticFileViewEngine 與快取實作

     編輯:關於ASP.NET

IView 介面與靜態檔案視圖

public class StaticFileView : IView
{
    public string FileName { get; private set; }
    public StaticFileView(string fileName) { FileName = fileName; }
    
    public void Render(ViewContext viewContext, TextWriter writer)
    {
        byte[] buffer;
        using (var fs = new FileStream(FileName, FileMode.Open))
        {
            buffer = new byte[fs.Length];
            fs.Read(buffer, 0, buffer.Length);
        }
        writer.Write(Encoding.UTF8.GetString(buffer));
    }
}

ViewEngineResult 快取鍵設計

internal class ViewEngineResultCacheKey
{
    public string ControllerName { get; private set; }
    public string ViewName { get; private set; }
    public ViewEngineResultCacheKey(string controllerName, string viewName)
    {
        ControllerName = controllerName ?? String.Empty;
        ViewName = viewName ?? String.Empty;
    }
    public override int GetHashCode() 
        => ControllerName.ToLower().GetHashCode() ^ ViewName.ToLower().GetHashCode();
    public override bool Equals(object obj)
    {
        var key = obj as ViewEngineResultCacheKey;
        return key != null && key.GetHashCode() == GetHashCode();
    }
}

StaticFileViewEngine 完整實作

public class StaticFileViewEngine : IViewEngine
{
    private Dictionary<ViewEngineResultCacheKey, ViewEngineResult> _cache = new Dictionary<ViewEngineResultCacheKey, ViewEngineResult>();
    private object _sync = new object();
    
    public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        => FindView(controllerContext, partialViewName, null, useCache);
    
    public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        string controllerName = controllerContext.RouteData.GetRequiredString("controller");
        var key = new ViewEngineResultCacheKey(controllerName, viewName);
        ViewEngineResult result;
        
        if (!useCache)
        {
            result = InternalFindView(controllerContext, viewName, controllerName);
            _cache[key] = result;
            return result;
        }
        if (_cache.TryGetValue(key, out result)) return result;
        
        lock (_sync)
        {
            if (_cache.TryGetValue(key, out result)) return result;
            result = InternalFindView(controllerContext, viewName, controllerName);
            _cache[key] = result;
            return result;
        }
    }
    
    private ViewEngineResult InternalFindView(ControllerContext controllerContext, string viewName, string controllerName)
    {
        string[] searchLocations = new[]
        {
            string.Format("~/views/{0}/{1}.shtml", controllerName, viewName),
            string.Format("~/views/Shared/{0}.shtml", viewName)
        };
        
        string fileName = controllerContext.HttpContext.Request.MapPath(searchLocations[0]);
        if (File.Exists(fileName))
            return new ViewEngineResult(new StaticFileView(fileName), this);
        
        fileName = string.Format(@"\views\Shared\{0}.shtml", viewName);
        if (File.Exists(fileName))
            return new ViewEngineResult(new StaticFileView(fileName), this);
        
        return new ViewEngineResult(searchLocations);
    }
    
    public void ReleaseView(ControllerContext controllerContext, IView view) { }
}

關鍵設計解析

  • 雙重檢查鎖定:無鎖快取讀取 → 鎖定 → 再次檢查 → 建立 → 存入,避免重複建構。
  • 搜尋路徑慣例:Controller 專屬目錄優先,次為 Shared 目錄,副檔名 .shtml。
  • StaticFileView:純靜態檔案讀取,無動態編譯,效能極高,適合不變內容。
  • ReleaseView 空實作:靜態檔案無資源需釋放。

註冊使用

// Global.asax
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new StaticFileViewEngine());

總結

自訂 IViewEngine 只需實作 FindView/FindPartialView/ReleaseView。本例展示靜態檔案視圖引擎完整實作,含快取鍵設計、雙重檢查鎖定快取、慣例搜尋路徑。理解此模式可建構資料庫驅動、雲端儲存等任意來源視圖引擎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved