存储库和静态方法

时间:2013-08-28 12:53:33

标签: c# asp.net-mvc dependency-injection inversion-of-control

最近我采用了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

2 个答案:

答案 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);

注意:在我的示例中,我没有对服务类使用依赖注入,只使用存储库。