由于我想使用新的内置依赖注入,我很难找到一种优雅的方法来保持我的DAL层与ASP.NET 5中的MVC / UI层分开。
例如,我有一个ASP.NET 5项目,一个业务层项目和一个数据访问项目,其中我有各种实体框架代码,如实体和上下文。在ASP.NET 5中设置上下文并定位数据库主要文档建议我在我的StartUp.cs类中做这样的事情
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<BookContext>(options =>
{
options.UseSqlServer(Configuration.Get("Data:ConnectionString"));
});
这意味着我现在必须在基本上我的UI层中引用我的DAL,根据各种专家和博客文章,多年来一直是不好的做法。
我解决这个问题的一种方法是创建两个新项目,一个是CompositeRoot项目,它包含生成我的业务类的工厂类,然后访问DAL,还有一个带有Configuration类的Utilities项目,其中有一个{我可以将{1}}属性传递到我的Context中,然后使用内置的DI连接所有内容并避免在我的UI层中引用我的DAL。但是我遇到了最新版本的Entity Framework(beta 7)的问题,因为现在似乎无法在上下文的构造函数或可重写的ConnectionString
方法中指定连接字符串。此外,到目前为止,所有文档似乎都不关心这种混合问题。这就是我们现在做事的方式吗?相信开发人员不会做直接在UI中引用DAL类的“坏”事情?或者是否有一种模式人们正在使用这种新的内置DI /配置为ASP.NET 5保持SOLID?
答案 0 :(得分:9)
如果您要求10位民用建筑师为您建造一座桥梁,您最终将拥有10种不同的架构。没有一个会是相同的,没有一个会比另一个更好。
无论他们应用多少最佳实践和设计模式,每个架构师都会证明他们的想法是正确的。有些人会过于热心,有些则会保持简单并完成工作。除此之外,预算,交付日期和工艺将对您决定的建筑类型产生直接影响。
同样的规则也适用于软件架构师。
我已经看到我在世界上拥有最佳意图的建筑师的公平份额,只是意识到UI层依赖于DAL。也许这背后的原因是:
回到MVC 5,我有以下几层:
-Contoso.Core (Class Library)
-Contoso.Data (Class Library)
-Contoso.Service (Class Library)
-Contoso.Web (asp.net MVC 5)
-Contoso.Web.Configuration (Class Library)
Web.Configuration
图层依赖于Core
,Data
和Service
。这层是我配置DI内容的地方。
Web
图层没有Data
图层的依赖关系,并且开始播放内容,我使用的是Bootstrapper Nuget Package。
也许你可以用ASP.NET 5实现类似的东西
我希望微软(或任何人)能够创建一个工作项目模板,该模板更适合企业级样本,使用解耦方法甚至是洋葱架构样本。
最后,无论我认为合理的解耦架构对某些人来说可能太多而对其他人来说不够......
随时可以分享您的发现,因为我很想知道您是如何使其成功的。
答案 1 :(得分:3)
这真的是一个主要问题吗?
您的UI图层将依赖于您的数据层,并且某处会有一些参考。
StartUp.cs添加了各种服务和配置,因此大多数这些引用都在一个地方。
答案 2 :(得分:1)
您可以使用Service Locator来解决这个问题。
例如,您的 root / core / abstractions 项目中有一个接口:
public interface IServiceConfiguration
{
void ConfigureServices(IServiceCollection services, IConfigurationRoot configuration);
}
在StartUp.cs中,找到实现IServiceConfiguration的所有类型,并使用它来注册外部服务。
public void ConfigureServices(IServiceCollection services)
{
var currentAssembly = typeof(Startup).Assembly;
// Limit to project assemblies
var @namespace = currentAssembly.FullName.Split(',')[0].Split('.')[0];
var assemblies = currentAssembly.GetReferencedAssemblies()
.Where(a => a.Name.StartsWith(@namespace, StringComparison.Ordinal))
.Select(a => Assembly.Load(a));
foreach (var assembly in assemblies)
{
// Assembly.ExportedTypes is not supported in dnxcore50 so you need to take it off your frameworks node in project.json.
foreach (var config in assembly.ExportedTypes.Where(t => typeof(IServiceConfiguration).IsAssignableFrom(t) && !t.IsAbstract))
{
((IServiceConfiguration)Activator.CreateInstance(config)).ConfigureServices(services, Configuration);
}
}
// More service registrations..
}
在您的DAL中,您可以添加一个将注册EF的类:
public sealed class EntityFrameworkServiceConfiguration : IServiceConfiguration
{
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<BookContext>(options =>
{
options.UseSqlServer(Configuration.Get("Data:ConnectionString"));
});
}
}
不是每个人都需要这种类型的解耦。在某些方面,在StartUp.cs中注册所有内容更有意义。您无论如何都会在Web项目中引用您的DAL(除非所有内容都是通过动态发现),这意味着它已经知道关于您的DAL的内容。
答案 3 :(得分:0)
添加全新的ClassLibraryPackage
编辑project.json文件
{
"version": "1.0.0-*",
"description": ":)",
"authors": [ "JJVC" ],
"tags": [ "" ],
"projectUrl": "JJVCblog.com",
"licenseUrl": "",
"frameworks": {
"dnx451": {
"frameworkAssemblies": {
},
"dependencies": {
"EntityFramework.Commands": "7.0.0-rc1-final"
}
}
},
"commands": {
"ef": "EntityFramework.Commands"
},
"dependencies": {
"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final",
"Microsoft.AspNet.Identity": "3.0.0-rc1-final",
"Microsoft.AspNet.Identity.EntityFramework": "3.0.0-rc1-final"
}
}
首先执行代码
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole,string>
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"server=localhost;Database=Whatever;Integrated Security=True;MultipleActiveResultSets=True;Connect Timeout=60;");
}
DbSet<ForgotPasswordResetHistory> ForgotPasswordResetHistory { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
base.OnModelCreating(builder);
}
}
public class ForgotPasswordResetHistory
{
[Key]
public int ForgotPasswordResetHistoryId { get; set; }
public bool UserTriedToResetPassword { get; set; }
public DateTime LinkExpirationDate { get; set; }
public string SecretCodeForTheLink { get; set; }
public DateTime PasswordRecoveryRequestDate { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public int Test { get; set; }
}
在文件夹的上下文中启动cmd提示符。 dnu恢复 dnx ef migration anyurmigrationnameis 数据库更新
现在去你的网站&#34;项目和对数据库的引用。在您的Web项目&#34; project.json&#34;你应该在依赖项下看到它被调用。
"ConsoleApp2.Database": "1.0.0-*"
祝你好运!
答案 4 :(得分:0)
我今天在为MVC 6制作演示时遇到了同样的问题。经过一些研究/试验和错误,当我删除
&#34; EntityFramework.SqlServer&#34;:&#34; 7.0.0-beta8&#34;
来自 project.json 文件,一切正常。
答案 5 :(得分:0)
我最近参加了2016年全球Azure Bootcamp,我们所处理的示例项目(纯粹来自Azure视角)非常清楚地表达了这些关注点。我没有花很多时间来剖析这个项目,但是如果有人想看一下,看看这是否适合N-Tier分裂,请回帖。链接是http://opsgilitytraining.blob.core.windows.net/public/modern-cloud-apps-student.zip。分离的内容如下:
答案 6 :(得分:0)
从UI层引用数据层的原因是因为我们需要在IoC容器中注册DbContext(如果您使用的是EF)。
您可以使用MEF(管理扩展性框架)来解决此项目/包参考。检查.NET Core中MEF的实现,因为它已从以前的.NET Framework更改。
在MEF中,您可以按惯例或通过配置来完成。
答案 7 :(得分:-1)
您可以在业务层和数据访问层中实现IServiceCollection的扩展方法。
然后在Web Startup中,您可以调用业务层上的扩展方法,然后再调用数据层上的扩展方法
所以这段代码可以在数据层扩展中:
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<BookContext>(options =>
{
options.UseSqlServer(Configuration.Get("Data:ConnectionString"));
});
将事物分开并且Web只需要在启动文件中使用语句来引用业务层