Asp.net MVC 示例项目"Suteki.Shop"分析之---Controller

简介:
在Suteki中,其使用Abstract的方式来定义一个ControllerBase,以此作为所有Controller的基类,下面是其Controller的类设计图:
    
    
        在该基类中定义了一些Controller中常用到的方法,比如为当前视图添加MetaDescription,Title等:  
 
[Rescue( " Default " ), Authenticate, CopyMessageFromTempDataToViewData]
public   abstract   class  ControllerBase : Controller, IProvidesBaseService
{
        
private  IBaseControllerService baseControllerService;

        
///   <summary>
        
///  Supplies services and configuration to all controllers
        
///   </summary>
         public  IBaseControllerService BaseControllerService
        {
            
get  {  return  baseControllerService; }
            
set  
            { 
                baseControllerService 
=  value;

                ViewData[
" Title " =   " {0}{1} " .With(
                    baseControllerService.ShopName,
                    GetControllerName());

                ViewData[
" MetaDescription " =   " \ " { 0 }\ "" .With(baseControllerService.MetaDescription);
            }
        }

        
public  ILogger Logger {  get set ; }

        
public   virtual   string  GetControllerName()
        {
            
return   "  - {0} " .With(GetType().Name.Replace( " Controller " "" ));
        }


        
public   virtual   void  AppendTitle( string  text)
        {
            ViewData[
" Title " =   " {0} - {1} " .With(ViewData[ " Title " ], text);
        }

        
public   virtual   void  AppendMetaDescription( string  text)
        {
            ViewData[
" MetaDescription " =  text;
        }

     
public   string  Message
     {
   
get  {  return  TempData[ " message " as   string ; }
   
set  { TempData[ " message " =  value; }
     }

  
protected   override   void  OnException(ExceptionContext filterContext) {
   Response.Clear();
   
base .OnException(filterContext);
  }
}
    
        当然,细心的朋友发现了该抽象类中还包括一个IBaseControllerService接口实例。该接口的主要定义了一些网店系统信息,如店铺名称,版权信息,Email信息等,如下:
 
public   interface  IBaseControllerService
{
    IRepository
< Category >  CategoryRepository {  get ; }
    
string  GoogleTrackingCode {  get set ; }
    
string  ShopName {  get set ; }
    
string  EmailAddress {  get set ; }
    
string  SiteUrl {  get ; }
    
string  MetaDescription {  get set ; }
    
string  Copyright {  get set ; }
    
string  PhoneNumber {  get set ; }
    
string  SiteCss {  get set ; }
}
   
        而作为唯一一个实现了该接口的子类“ BaseControllerService”定义如下:  
 
public   class  BaseControllerService : IBaseControllerService
{
        
public  IRepository < Category >  CategoryRepository {  get private   set ; }
        
public   string  GoogleTrackingCode {  get set ; }
        
public   string  MetaDescription {  get set ; }
        
private   string  shopName;
        
private   string  emailAddress;
        
private   string  copyright;
        
private   string  phoneNumber;
        
private   string  siteCss;

        ..
}
    
        而初始化BaseControllerService实例并将配置文件中的信息绑定到该类实例中的操作交给了Windsor,该组件在Castle中用于实现IOC操作,其配置文件位于项目Suteki.Shop\Configuration\Windsor.config.下面是其配置结点内容:
 
< component
  id
= " IBaseControllerService:test.jumpthegun.co.uk "
  service
= " Suteki.Shop.Services.IBaseControllerService, Suteki.Shop "
  type
= " Suteki.Shop.Services.BaseControllerService, Suteki.Shop "
  lifestyle
= " transient " >
  
< parameters >
    
< ShopName > Suteki Shop </ ShopName >
    
< EmailAddress > info@sutekishop.co.uk </ EmailAddress >
    
< GoogleTrackingCode > UA - 1643677 - 4 </ GoogleTrackingCode >
    
< MetaDescription > Suteki Shop  is  a  new  self service eCommerce solution. Search engine optimised and fully customisable </ MetaDescription >
    
< SiteCss > Site.css </ SiteCss >
  
</ parameters >
</ component >
    
       这类就完成了把网店的系统信息绑定到Controller中的操作,而Controller就会在其基类中将相关的信息绑定到ViewData中,如下: 
 
 ViewData[ " Title " =   " {0}{1} " .With(baseControllerService.ShopName, GetControllerName());
 ViewData[
" MetaDescription " =   " \ " { 0 }\ "" .With(baseControllerService.MetaDescription);

 
       到这里,其实大家应该发现这种对Controller的处理与我们以前所使用的PageBase方式相似,就是将项目中所有的Page都继承自PageBase,然后在相应的Page中引用PageBase中定义的属性和方法。

        有了ControllerBase,我们看一下在相应的子Controller中是如何使用的,这里有一个例子,ProductController(位于Suteki.Shop\Controllers\ProductController.cs): 
    
public   class  ProductController : ControllerBase
{
    
    
 
public  ActionResult Item( string  urlName)
 {
  
return  RenderItemView(urlName);
 }
    ..
    
 ActionResult RenderItemView(
string  urlName)
 {
  var product 
=  productRepository.GetAll().WithUrlName(urlName);
  AppendTitle(product.Name);
  AppendMetaDescription(product.Description);
  
return  View( " Item " , ShopView.Data.WithProduct(product));
 } 
 
}
 
         该Controller中的Action:"Item"调用了RenderItemView()就是使用了基类中的AppendTitle,AppendMetaDescription。 下面是其运行时的截图:
    
        

         
    
         除了上面所说的这种 ControllerBase方式,Suteki.Shop还使用了 Controller<T>方式来实现对一些公用Action的操作,比如列表,编辑,添加记录,调整记录上下位置等。而这块实现代码被放置在了 Suteki.Common\ScaffoldController.cs和OrderableScaffoldController.cs文件中,其中 ScaffoldController为父类,其中包括列表,编辑,添加Action等。
 
ContractedBlock.gif Code
   
        大家请注意ScaffoldController类中的几个公共属性:   
     public  IRepository < T >  Repository {  get set ; }
    
public  IRepositoryResolver repositoryResolver {  get set ; }
    
public  IValidatingBinder ValidatingBinder {  get set ; }
    
public  IHttpContextService httpContextService {  get set ; }
   
         其中Repository是一些对数据CRUD的操作对象,下面是Repository中的一些接口成员方法:
 
public   interface  IRepository < T >   where  T :  class
{
    T GetById(
int  id);
    IQueryable
< T >  GetAll();
    
void  InsertOnSubmit(T entity);
    
void  DeleteOnSubmit(T entity);
    [Obsolete(
" Units of Work should be managed externally to the Repository. " )]
    
void  SubmitChanges();
}
 
         这样就可以在ScaffoldController使用统一的接口函数调用相应子类中的实现方法了。   
         而ScaffoldController的子类OrderableScaffoldController则实现了对数据集合中的某行元素上下移动的操作:
    
public   class  OrderableScaffoldController < T >  : ScaffoldController < T >   where  T :  class , IOrderable,  new ()
{
    
public  IOrderableService < T >  OrderableService {  get set ; }

    
protected   override  ActionResult RenderIndexView( int ?  page)
    {
        var items 
=  Repository.GetAll().InOrder().AsPagination(page  ??   1 );
        
return  View( " Index " , ScaffoldView.Data < T > ().With(items));
    }

    
public   override  ActionResult New()
    {
        T item 
=   new  T
        {
            Position 
=  OrderableService.NextPosition
        };
        
return  View( " Edit " , ( object )BuildEditViewData().With(item));
    }

   [UnitOfWork]
    
public   virtual  ActionResult MoveUp( int  id,  int ?  page)
    {
        OrderableService.MoveItemAtPosition(id).UpOne();
  
return  RedirectToAction( " Index " );
    }
    [UnitOfWork]
    
public   virtual  ActionResult MoveDown( int  id,  int ?  page)
    {
        OrderableService.MoveItemAtPosition(id).DownOne();
  
return  RedirectToAction( " Index " );
    }
}

   
         注:IOrderableService的实现相对复杂一些,具体内容详见 Suteki.Common\Services\OrderableService.cs.
     
     按说有了这些功能之后,只要在相应的子类中直接继承使用就可以了,但在Suteki.Shop项目中作者又对 OrderableScaffoldController进行了一个“继承式”扩展,提供了与前面所说的那个“ControllerBase"相似的方法定义,如下:
 
[Authenticate, CopyMessageFromTempDataToViewData]
public   abstract   class  ShopScaffoldController < T >  : OrderableScaffoldController < T > , IProvidesBaseService  where  T :  class , IOrderable,  new ()
{
    
private  IBaseControllerService baseControllerService;

    
///   <summary>
    
///  Supplies services and configuration to all controllers
    
///   </summary>
     public  IBaseControllerService BaseControllerService
    {
        
get  {  return  baseControllerService; }
        
set
        {
            baseControllerService 
=  value;
            ViewData[
" Title " =   " {0}{1} " .With(
                baseControllerService.ShopName,
                GetControllerName());
        }
    }

    
public   virtual   string  GetControllerName()
    {
        
return   "  - {0} " .With(GetType().Name.Replace( " Controller " "" ));
    }
}
   
        而ShopScaffoldController这个抽象类有三个子类,如下图:
  
    

         因为这三个Controller的功能需求相似,而相应的Action实现也在基类“ScaffoldController”中实现,所以相应的类代码基本上就没有什么了。只不过在这几个子类中都被绑定了UnitOfWork过滤器( UnitOfWorkFilter),其代码如下 Suteki.Common\Filters\UnitOfWorkAttribute.cs
 
public   class  UnitOfWorkAttribute : FilterUsingAttribute
{
 
public  UnitOfWorkAttribute() :  base ( typeof  (UnitOfWorkFilter))
 { }
}

public   class  UnitOfWorkFilter : IActionFilter
{
 
private   readonly  IDataContextProvider provider;

 
public  UnitOfWorkFilter(IDataContextProvider provider)
 {
  
this .provider  =  provider;
 }

 
public   void  OnActionExecuting(ActionExecutingContext filterContext)
 {}

 
public   void  OnActionExecuted(ActionExecutedContext filterContext)
 {
  var context 
=  provider.DataContext;

  
if  (filterContext.Controller.ViewData.ModelState.IsValid)
  {
   context.SubmitChanges();
  }
 }
}
    
         其核心功能就是在对用户提交的数据进行有效验证后调用DataContext的SubmitChanges()方法(注:该逻辑被放在了OnActionExecuted方法中实现)来保存修改,这种做法在以往的MVC示例子没有看到过,呵呵,不过这种做法还有待研究。
        好了,今天的内容就先到这里了,在下一篇中,将来讨论一下该项目中对MVC框架中Filter的用法。

   本文转自 daizhenjun 51CTO博客,原文链接:http://blog.51cto.com/daizhj/157157,如需转载请自行联系原作者
相关文章
|
3天前
|
安全 数据安全/隐私保护 开发者
三款.NET 代码混淆工具比较分析:ConfuserEx、Obfuscar 和 Ipa Guard
三款.NET 代码混淆工具比较分析:ConfuserEx、Obfuscar 和 Ipa Guard
|
7月前
|
前端开发 Java 数据库
MVC项目导入
MVC项目导入
26 0
|
7月前
|
存储 开发框架 前端开发
asp.net与asp.net优缺点及示例
asp.net与asp.net优缺点及示例
|
3天前
|
前端开发 安全 Java
SpringMVC基础篇:第一个MVC程序和细节分析
SpringMVC基础篇:第一个MVC程序和细节分析
|
3天前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
48 0
|
3天前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
23 0
|
3天前
|
存储 测试技术 计算机视觉
高维数据惩罚回归方法:主成分回归PCR、岭回归、lasso、弹性网络elastic net分析基因数据
高维数据惩罚回归方法:主成分回归PCR、岭回归、lasso、弹性网络elastic net分析基因数据
|
3天前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
32 0
|
3天前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
122 5
|
3天前
|
SQL 开发框架 .NET
ASP.NET Web——GridView完整增删改查示例(全篇幅包含sql脚本)大二结业考试必备技能
ASP.NET Web——GridView完整增删改查示例(全篇幅包含sql脚本)大二结业考试必备技能
38 0