我花了一些时间研究在ASP.Net MVC网站上实现验证的策略。冒着过度工程的风险,我正在尝试开发一个松散的实现,可以为我的任何项目一致地推出。考虑到所有活动部分,我想我会问SO的人们是否有任何改进的意见或想法。代码显然是做作的,我只是想了解一切如何挂在一起。
感兴趣的活动部分:
鉴于我想在单个Controller操作期间使用相同的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);
}
继续使用一些更人为的代码,让我们说在我的创建操作中,我想创建一个产品订单,并从库存中删除该产品:
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方法时进行业务规则验证。这些服务使用相同的Unit of Work对象,该对象包含对存储库的引用,因此所有服务CRUD方法都在同一个EF上下文中执行,这为我提供了诸如事务和并发之类的好东西。
在我的控制器中,我在Create操作中调用多个服务。是否最好只调用OrderService,然后调用InventoryService本身?
有没有办法通过Unity将工作单元对象附加到服务中,因为我需要为每个服务使用相同的UoA对象?我无法想到一种方法,它不会以每个服务的不同实例结束。
如果有人有任何想法或建议,我很乐意听到他们!
谢谢!
克里斯
答案 0 :(得分:0)
在我的控制器中,我在Create操作中调用多个服务。相反,最好是拨打一个电话 OrderService,然后调用InventoryService本身?
是。最好将业务事务封装在服务方法中。这将使以后更容易重用其他地方的逻辑。
有没有办法通过Unity将工作单元对象附加到服务中,因为我需要为每个服务使用相同的UoA对象?
使用Unity的生命周期管理器,每个请求使用一个上下文,例如PerHttpRequestLifetime让Unity将上下文/ UoW注入到服务中,而不是在控制器的构造函数中手动设置它。