应用程序服务层作为静态类

10
在我的ASP.NET MVC应用程序中,我有一个包含所有业务逻辑/服务层的项目。该项目与位于单独项目中的数据库(Entity framework)进行交互。
我希望轻松访问服务层,因此我在其中创建了静态类,以便可以轻松引用它们。例如,如果我在控制器中需要创建新账户:
 ServiceLayer.Accounts.CreateAccount(userName, passWord) //etc..

服务层然后执行所有必要的逻辑,然后通过DatabaseLayer中的存储库创建用户。

    private static AllRepos _Repos;
    private static AllRepos Repos { 
       get 
        { 
           if(_Repos == null)
              _Repos = new AllRepos();

           return _Repos
        }
    }

    public static void CreateAccount(string username, password)
    {
        string salt = GenerateSalt();
        Account newAccount = DatabaseLayer.Models.Account
              { 
              Name = username,
              Password = HashPassword(password, salt),
              Salt = salt
              };
        Repos.AddAccount(newAccount);      
    }

因为我不想在我的服务层中到处执行以下操作:

 AccountRepository Accounts = new DatabaseLayer.AccountRepository();

我相反地创建了一个仓库的包装类,这样我只需要实例化一次就可以使用所有其他仓库。

 public class AllRepos
 {

    private AccountRepository _Accounts;

    public AccountRepository Accounts
    {
        get
        {
            if (_Accounts== null)
                _Accounts= new AccountRepository();

            return _Accounts;
        }
    }

    // the same is done for every other repository (currently have about 10+)
  }

这是在服务层的静态类中使用的。

由于我的所有服务层类都是静态的,而Repos字段也是静态的,明显的问题是同一个对象从多个数据上下文中检索出来,导致更新/删除时出现奇怪的行为。

我知道如果像我一样使用静态成员/类,这是可以预料到的,因为它们持续了应用程序的生命周期,但是否有一种方法可以在不创建需要实例化的非静态类的情况下,使用服务层作为ServiceLayer.Accounts.Method()并且不会因为多个数据上下文实例而遇到CRUD问题?


事实上,一些最好的辅助方法是静态的。你对“最好”的概念是什么? - user501406
4个回答

16

你的方法并不是一种推荐的方式。个人来说,我绝不会允许这种方法在我的团队中出现。以下是它的缺点:

  1. 存在重大的线程问题,正如你所经历的那样,这些问题并不容易解决
  2. 很难进行测试
  3. 对数据访问进行了不切实际的抽象

创建存储库实例最大的原因是为了在需要时注入依赖项。其中最著名的论据是为了单元测试,以便您可以模拟依赖项,但我已经构建了许多存储库,这些存储库具有在生产代码中更改的接口依赖性。

您应该将存储库实例化作为基本服务类的一部分。没有理由一定要在“静态 实例调用到处”之间选择。在基类中应该只存在有限的实例化代码。


还想补充一点,当在控制器和服务之间使用静态类时,我遇到了升级到MSDTC的问题。 - DevDave

10

我不确定你为什么如此坚决反对使用实例。除了你现有的代码已经过于复杂之外,使用静态类型还会使单元测试变得更加困难。静态类型就像是一个单例模式,你无法模拟或替换它。在我看来,你真正的问题可能是“如何管理服务层的实例生命周期?”通常,你可以通过每个Web请求使用一个实例来解决这个问题。在ASP.NET MVC应用程序中,你可以通过ControllerFactory新建一个DI容器,并处理所有这些事情。 [PDF]


1

你需要有意识地处理你的对象上下文的范围,就像做一个工作单元模式一样。

除此之外,我认为你应该重新考虑将所有东西都设为静态的。正如womp所说,这会导致非常高的耦合性,并且使测试变得非常困难。通过使用IOC容器,你可以获得很多帮助来管理依赖关系图。

我可以说,在以前做过那种事情后,我自己也受到了伤害 :)


-4

单例模式(以及静态类)是有害的,应该尽量避免在 Web 应用程序中使用。


我不同意这个观点,Helper方法在静态时是理想的。 事实上,一些最好的Helper方法在Web应用中是静态的。例如Request、Server.MapPath、File/Directory等等。 - Mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接