Alan Tsai 的學習筆記


學而不思則罔,思而不學則殆,不思不學則“網貸” 為現任微軟最有價值專家 (MVP)、微軟認證講師 (MCT) 、Blogger、Youtuber:記錄軟體開發的點點滴滴 著重於微軟技術、C#、ASP .NET、Azure、DevOps、Docker、AI、Chatbot、Data Science

[iThome 第七屆鐵人賽 12] BaseController的重要性

在這一篇將會介紹爲什麽對框架來說有一個BaseController讓所有的Controller來繼承很重要,並且介紹一個簡單的強型別的RedirectToAction讓所有繼承這個BaseController的可以來使用。

透過這個強型別的RedirectToAction讓在寫Code的時候,不要犯下寫錯Action的名字,或者Action名字改了但是對應的RedirectToAction沒有改到的低級錯誤。

爲什麽要自定自己的BaseController

所有的Controller都會繼承System.Web.Mvc.Controller。繼承的概念在OO裡面很重要,因為可以讓一些所有Controller都通用的功能,透過繼承來傳下去。同時,一些特殊的Attribute如果放在Controller的層級,那麼所有的ActionResult都會有效果,因此針對我們的框架,就會定義一個框架的BaseController來讓所有的Controller繼承,以提供一些通用的方法。

強型別的RedirectToAction

定義一個BaseController非常的簡單,只需要定一個class然後讓他繼承System.Web.Mvc.Controller,之後我們實際要使用的Controller在繼承這個BaseController 就可以了。

 /// <summary>
/// Application 層級的BaseController
/// </summary>
public class BaseController : Controller
{
}

// 繼承BaseController
public class HomeController : BaseController
{
}

爲了未來的擴充性,因此就算目前沒有任何共通的方法而讓BaseController留空都沒關係,因為有了這一層,在未來需要添加內容就會變的相對簡單。


不過爲了不讓我們的BaseController什麽都沒有,我們來做一個很好用的功能,那就是加入強型別的RedirectToAction。


那什麽是強型別的RedirectToAction?基本上Controller已經有一個RedirectToAction的方法,不過這個方法和很多Mvc的helper方法一樣,接受一個string作為參數,而這個string就是所謂的“magic string”會幫我們對應到正確的Action。舉例來說,通常儲存成功都會做一個RedirectToAction("Index"),表示回傳的內容將會是這個Controller的Index ActionResult。


問題來了,假設今天打的太快,把“Index”打成“Indx”(或者是把Action從“Index”改成了“Home”但是忘記改對應的RedirectToAction),因為它是string,在compile time完全看不出來打錯了。只有到Runtime才會發現有問題。那這個地方就有可能被漏掉並且造成系統炸掉,如果剛好在客戶面前發生,那麼整個開發團隊感覺就low掉了。


image

少打一個字母,其實肉眼很不容易發現

而強型別的RedirectToAction就可以避免掉這個問題。


取得和使用強型別的RedirectToAction


有一個Nuget的package叫做:Microsoft.AspNet.Mvc.Futures


可以透過Package Mangement Console輸入:Install-Package Microsoft.AspNet.Mvc.Futures來安裝。


這個Package就有包含一個強型別的RedirectToAction,不過它屬於extension method,因此使用起來有些變扭:

// 繼承BaseController
public class HomeController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Create()
    {
		...
        return this.RedirectToAction<HomeController>(x => x.Index());
    }
}

這個強型別的RedirectToAction是很好,可是用起來都需要加上this實在和原始的RedirectToAction感覺不一樣,難道沒有辦法讓呼叫強型別的時候,不要透過this?這時候我們的BaseController就能夠排上用場。


BaseController讓強型別的RedirectToAction用起來和原來的版本一樣


我們可在BaseController做一個Wrapper,把那個extension方法包起來,這樣呼叫起來感覺強型別的RedirectToAction就和原本的是一樣的呼叫方式:

/// <summary>
/// Application 層級的BaseController
/// </summary>
public class BaseController : Controller
{
    /// <summary>
    /// Redirects to action.
    /// </summary>
    /// <typeparam name="TController">The type of the controller.</typeparam>
    /// <param name="action">The action.</param>
    /// <returns></returns>
    protected ActionResult RedirectToAction<TController>(Expression<Action<TController>> action)
        where TController : Controller
    {
        return ControllerExtensions.RedirectToAction(this, action);
    }
}

// 繼承BaseController
public class HomeController : BaseController
{
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Create()
    {
	...
        return RedirectToAction<HomeController>(x => x.Index());
    }
}

這邊有一點需要注意,假設Index需要傳入參數,這個強型別的方法是會有問題。

結語


希望透過這個例子,能夠展示出有一個共通的Base是很好的一件事情,就算目前不需要擴充,但是只要所有的都繼承這個Base,以後要擴充就很方便。


同時希望透過介紹強型別的RedirectToAction讓在寫Code的時候,避免掉低級錯誤,像是打錯字,或者改名字沒有改到對應的“Magic String”


如果文章對您有幫助,就請我喝杯飲料吧
街口支付QR Code
街口支付QR Code
台灣 Pay QR Code
台灣 Pay QR Code
Line Pay 一卡通 QR Code
Line Pay 一卡通 QR Code
街口支付QR Code
支付寶QR Code
街口支付QR Code
微信支付QR Code
comments powered by Disqus