框架最新的升級實現了一個頁面部件功能,其實就是通過後臺方法查詢資料庫內容,把查詢結果的 HTML 代碼呈現到 Razor 視圖中,考慮到靈活性,需要能在任意 Razor 視圖中調用該方法,這樣任意 Razor 頁面都能以統一的方式方便地共用該頁面部件的 HTML 內容,這對於代碼的重用性和可維護性都... ...
上一篇介紹了 MVC中實現動態自定義路由 的實現,本篇將介紹Razor視圖中以全局方式調用後臺方法輸出頁面代碼的三種方法。
框架最新的升級實現了一個頁面部件功能,其實就是通過後臺方法查詢資料庫內容,把查詢結果的 HTML 代碼呈現到 Razor 視圖中,考慮到靈活性,需要能在任意 Razor 視圖中調用該方法,這樣任意 Razor 頁面都能以統一的方式方便地共用該頁面部件的 HTML 內容,這對於代碼的重用性和可維護性都是非常有必要的。
為實現上述要求,本文介紹如下可供選擇的三種方式。
1、擴展靜態類 Helper 方法,返回 HtmlString
1)可參考如下代碼:
public static class ImageHelper { public static HtmlString Image(this HtmlHelper helper, string id, string url, string alternateText) { return Image(helper, id, url, alternateText, null); } public static HtmlString Image(this HtmlHelper helper, string id, string url, string alternateText, object htmlAttributes) { // Instantiate a UrlHelper var urlHelper = new UrlHelper(helper.ViewContext.RequestContext); // Create tag builder var builder = new TagBuilder("img"); // Create valid id builder.GenerateId(id); // Add attributes builder.MergeAttribute("src", urlHelper.Content(url)); builder.MergeAttribute("alt", alternateText); builder.MergeAttributes(new RouteValueDictionary(htmlAttributes)); // Render tag var ret = new MvcHtmlString(builder.ToString(TagRenderMode.SelfClosing)); return ret; } }
2)此時界面可以這樣調用:
@Html.Image("my-id", "~/Content/my-img.png", "Alt Text")
總結:此方式最簡單,但缺點也非常明顯,因為是靜態類,無法方便的進行依賴註入以調用其他實例方法。
2、繼承 WebViewPage<TModel> 實現自定義的 WebViewPage ,在子類中實現返回界面 HTML 字元串的方法。
此種方式可參照Abp框架中多語言的本地化實現過程,步驟如下:
1)繼承 WebViewPage 類
public abstract class AbpWebViewPage<TModel> : WebViewPage<TModel>
2)實現方法,返回指定 Key 名稱的本地化語言字元串
/// <summary> /// Gets localized string for given key name and current language. /// </summary> /// <param name="name">Key name</param> /// <returns> /// Localized string /// </returns> protected virtual string L(string name) { return this._localizationSource.GetString(name); }
3)在 Web.config 中配置視圖基類
<system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="Yb.AbpZero.Web.Views.AbpZeroTemplateWebViewPageBase"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="System.Web.Optimization" /> <add namespace="Yb.AbpZero.Web" /> <add namespace="Yb.AbpZero.Localization" /> </namespaces> </pages> </system.web.webPages.razor>
4)這樣視圖頁面上就可以方便的調用 @L("Dashboard") 代碼輸出對應語言的字元串內容
總結:此種方式需要在指定文件夾下的 Web.config 中配置頁面視圖的基類,在未配置的頁面中無法進行方法的調用
3、推薦的最佳方案
我們換種方式實現 Helper 方法,通過使用全局 Razor 視圖中的 Helper 代碼去訪問後臺方法並輸出結果
1)繼承 System.Web.WebPages.HelperPage ,並重寫 Html 屬性
此處需要註意的是 System.Web.WebPages.HelperPage 的 Html 對象和如下重寫的 Html 對象不是同一個類,為便於記憶、統一以 MVC Razor 中的關鍵字進行界面調用,我們此處還是把屬性名稱定義為 Html 。
public class HelperPage : System.Web.WebPages.HelperPage { // Workaround - exposes the MVC HtmlHelper instead of the normal helper public static new HtmlHelper Html { get { return ((WebViewPage) WebPageContext.Current.Page).Html; } } }
2)把 Helper 方法放到 App_Code 文件夾下的 Razor 視圖中
我們已經知道Razor可以訪問本路徑下其他 Razor 視圖中定義的 Helper 方法,但現在我們考慮的是任意路徑下 Razor 視圖可均共用該 Helper 方法。
首先在 App_Code 文件夾下創建一個 Razor 視圖,該視圖將會被進行動態編譯,通過 Razor 的視圖引擎調用後臺方法輸出界面所需的 HTML 代碼,代碼如下:
@inherits YbRapidSolution.Mvc.HelperPage @using System.Web.Mvc.Html @helper Partial(string id) { Html.RenderAction("_Widget", "Home", new { id }); }
3)我們在 _Widget 的後臺方法中來訪問資料庫,然後生成頁面部分視圖並返回至界面,代碼如下:
#region CMS部件呈現 /// <summary> /// CMS部件呈現 /// </summary> /// <param name="id"></param> /// <returns></returns> [ChildActionOnly] public PartialViewResult _Widget(string id) { if (string.IsNullOrEmpty(id)) { return PartialView("E404"); } var widget = _widgetService.GetById(id); if (widget == null) { return PartialView("E404"); } if (string.IsNullOrWhiteSpace(widget.TemplatePath)) { return PartialView("_Widget", widget); } return PartialView(widget.TemplatePath, widget); } #endregion
4)這樣就可在任意頁面進行調用如下代碼生成界面所需的 Html 字元串,而字元串的內容則可放到資料庫中,可在需要的時候在後臺進行修改和維護:
@_Widget.Partial("31dbfb04b41e4883bab880ceec2cfef3")
總結:此種方式無需額外配置即可實現 Helper 方法的全局共用,調用的時候可以使用自己定義的標簽,代碼可讀性更強。