Asp.net MVC 示例项目"Suteki.Shop"分析之---Controller
2009-05-12 08:14
453 查看
在上文中,介绍了如何安装和使用Suteki,今天我们通过源码来看一下Suteki是如何使用
Controller。
在Suteki中,其使用Abstract的方式来定义一个ControllerBase,以此作为所有Controller
的基类,下面是其Controller的类设计图:
public class ScaffoldController<T> : Controller where T : class, new()
{
public IRepository<T> Repository { get; set; }
public IRepositoryResolver repositoryResolver { get; set; }
public IValidatingBinder ValidatingBinder { get; set; }
public IHttpContextService httpContextService { get; set; }
public virtual ActionResult Index(int? page)
{
return RenderIndexView(page);
}
protected virtual ActionResult RenderIndexView(int? page)
{
var items = Repository.GetAll().AsPagination(page ?? 1);
return View("Index", ScaffoldView.Data<T>().With(items));
}
public virtual ActionResult New()
{
var item = new T();
return View("Edit", BuildEditViewData().With(item));
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult New([DataBind(Fetch = false)] T item)
{
if(ModelState.IsValid)
{
Repository.InsertOnSubmit(item);
TempData["message"] = "Item successfully added.";
return RedirectToAction("Index");
}
return View("Edit", BuildEditViewData().With(item));
}
[NonAction]
public virtual ScaffoldViewData<T> BuildEditViewData()
{
var viewData = ScaffoldView.Data<T>();
AppendLookupLists(viewData);
return viewData;
}
public virtual ActionResult Edit(int id)
{
T item = Repository.GetById(id);
return View("Edit", BuildEditViewData().With(item));
}
[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Edit([DataBind] T item)
{
if(ModelState.IsValid)
{
TempData["message"] = "Item successfully updated.";
return RedirectToAction("Index");
}
return View("Edit", BuildEditViewData().With(item));
}
public virtual ActionResult Delete(int id, int? page)
{
T item = Repository.GetById(id);
Repository.DeleteOnSubmit(item);
//Repository.SubmitChanges();
return RedirectToAction("Index", new {page});
}
/// <summary>
/// Appends any lookup lists T might need for editing
/// </summary>
/// <param name="viewData"></param>
[NonAction]
public virtual void AppendLookupLists(ScaffoldViewData<T> viewData)
{
// find any properties that are attributed as a linq entity
foreach (var property in typeof(T).GetProperties())
{
if (property.PropertyType.IsLinqEntity())
{
AppendLookupList(viewData, property);
}
}
}
private void AppendLookupList(ScaffoldViewData<T> viewData, PropertyInfo property)
{
var repository = repositoryResolver.GetRepository(property.PropertyType);
// get the items
object items = repository.GetAll();
// add the items to the viewData
viewData.WithLookupList(property.PropertyType, items);
}
}
大家请注意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的用
法。
原文链接: /article/4598193.html
作者: daizhj,代震军,LaoD
Tags: mvc
网址: http://daizhj.cnblogs.com/
Controller。
在Suteki中,其使用Abstract的方式来定义一个ControllerBase,以此作为所有Controller
的基类,下面是其Controller的类设计图:
public class ScaffoldController<T> : Controller where T : class, new()
{
public IRepository<T> Repository { get; set; }
public IRepositoryResolver repositoryResolver { get; set; }
public IValidatingBinder ValidatingBinder { get; set; }
public IHttpContextService httpContextService { get; set; }
public virtual ActionResult Index(int? page)
{
return RenderIndexView(page);
}
protected virtual ActionResult RenderIndexView(int? page)
{
var items = Repository.GetAll().AsPagination(page ?? 1);
return View("Index", ScaffoldView.Data<T>().With(items));
}
public virtual ActionResult New()
{
var item = new T();
return View("Edit", BuildEditViewData().With(item));
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult New([DataBind(Fetch = false)] T item)
{
if(ModelState.IsValid)
{
Repository.InsertOnSubmit(item);
TempData["message"] = "Item successfully added.";
return RedirectToAction("Index");
}
return View("Edit", BuildEditViewData().With(item));
}
[NonAction]
public virtual ScaffoldViewData<T> BuildEditViewData()
{
var viewData = ScaffoldView.Data<T>();
AppendLookupLists(viewData);
return viewData;
}
public virtual ActionResult Edit(int id)
{
T item = Repository.GetById(id);
return View("Edit", BuildEditViewData().With(item));
}
[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Edit([DataBind] T item)
{
if(ModelState.IsValid)
{
TempData["message"] = "Item successfully updated.";
return RedirectToAction("Index");
}
return View("Edit", BuildEditViewData().With(item));
}
public virtual ActionResult Delete(int id, int? page)
{
T item = Repository.GetById(id);
Repository.DeleteOnSubmit(item);
//Repository.SubmitChanges();
return RedirectToAction("Index", new {page});
}
/// <summary>
/// Appends any lookup lists T might need for editing
/// </summary>
/// <param name="viewData"></param>
[NonAction]
public virtual void AppendLookupLists(ScaffoldViewData<T> viewData)
{
// find any properties that are attributed as a linq entity
foreach (var property in typeof(T).GetProperties())
{
if (property.PropertyType.IsLinqEntity())
{
AppendLookupList(viewData, property);
}
}
}
private void AppendLookupList(ScaffoldViewData<T> viewData, PropertyInfo property)
{
var repository = repositoryResolver.GetRepository(property.PropertyType);
// get the items
object items = repository.GetAll();
// add the items to the viewData
viewData.WithLookupList(property.PropertyType, items);
}
}
大家请注意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的用
法。
原文链接: /article/4598193.html
作者: daizhj,代震军,LaoD
Tags: mvc
网址: http://daizhj.cnblogs.com/
相关文章推荐
- Asp.net MVC 示例项目"Suteki.Shop"分析之---Controller
- Asp.net MVC 示例项目"Suteki.Shop"分析之---Controller
- Asp.net MVC 示例项目"Suteki.Shop"分析之---Controller
- Asp.net MVC 示例项目"Suteki.Shop"分析之---结束篇
- Asp.net MVC 示例项目"Suteki.Shop"分析之---Filter
- Asp.net MVC 示例项目"Suteki.Shop"分析之---ViewData
- Asp.net MVC 示例项目"Suteki.Shop"分析之---Model和Service
- Asp.net MVC 示例项目"Suteki.Shop"分析之---安装篇
- Asp.net MVC 示例项目"Suteki.Shop"分析之---NHibernate
- Asp.net MVC 示例项目"Suteki.Shop"分析之---Filter
- Asp.net MVC 示例项目"Suteki.Shop"分析之---数据验证
- Asp.net MVC 示例项目"Suteki.Shop"分析之---数据验证
- Asp.net MVC 示例项目"Suteki.Shop"分析之---ViewData
- Asp.net MVC 示例项目"Suteki.Shop"分析之---NVelocity模版引擎 推荐
- Asp.net MVC 示例项目"Suteki.Shop"分析之---安装篇
- Asp.net MVC 示例项目"Suteki.Shop"分析之---NHibernate
- Asp.net MVC 示例项目"Suteki.Shop"分析之---Filter 推荐
- Asp.net MVC 示例项目"Suteki.Shop"分析之---ModelBinder
- Asp.net MVC 示例项目"Suteki.Shop"分析之---IOC(控制反转)
- Asp.net MVC 示例项目"Suteki.Shop"分析之---NVelocity模版引擎