2

我得到了一个带有控制器和服务的API,当调用控制器中的一个动作时,我必须应用一个验证,此验证需要检查数据库中的数据以验证它是否正确。在webapi中的异常处理MVC.net

据我所看到的也有叫“更新”,以防止错误

public IActionResult UpdateCustomer(CustomerDto customer) 
{ 
    if (!customerService.Validate(customer)) 
    { 
     return Send400BadRequest(); 
    } 
    customerService.Update(customer); 

    return Send200Ok(); 
} 

2-呼叫内更新验证和罚球前处理这个

1-验证两种方法例外。

public IActionResult UpdateCustomer(CustomerDto customer) 
{ 
    customerService.Update(customer);  
    return Send200Ok(); 
} 

在客户服务

public void Update(CustomerDto customer) 
    { 
    if (!Validate(customer) 
     throws new CustomValidationException("Customer is not valid"); 
    //Apply update 
    } 

我们已经有一个ActionFilter处理CustomValidationException所以它会返回一个错误请求。

1) 优点 +不要使用例外为使用运行流动

缺点 -Controller是更多的脂肪,对每一种情况下,将决定哪个是输出

2多个决策) 优点 +操作更原子化,所有逻辑都在服务内部。 +更容易测试 +该方法的每次使用都将被验证。

缺点 - 使用异常来管理流程。

哪一个更好的解决方案?

我确实需要论据来捍卫其中的一个。

+1

我不会考虑2个额外的代码行膨胀控制器IMO。 –

+0

对我来说不是那么臃肿与否,但更多的是决定不应该在控制器中 – Balder

+1

@Balder,使用另一个动作过滤器在进行动作之前进行验证。贯穿始终的关切和单一责任原则。 – Nkosi

回答

0

我宁愿2 :)

因为我觉得服务可以从另一个节点不仅asp.net控制器如果所有的验证逻辑是一样的服务单层处理,被称为所以这将是对我好层。

0

我认为通过使用httpresponse消息来处理异常比其他任何人都好得多。至少你得到了正确的错误响应,输出正确的http响应消息。

 public HttpResponseMessage TestException() 
     { 
     try 
     { 
      //if your code works well 
      return Request.CreateResponse(HttpStatusCode.OK); 
     } 
     catch (Exception ex) 
     { 

      return Request.CreateErrorResponse(HttpStatusCode.ExpectationFailed, ex.ToString()); 
     } 
     } 
0

我会做这种方式:

public IActionResult UpdateCustomer(CustomerDto customer) 
    { 
    try 
     { 
     consumerService.Update (customer); 
     } 
    catch (CustomValidationException) 
     { 
     return Send400BadRequest(); 
     } 

    return Send200Ok(); 
    } 

而在你的CustomerService:

public void Update(CustomerDto customer)  
     { 
     if (!Validate(customer)) 
      throw new CustomValidationException("Customer is not valid"); 
     } 

这样,你的服务有验证逻辑。因此,任何其他您的服务的调用者在尝试更新之前也将验证其输入,因此会得到适当的错误消息。 您的控制器将不会有任何验证码。此外,拥有try-catch块意味着你可以优雅地处理更新调用可能抛出的任何其他错误。希望有所帮助。

1

我反对在这里的其他意见,并说第一种方法都清楚地说明了你的方法的意图是什么,如果你决定不返回400错误,它有点容易把它拉下来场景#1。

此外,对异常的一些想法。异常应该是例外,这意味着代码中出现意外事件。没有通过验证检查的公司不是异常事件,它可以通过或不通过。将用户对象传入ValidateCompany()方法应该会引发异常。

Here是异常抛出类似主题上的一个很好的答案。它使用一个简单的示例问题来确定何时应该引发异常。

关于“更容易测试” - 我看不出如何。您的控制器将进行两项测试,包括您选择的任何选项,有效的公司和无效的公司。您的服务将通过您选择的任何选项,有效的公司和无效的公司进行两项测试(显然简化了您的服务层)。在任何情况下,您都希望确保您的控制器操作和您的服务层可以处理无效且有效的公司对象。

0

接收一个客户可验证模型,通过该模型的数据服务层,并且在所述控制器执行异常处理 如果数据服务层失败。

客户模式

实施IValidatableObject捕获业务逻辑相关的错误。

