OOP繼承技巧:BaseController與BaseApiController

繼承技巧:BaseController與BaseApiController

BaseController與BaseApiController類別技巧不算是ASP.NET MVC或ASP.NET Web API的技術,它是一個OOP(Object-oriented programming,物件導向程式設計)繼承的應用,這在早期Web Forms就已經被大量使用,因為它只是單純的OOP繼承應用,並不會被語言或框架所限制。

ASP.NET MVC - Controller類別

我們先來看看我們在進行開發的Controller類別繼承關係:

IController繼承關係

ControllerBase類別繼承自IController介面,Controller類別繼承自ControllerBase類別,而ControllerBase與Controller都是抽象類別:

 public abstract class ControllerBase : IController {}
 public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer {}  
 

而我們開發者所在的ASP.NET MVC的Controller都是繼承自Controller抽象類別,Controller抽象類別提供開發者所需的大部分功能:

 public class HomeController : Controller {}  
 

從程式設計的角度來看,ASP.NET MVC的Controller也只是一個類別。如果你發現自己在其他Controller寫了完全相同邏輯的程式碼(相同的成員、屬性或方法等),那麼我們有非常合理的理由來建立一個共用的基礎類別,之後將Controller裡相同的成員、屬性或方法往上層的基礎類別移動,Controller只需重新繼承此基礎類別,就能發揮物件導向的繼承的優勢。

BaseController

BaseController是繼承自Controller的類別,用於集中共用程式碼讓底下實作的Controller繼承使用。

BaseController - 資料庫物件初始化

以Northwind資料庫為例,使用基架多產生幾個Controller類別(ProductsController、OrdersController、OrderDetailsController…),分析這些所有Controller類別會發現有一個成員會不斷重覆出現在所有的Controller類別中:

 private NorthwindEntities db = new NorthwindEntities();
 
這裡不討論Repository模式或IoC的應用。

新增一個BaseController類別並繼承Controller抽象類別,然後將產生db執行個體的程式碼移至BaseController類別:

 public class BaseController : Controller
 {
     protected NorthwindEntities db = new NorthwindEntities();
 }  
 

注意,為了讓子類別可以存取,存取修飾詞不能是private。修改MVC Controller所繼承的類別(以ProductsController為例):

 public class ProductsController : BaseController
 {
  // 可刪除。註解是為讓讀者瞭解。
     // private NorthwindEntities db = new NorthwindEntities();
 }
 

BaseController - 指定Title

基架系統產生的View Page,每一頁面的title值是在View Page裡去指定,當要一一指定每一個頁面title值時非常不便(你要開啟每一個Action方法對應的View Page再一一修改)。

 @{
     ViewBag.Title = "Index";
 }  
 

我們希望直接在Action方法裡去指定title的值。把View Page裡的指定title的程式碼刪除,然後在BaseController裡新增一個Title屬性:

 public class BaseController : Controller
 {
     protected NorthwindEntities db = new NorthwindEntities();
     // 新增Title屬性
     protected string Title {
         set
         {
             ViewBag.Title = value;
         } 
     }
 }  
 

在繼承BaseController類別的MVC Controller類別中就能直接進行title的設置:

 public class ProductsController : BaseCont
 {
     public ActionResult Index()
     {
      // 指定Title屬性
         Title = "產品首頁";
         return View(db.Products.ToList());
     }
     // 省略
 }  
 
View Page - Title

如果你有些專屬於此系列MVC Controller的Action Filters,也能在BaseController裡去覆寫(Override)而繼承的MVC Controller會直接生效。

 public class BaseController : Controller
 {
     // 覆寫ActionFilters
     protected override void OnActionExecuting(ActionExecutingContext filterContext)
     {
         log("OnActionExecuting", filterContext.RouteData);
     }
     private void log(string method, RouteData routeData)
     {
         // Log程式碼
     }
 }  
 

Action Filters本身是一種AOP 設計,在BaseController類別裡覆寫Action Filters的方式並不是很好的方式。這裡要清楚類別繼承的應用情境與AOP的應用情境是不同的。

BaseApiController

在ASP.NET Web API 2裡的應用等同於Web Form與ASP.NET MVC的應用方式,新增BaseApiController並繼承ApiController,然後實作共用程式碼,並讓其他子ApiController繼承BaseApiController。

 public class BaseApiController : ApiController
 {
  // 共用程式碼
 }
 

不論是ASP.NET MVC或ASP.NET Web API 2本身是都大量OOP的實踐,而我們要去「承先啟後」都不會太難。另外,像一些如NLog日誌方法的初始化也適合由BaseController / BaseApicontroller來提供。

沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。