1

我花了一些时间研究在我的 ASP.Net MVC 站点中实施验证的策略。冒着过度设计的风险,我正在尝试开发一个松散的实现,可以为我的任何项目一致地推出。鉴于所有活动部件,我想我会问 SO 的人,看看他们是否有任何改进意见或想法。代码显然是人为的,我只是想说明一切是如何联系在一起的。

感兴趣的运动部分:

  • 用于数据访问的 EF 存储库层
  • 用于输入验证的模型数据注释
  • 业务规则验证的服务层
  • DI的统一

鉴于我想在单个控制器操作期间使用相同的 EF 上下文,我使用工作单元模式将相同的 DataContect 注入控制器内的多个服务中:

public class OrderController : Controller
{
    private IUnitOfWork _unitOfWork;
    private IOrderService _recipeService;
    private IInventoryService _inventoryService;

    public OrderController(IUnitOfWork unitOfWork, IOrderService orderService, IInventoryService inventoryService)
    {
        _unitOfWork = unitOfWork;
        _orderService = orderService;
        _inventoryService = inventoryService
        //Use property injection to apply the Unit of Work context and validation state to our services
        _orderService.Context = _unitOfWork;
        _orderService.ValidationState = new ModelStateWrapper(this.ModelState);
        _inventoryService.Context = _unitOfWork;
        _inventoryService.ValidationState = new ModelStateWrapper(this.ModelState);
    }

继续使用一些人为的代码,假设在我的 Create 操作中,我想为产品创建一个订单,并从库存中删除该产品:

public ActionResult Create(CreateEditOrderViewModel model)
    {
        try
        {

            Product product = Mapper.Map<ProductDTO, Product>(model.ProductDTO);

            if(_orderService.Insert(product) && 
               _inventoryService.Remove(product) &&
                ModelState.IsValid)
            {   
                _unitOfWork.Save();
                return RedirectToAction("Index");
            }
        }
        catch (DataException exc)
        {
            //Log the error (add a variable name after DataException)
            ModelState.AddModelError("", "Unable to save changes, please check the log for errors.");
        }
        return View(model);
    }

在我的服务中,我根据http://www.asp.net/mvc/tutorials/older-versions/models-(data)/validating-with-a-service-layer-cs进行一些业务规则验证:

public class OrderService : IOrderService
{

    public bool Insert(Recipe orderToCreate)
    {
        // Validation logic
        if (!ValidateOrder(orderToCreate))
            return false;

        // Database logic
        try
        {
            _context.OrderRepository.Insert(orderToCreate);
        }
        catch
        {
            return false;
        }
        return true;
    }

    protected bool ValidateOrder(Order orderToValidate)
    {
        Product p = orderToValidate.Product;
        //Ensure inventory has product before creating order
        if (_context.InventoryRepository.HasProduct(p)
            _validationState.AddError("Product", "That product cannot be added to the order as we don't have it in stock");

        return _validationState.IsValid;
    }


    public IUnitOfWork Context
    {
        get
        {
            return _context;
        }
        set
        {
            _context = value;
        }
    }

    public IValidationDictionary ValidationState
    {
        get
        {
            return _validationState;
        }
        set
        {
            _validationState = value;
        }
    }
}

一个简单的订单模型如下所示:

public class Order: IModel
{
    [Key]
    public int ID { get; set; }
    [Required(ErrorMessage="A buyer is required.")]
    public string Buyer { get; set; }
    public virtual ICollection<Product> Products{ get; set; }
}

因此,就目前而言,数据注释的验证发生在模型绑定期间,而业务规则验证发生在调用服务的 CRUD 方法时。这些服务使用包含对存储库的引用的相同工作单元对象,因此所有服务 CRUD 方法都在相同的 EF 上下文中执行,这为我提供了事务和并发等好处。

在我的控制器中,我在我的 Create 操作中调用多个服务。是否最好改为对 OrderService 进行一次调用,然后再调用 InventoryService 本身?

鉴于我需要为每个服务提供相同的 UoA 对象,有没有办法通过 Unity 将工作单元对象附加到服务中?我想不出一种方法,它不会最终为每个服务提供不同的实例。

如果有人有任何想法或建议,我很想听听他们的意见!

谢谢!

克里斯

4

1 回答 1

0

在我的控制器中,我在我的 Create 操作中调用多个服务。是否最好改为对 OrderService 进行一次调用,然后再调用 InventoryService 本身?

是的。最好将业务事务封装在服务方法中。这将使以后更容易重用其他地方的逻辑。

鉴于我需要为每个服务提供相同的 UoA 对象,有没有办法通过 Unity 将工作单元对象附加到服务中?

使用 Unity 的生命周期管理器,每个请求使用一个上下文,例如PerHttpRequestLifetime并让 Unity 将上下文/UoW 注入到服务中,而不是在控制器的构造函数中手动设置它。

于 2012-11-11T14:16:19.987 回答