public class CustomerModel : IValidatableObject 
{ 
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     // example validation 
     if (Balance < 100) 
      yield return new ValidationResult("Balance >= 100 req.", new [] { nameof(Balance) }); 
    } 
    public string Name { get; set; } 
    public double Balance { get; set; } 
} 

API控制器

在面向公众的UpdateCustomer API方法接收一个CustomerModel,然后引用ModelState,以确定客户是否有效。

public IActionResult UpdateCustomer(CustomerModel customer) 
{ 
    if(ModelState.IsValid) // model validation succeeded 
    { 
     try 
     { 
      customerService.Update(customer); 
     } 
     catch (ServiceUpdateException svcEx) 
     { 
      // handled failure at the service layer 
      return Conflict(); 
     } 
     catch (Exception ex) 
     { 
      // unhandled error occured 
      return InternalServerError(ex); 
     } 
     // update succeeded 
     return Ok(); 
    } 
    // invalid model state 
    return BadRequest(); 
} 

服务(数据层)

public void Update(Customer customer) 
{ 
    //Apply update 
    try 
    { 
     database.Update(customer); 
    } 
    catch (DataStorageException dbEx) 
    { 
     throw new ServiceUpdateException(dbEx); 
    } 
    catch 
    { 
     throw;//unknown exception 
    } 
} 
3

如果你有业务逻辑层服务层,我希望保留所有业务逻辑规则包括业务逻辑验证 in 业务逻辑层并使用服务层作为包装业务逻辑层Exception业务方法。

在决定是否使用异常的业务验证规则或没有,你可以考虑:

1)它的更好,你的业务方法的工作单元。他们应该完成一项完整的任务。所以它们最好包含验证规则。这样,您就可以重新使用这种业务逻辑层在不同服务层或使用工作相同单位在同一服务层的不同方法。如果您在业务逻辑层中引入业务验证例外,您将不会面临遗漏验证或错误地使用其他验证规则的风险,并且每个服务方法/操作都将为您执行单个任务,并且将尽可能轻量级。

想想,当你可能需要公开WCF服务的一些客户,或者例如,如果你可以使用ASP.NET MVC,而无需使用的WebAPI或当且仅当您要使用相同的逻辑在其他行动方法相同的WebAPI。

如果你把业务逻辑的Web API控制器验证,创建WCF服务方法或创建MVC操作或其他服务的方法时,你可能会忘记申请验证,也可以适用不同的规则错误验证新服务层

2)考虑到第一个好处,您是否可以从显示成功,失败或在输出中包含有关失败原因的合适信息的方法返回有意义的值?

我相信这是不适合所有这些目标的方法。方法输出是方法输出,它应该是这种业务应用程序中的数据。它不应该有时是一种地位,有时候是数据或有时是消息。抛出异常将解决这个问题。

+0

你的回答非常好,它的完整性,我给你的赏金,但我的问题是更概念。其实我相信最好是从业务逻辑层中抛出异常,但我需要争论来辩论这个问题,这是我的问题的目标,因为我收到了关于我的同事的想法,比如“抛出异常导致糟糕的性能”或“抛出处理逻辑异常是一种代码异味“,为什么我真的需要参数来讨论这是最佳解决方案 – Balder

+0

感谢您的反馈,我试图描述为什么在业务逻辑层中抛出异常更好。它不控制应用程序的流程。它使业务逻辑更加可重用,更可靠。它保证每个工作单位,始终以相同的方式工作。但是,如果您将业务验证置于某个操作方法中,则可能会忘记在使用相同业务逻辑的另一个操作方法中应用相同的业务验证。或者显然如果你使用另一个服务层,你应该再次在新的服务层调用相同的业务验证。 –

0

我认为你应该在验证控制器和服务,但验证稍有不同的东西。特别是如果什么开始只是一个API变成一个API,与MVC网站和WPF管理界面经常发生。

使用Validation Attributes和模型绑定为数据提供了一次快速的“一次性”检查。他们是否提供客户更新的ID?他们是否为相关实体提交了外键值?价格在0到1,000,000之间?如果你有一个网站,那么你也可以开箱即可获得客户端验证。至关重要的是,根本不需要连接到数据库,因为数据显然是错误的。

服务中的验证也是必需的,因为您最终可能会有3或4个应用程序调用此服务,并且您希望编写一次业务逻辑。一些验证,例如。引用外键只能在数据库中完成,但抛出异常没有任何问题。你的API的消费者应该有权访问有效值的范围,网站的用户应该从下拉等选择,所以这种情况应该是例外