从ASP.NET MVC操作中删除样板

时间:2014-05-28 17:36:50

标签: c# asp.net asp.net-mvc

我几乎在每一个行动中都有类似的东西:

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,还用于项目的其他部分。

4 个答案:

答案 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)

您可以查看

答案 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。