我想在每次保存域对象时强制执行一些规则,但我不知道实现此目的的最佳方法。正如我所看到的,我有两个选择:向域对象添加save方法,或者在保存到应用程序层之前处理规则。请参阅下面的代码示例:
using System;
namespace Test
{
public interface IEmployeeDAL
{
void Save(Employee employee);
Employee GetById(int id);
}
public class EmployeeDALStub : IEmployeeDAL
{
public void Save(Employee employee)
{
}
public Employee GetById(int id)
{
return new Employee();
}
}
public interface IPermissionChecker
{
bool IsAllowedToSave(string user);
}
public class PermissionCheckerStub : IPermissionChecker
{
public bool IsAllowedToSave(string user)
{
return false;
}
}
public class Employee
{
public virtual IEmployeeDAL EmployeeDAL { get; set; }
public virtual IPermissionChecker PermissionChecker { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public void Save()
{
if (PermissionChecker.IsAllowedToSave("the user")) // Should this be called within EmployeeDAL?
EmployeeDAL.Save(this);
else
throw new Exception("User not permitted to save.");
}
}
public class ApplicationLayerOption1
{
public virtual IEmployeeDAL EmployeeDAL { get; set; }
public virtual IPermissionChecker PermissionChecker { get; set; }
public ApplicationLayerOption1()
{
//set dependencies
EmployeeDAL = new EmployeeDALStub();
PermissionChecker = new PermissionCheckerStub();
}
public void UnitOfWork()
{
Employee employee = EmployeeDAL.GetById(1);
//set employee dependencies (it doesn't seem correct to set these in the DAL);
employee.EmployeeDAL = EmployeeDAL;
employee.PermissionChecker = PermissionChecker;
//do something with the employee object
//.....
employee.Save();
}
}
public class ApplicationLayerOption2
{
public virtual IEmployeeDAL EmployeeDAL { get; set; }
public virtual IPermissionChecker PermissionChecker { get; set; }
public ApplicationLayerOption2()
{
//set dependencies
EmployeeDAL = new EmployeeDALStub();
PermissionChecker = new PermissionCheckerStub();
}
public void UnitOfWork()
{
Employee employee = EmployeeDAL.GetById(1);
//do something with the employee object
//.....
SaveEmployee(employee);
}
public void SaveEmployee(Employee employee)
{
if (PermissionChecker.IsAllowedToSave("the user")) // Should this be called within EmployeeDAL?
EmployeeDAL.Save(employee);
else
throw new Exception("User not permitted to save.");
}
}
}
在这种情况下你做了什么?
答案 0 :(得分:0)
我更倾向于第二种方法,即关注点之间存在明显的分离。有一个负责DAL的类,还有一个负责验证,另一个负责编排这些。
在您的第一种方法中,您将DAL和验证注入业务实体。如果我认为向实体注入验证器可能是一个好的做法,那么将DAL注入商业实体绝对不是一个好的实践恕我直言(但我知道这只是一个示范,并且在一个真实的项目中,你会在至少使用服务定位器)。
答案 1 :(得分:0)
如果我必须选择,我会选择第二个选项,以便我的实体不与任何DAL基础设施相关联,并且完全专注于域逻辑。
但是,我真的不喜欢这两种方法。我更喜欢采用更多AOP方法来实现安全性和安全性。通过向我的应用程序服务方法添加属性来实现角色。
我要改变的另一件事就是摆脱'CRUD'的思维模式。如果您能够针对特定命令/用例进行保护,则可以提供更精细的安全选项。例如,我做到了:
public class MyApplicationService
{
[RequiredCommand(EmployeeCommandNames.MakeEmployeeRedundant)]
public MakeEmployeeRedundant(MakeEmployeeRedundantCommand command)
{
using (IUnitOfWork unitOfWork = UnitOfWorkFactory.Create())
{
Employee employee = _employeeRepository.GetById(command.EmployeeId);
employee.MakeRedundant();
_employeeRepository.Save();
}
}
}
public void AssertUserHasCorrectPermission(string requiredCommandName)
{
if (!Thread.CurrentPrincipal.IsInRole(requiredCommandName))
throw new SecurityException(string.Format("User does not have {0} command in their role", requiredCommandName));
}
你拦截对第一个方法的调用,并调用第二个方法传递他们必须拥有的角色。
以下是关于如何使用统一拦截的链接:http://litemedia.info/aop-in-net-with-unity-interception-model
答案 2 :(得分:0)
将保存/预存方法放在域对象中的位置?
域对象在DDD中是持久无知的。他们没有意识到有时他们被“冻结”运送到某个存储器然后恢复。他们没有注意到这一点。换句话说,域对象始终处于“有效”且可保存的状态。
权限也应该是持久的 - 无知的,并且基于域和泛在语言,例如:
只有来自销售组的用户才能将OrderLines添加到订单中 待定状态
相反:
只有销售组的用户才能保存订单。
代码可能如下所示:
internal class MyApplication {
private IUserContext _userContext;
private ICanCheckPermissions _permissionChecker;
public void AddOrderLine(Product p, int quantity, Money price, ...) {
if(!_permissionChecker.IsAllowedToAddOrderLines(_userContext.CurrentUser)) {
throw new InvalidOperationException(
"User X is not allowed to add order lines to an existing order");
}
// add order lines
}
}