最近我采用了Repository / Service设计模式来处理我的MVC 4项目中的对象。
这绝对是一个很好的举动,但我发现了一个问题:)现在这可以归结为我对模式的应用,所以我想我会把它放在那里,看看是否有人可以提出解决方案或设计模式,以满足我的需求。
我有一个存储库和一个服务来处理自定义用户。这非常适合获取用户和执行任何用户方法。但是,在我转移到Repository / Service设计模式之前,我有一个静态类来处理所有与用户相关的方法。
其中一种方法是:
public static Profile CurrentUser()
{
// TODO: Need to replace the Profile session when any permissions are changed....
var companyId = HttpContext.Current.Session["CompanyId"].ToString();
if (HttpContext.Current.User.Identity.IsAuthenticated && !string.IsNullOrEmpty(companyId))
{
var userId = Membership.GetUser(HttpContext.Current.User.Identity.Name).ProviderUserKey.ToString();
var repository = new ProfileRepository(companyId);
return repository.Get(userId);
}
else
return null;
}
如您所见,此方法返回特定用户的个人资料(如果他们已登录)。如果不是,则返回null。
我的问题是该方法需要与服务和存储库分开,因为必须从任何控制器调用它,这就是我将其设置为静态的原因。
为了解决这个问题,我创建了一个名为ProfileContext的类,而CurrentUser()是此静态类中唯一的方法。
所以我的问题很简单。这是处理CurrentUser方法的最佳方法还是有另一个更好的解决方案?
干杯, / r3plica
答案 0 :(得分:2)
如果我理解正确,您当前的解决方案是使用静态类(ProfileContext
),其中包含您问题中列出的方法。
这不是太糟糕,但通常最好避免使用静态类,因为它们在单元测试中效果不佳。
处理静态类的一般模式是包装器。
e.g。
public interface IMembershipWrapper
{
MembershipUser GetUser(string name)
}
您的控制器将具有依赖属性:
public IMembershipWrapper membershipWrapper { get; set; }
对于单元测试,您可以使用模拟。 具体实现如下:
public class MembershipWrapper : IMembershipWrapper
{
public MembershipUser GetUser(string name)
{
return Membership.GetUser(string);
}
}
在您的情况下,您可以为ProfileContext
静态类创建一个包装器并使用它。
答案 1 :(得分:0)
我遇到了类似的问题,为了解决这个问题,我提供了一些服务单身。然后我创建了一个只能调用一次的Configure方法。然后,您可以在global.asax文件中调用该方法
SecurityService.cs:
public sealed class SecurityService {
private ISecurityRepository _repository;
public static SecurityService Instance { get; private set; }
private SecurityService(ISecurityRepository repository) {
_repository = repository;
}
public static void Configure(ISecurityRepository repository) {
Instance = new SecurityService(repository);
}
public Model.LoginResponse GetUser(Model.UserRequest request) {
if (string.IsNullOrEmpty(request.SecurityToken)) return null;
User user = _repository.GetUserByToken(request.SecurityToken);
if (user == null) throw new HabitationException("Invalid Security Token. Please login.", null);
return AutoMapper.Mapper.Map<Model.LoginResponse>(user);
}
public Model.LoginResponse Login(Model.LoginRequest request) {
string strPassword = EncryptPassword.GetMd5Hash(request.Password);
User user = _repository.GetUser(request.Username, strPassword);
return AutoMapper.Mapper.Map<Model.LoginResponse>(user);
}
internal User GetLoggedInUser(string securityToken) {
if (string.IsNullOrEmpty(securityToken)) {
return null;
}
User user = _repository.GetUserByToken(securityToken);
if (user == null) throw new HabitationException("Invalid Security Token.", null);
return user;
}
}
global.asax中:
protected void Application_Start() {
MyProject.LinqToSQL.Repositories.SecurityRepository securityRepository = new MyProject.Repository.LinqToSQL.Repositories.SecurityRepository(connection);
MyProject.Repository.HttpCache.Repositories.SecurityRepository securityCacheRepository = new MyProject.Repository.HttpCache.Repositories.SecurityRepository(securityRepository);
MyProject.Domain.Service.Interface.SecurityService.Configure(securityCacheRepository);
}
注意:这里有两个存储库因为我正在使用策略模式。我的一些存储库可以传递额外的存储库,如果它们找不到对象,它们可以调用嵌套的存储库。在这种情况下,效果是如果它不在HttpCache中,它将检查数据库。但这有点偏离主题。
现在,在另一个服务中,您可以调用任何实例方法:
SecurityService.Instance.GetLoggedInUser(SecurityToken);
注意:在我的示例中,我没有对服务类使用依赖注入,只使用存储库。