精進 ASP.NET MVC 開發技術,打造高生產力與易於維護的系統 (Develop ASP.NET MVC Better)

2020-09-15

本次的筆記是從 LinkedIn Learing 課程中,反芻學習內容整理而成,深信只有動手輸出,才能夠將知識真正納為己有 😉

logo

目錄

Customizing routes with attribute routing

在 RouteConfig.cs 加入 routes.MapMvcAttributeRoutes

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapMvcAttributeRoutes();

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

即可在 Controller Action 藉由 Route Attribute 自定義路由,使用 Url.Action 的 Url 會自動配合使用新的 Route ,十分方便。

Controller.cs

[RoutePrefix("Home")]
public class HomeController : Controller
{
    [Route("~/About")] // /About/
    [Route] // /Home/
    [Route("~/")] // /
    [Route("Information")] // /Home/Information/
    [Route("Info/About")] // /Home/Info/About
    public ActionResult About()
    {
        return View();
    }
    
    [Route("Application")] // /Home/Contact -> /Home/Application/
    public ActionResult Contact()
    {
        return View();
    }
}

Route Constraint 可以進一步的限制參數條件來決定使用不同的 Action 處理。

Controller.cs

[Route(@"~/Route/{str:regex(^\d{6})}")]
public ActionResult ProcessDigits(string str)
{
    return Content($"<h1>It's Digit</h1><p>{str}</p>");
}

[Route(@"~/Route/{str:regex(^[a-zA-Z]\d{0,8})}")]
public ActionResult ProcessAlphaDigits(string str)
{
    return Content($"<h1>It's Alpha Digit String</h1><p>{str}</p>");
}

MS Docs - Route Constraints

Reuse View with AjaxRequest

共用 Controller Action 及 View,利用 IsAjaxRequest 區別呼叫是否來自於 Ajax,如果是以 Partial View 方式回傳,避免多餘的 head, body 標籤。

Custom Html Helper To reuse code

重複使用 Razor Html Code 的三種方式:

  1. Razor Helper
  2. Razor Function
  3. Html Helper Extension

Razor Helper

/cshtml

@helper ROCCalendarTrans(int commonEra)
{
    <text>@(commonEra - 1911)</text>
}

@ROCCalendarTrans(DateTime.Now.Year)

@helper AMPM(DateTime datetime)
{
    if (datetime.Hour < 12)
    {
        <text>AM🌞</text>
}
    else
    {
        <text>PM🌙</text>
    }
}

@AMPM(DateTime.Now)

Razor Function

/cshtml

@functions
{
    public int func(string str)
    {
        return 42;
    }
}

@func("params")

不論是 Razor Helper 或者 Function 都可以將程式碼存在 App_Code 讓 View 共用,引用的方式配合調整為檔案名稱即可。例如 App_Code/RazorHelper.cshtml 下則調整為 @RazorHelper.HelperName 😎

Html Helper Extension

/App_Code/HtmlHelperExteinsions.cs

namespace System.Web.Mvc
{
    public static MvcHtmlString ExtensionExamples(this HtmlHelper helper, object htmlAttributes = null)
    {
        var ele = new TagBuilder("div")
        {
            InnerHtml = "<p>Lorem Ipsum</p>"
        };
        ele.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
            
        return new MvcHtmlString(ele.ToString());
    }
}

GitHub - Nancy.ViewEngines.Razor.HtmlHelpers

目前範例寫得還不理想,主要是要用 TagBuilder 客製化可以重用的 Html Code,待實際情境再補充這部分的內容 🤔

Less Responsibility On View, More Responsibility For ViewModel

View 中複雜的邏輯抽取為 ViewModel 的方法。

  1. 不要懼怕創造新的類別(Viewmodel),為了區別輸入物件與呈現物件,使用不同的類別是可以被接受的
  2. 類別共有屬性,藉由 Controller 做 Adapter 轉換兩者
  3. Viewmodel 中可以將原本 View 的 logic 抽取出

Seperation Concerntion of Controller & Model (Abstract Service Level)

將 Controller 中龐雜的邏輯抽取為 Business Folder 下的 Service.cs

AutoFac Dependency Injection

ELMAH - Log & Monitor

The Error Logging Modules And Handlers

Nuget Install :

Install-Package elmah
Install-Package elmah.xml
Install-Package elmah.mvc

預設情況下,ELMAH 會將錯誤存在 Ram 中,安裝完成 elmah.xml packages 後,則會將資料存在 ~\App_Data\Elmah.Errors 下以 XML file 的方式保存。每一個 XML file 代表一個 錯誤。

使用 ELMAH 要特別注意存取的安全性,因為錯誤訊息的資料如果被惡意存取,將會被利用於攻擊所使用。

同時 ELMAH 可以將資料改存在資料庫,另外可以設定電子郵件通報以及區別事件的等級來決定是否通報。