我几乎在每一个行动中都有类似的东西:
public ActionResult Show(int object_id)
{
Object obj = ObjectRepository.ById(object_id);
if (obj == null)
{
throw new HttpException(404);
}
if (obj.SomeCheck)
{
throw new HttpException(403);
}
// processing
}
问题是如何将对象移动(以及抛出http异常)远离操作,并且具有以下内容:
public ActionResult Show(Object obj)
{
// processing
}
UPD:无法更改ObjectRepository和模型本身,它不仅用于ASP.NET,还用于项目的其他部分。
答案 0 :(得分:5)
一种选择是将样板重构为私有方法:
private object GetItem(object obj) {
Object obj = ObjectRepository.ById(object_id);
if (obj == null) {
throw new HttpException(404);
}
if (obj.SomeCheck()) {
throw new HttpException(403);
}
return obj;
}
然后:
public ActionResult Show(int object_id) {
object obj = GetItem(object_id);
// processing
}
答案 1 :(得分:4)
正如其他人所建议你可以编写过滤器或调用像PostSharp这样的AOP框架。
然而,对某些人来说,这可能是一个很高的要求。您可能需要考虑编写一些简单,可维护且可读的内容,团队中的每个人都可以立即理解:
public ActionResult Show(int object_id)
{
SomeClass obj = Require<SomeClass>(object_id, assumption: o => o.SomeCheck);
// processing
}
//Perhaps: put this in a base controller or other common class
private object Require<T>(int id, Func<object, bool> assumption) where T : class
{
var o = ObjectRepository.ById(object_id) as T;
//Result is required
if (o == null) {
throw new HttpException(404);
}
//Verify assumption
if (!assumption(o)) {
throw new HttpException(403);
}
return o;
}
答案 2 :(得分:2)
您可以查看
编写自定义过滤器属性,例如AuthorizationAttribute
或ValidateInputAttribute
。它们可以应用于整个控制器或指定方法(操作)。有关概述,请参阅http://msdn.microsoft.com/en-us/magazine/dd695917.aspx#id0070026。
您可能希望使用PostSharp(面向方面的编程框架)为您的方法注入合适的方面。
答案 3 :(得分:1)
其他人提供了一些很好的答案。其中,我喜欢使用动作过滤器的想法,但不幸的是我不相信它会很好地工作,因为你将被迫使用属性注入(或显式实例化 - yuck!)来存储库,我宁愿避免。出于这个原因,我认为专用的控制器方法是更好的选择。
但是,我会在帽子里再提出一个想法。您提到您无法更改ObjectRepository
,但您可以随时摘取它:
public class HttpObjectService /*: IObjectService */
{
private readonly /*I*/ObjectRepository _repository;
public HttpObjectService(/*I*/ObjectRepository repository)
{
if (repository == null) throw new ArgumentNullException("repository");
_repository = repository;
}
public Object ById(int id)
{
var obj = _repository.ById(id);
/* Check and throw HttpExceptions */
}
}
然后将其注入您的控制器。你是否喜欢“特定于网络”的想法。直接抛出HttpExceptions
的服务是一个品味问题,但它是非常可重复使用的,在这种情况下,我认为它比控制器中的私有验证方法提供了更清晰的关注点分离。
当然,缺点是您允许控制器将其响应(如果发生错误)直接委托给第三方。您可能希望您的控制器对此有绝对的控制权 - 这将是一个合理的批评。在这种情况下,您始终可以将ObjectValidator
对象从控制器传递到构造函数中,该控制器负责验证。这样,无论服务实现如何,您的控制器都可以控制抛出的异常。
您必须考虑到这适合您的项目架构 - 它可能属于MVC项目的单独程序集,但是专用于基于Web的UI。