复杂服务层中IoC的最佳实践
我正在开发一个MVC应用程序,我正在使用Unity for IoC。 我的应用程序基本上由UI层,服务层和存储库层组成。
我的典型控制器是:
public class TestController : Controller { private ITestService testServ; public TestController(ITestService _testServ) { testServ= _testServ; } public ActionResult Index() { testServ.DoSomething(); return View(); } }
没有什么不寻常的,我的每个控制器都注入了一个服务对象。 因此,我的服务层对象执行复杂的业务规则,聚合来自许多不同存储库的信息。 通过使用IoC我发现我的构造函数看起来过于复杂,但由于服务需要访问许多存储库,我无法看到任何解决方法。
我的服务层中的典型类看起来像:
public class TestService : ITestService { private ITransactionRepository transRepo; private IAccountRepository accountRepo; private ISystemsRepository sysRepo; private IScheduleRepository schRepo; private IProfileRepository profileRepo; public TestService(ITransactionRepository _transRepo; IAccountRepository _accountRepo; ISystemsRepository _sysRepo; IScheduleRepository _schRepo; IProfileRepository _profileRepo) { transRepo = _transRepo; accountRepo = _accountRepo; sysRepo = _sysRepo; schRepo = _schRepo; profileRepo = _profileRepo; } public DoSomething() { //Implement Business Logix } }
我的几个服务层对象需要10个或更多的存储库。 我的存储库位于使用Entity Framework,其中每个存储库类都在底层数据存储中公开一个表。
我正在寻找有关所描述情况的最佳实践的一些建议。
以下是一些简化(和减少)依赖项的步骤:
-
将服务拆分为单独的服务并将其注入控制器。 这将减少服务的依赖性数量。 缺点是您需要向控制器注入更多依赖项。 分裂控制器变得复杂时,下一步就是它们。 记住单一责任原则 。
-
看看Bounded Context模式:您可以尝试将通常在单个上下文中组合在一起的实体分组,并将该上下文注入服务,而不是注入数十个存储库:
public class TestService : ITestService { private readonly ITestData testData; // represents a bounded context public TestService(ITestData testData) { this.testData = testData; } public void DoSomething() { this.testData.Transactions.Add(...); //It gives you access to Transactions repository } }
您已创建了一个服务层,以便它充当底层存储库的外观。 这种方法是一种很好的做法,可以使用粗API为客户端提供外观。 客户端不必担心底层存储库。
由于DI的完成方式,服务本身现在具有复杂的构造函数。 另一种方法是在服务层使用抽象工厂模式并执行setter注入。 新的存储库的这种复杂性被移动到一个单独的类中,它自己的工厂。 例如:
您可以按如下方式设置测试服务的存储库,而不是构造函数
public class TestService : ITestService { private ITransactionRepository transRepo = DataAccess.transRepo; private IAccountRepository accountRepo = DataAccess.accountRepo; private ISystemsRepository sysRepo = DataAccess.sysRepo; private IScheduleRepository schRepo = DataAccess.schRepo ; private IProfileRepository profileRepo = DataAccess.profileRepo; }
以下是工厂界面的示例
public interface IRepoFactory { ITransactionRepository TransRepo {get;} IAccountRepository AccountRepo {get;} ISystemsRepository SysRepo {get;} IScheduleRepository SchRepo {get;} IProfileRepository ProfileRepo {get;} }
下面是一个具体工厂的例子,它将新建所有存储库。
public class EfFactory : IRepoFactory { public ITransactionRepositry TransRepo { return new TransactionRepository();} public IAccountRepository AccountRepo {return new AccountRepository();} public ISystemsRepository SysRepo {return new SystemRepository();} public IScheduleRepository SchRepo {return new SchRepository();} public IProfileRepository ProfileRepo {return new ProfileRepository();} }
下面是一个工厂方法,将返回具体工厂(在您的情况下,它将是一个EF工厂)
public class RepoFactories { public static IRepoFactory GetFactory(string typeOfFactory) { return (IRepoFactory)Activator.CreateInstance(Type.GetTypetypeOfFactory) } }
抽象工厂用静态方法来新建并返回存储库对象
//示例:factoryName = MyProject.Data.EFFactory(可以在web.config或app.config中添加)
Public static class DataAccess { private static readonly string DbfactoryName= ConfigurationManager.AppSettings.Get("factoryName"); private static readonly IRepoFactory factory = RepoFactories.GetFactory(DbfactoryName); public static ITransactionRepositry transRepo { get {return factory.TransRepo;} } public static IAccountRepository accountRepo { get {return factory.AccountRepo;} } }
- 如何在asp.net 5中为“asp-for”传递字符串值
- asp.net mvc中db上下文类的用途是什么
- Custom MembershipProvider:没有为此对象定义的无参数构造函数
- MVC3全球化:在模型绑定之前需要全局过滤
- 在DropDownListFor上添加搜索function
- 如何对依赖于c#中的身份validation的MVC控制器操作进行unit testing?
- 在ASP.Net Core 2 MVC中禁用模型validation的正确方法
- Http错误的自定义错误页面404.13 ASP.NET Core MVC
- ASP.NET身份,立即将另一个用户添加到角色(他们不必再次注销)