.NET MVC 5 分成不同的项目:避免循环引用
.NET MVC 5 separate into different projects: avoid circular reference
我有一个解决方案只包含一个项目(MVC 5 with Identity and EF).
数据库上下文是一个 ApplicationDbContext(IdentityDbContext 的子class,它本身是 EF DbContext 的子class)。
我还有一个自定义验证属性,需要使用数据库上下文来执行它的操作:
public class RequiredIfRol : ValidationAttribute, IClientValidatable {
//...
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
// ...
string nomRol = "";
//instance and use the ApplicationDbContext
using (ApplicationDbContext db = new ApplicationDbContext()) {
var roldb = db.Roles.Find(rolId);
if (roldb == null) return ValidationResult.Success;
nomRol = db.Roles.Find(rolId).Name;
}
// more code here
}
}
这工作正常。
现在,在阅读它之后,我试图将这个 MVC 项目分成几个项目:
- class DAL 库(它将包含 EF 模型和 ApplicationDbContext),
- 另一个用于业务逻辑,
- 另一个普通东西
- 然后是 MVC 项目。
我对此一窍不通,因为我一直把所有东西都放在同一个 MVC 项目中,所以我很困惑:
我认为该属性应该驻留在 Common 项目中,以便可以从 DAL(装饰模型)和 MVC(装饰视图模型)中引用它。
由于 Common 项目将从所有其他项目中引用,我想我不能从 Common 中引用任何这些项目(循环引用?)。并且,由于 ApplicationDbContext(属性需要使用)将驻留在 DAL 项目中,我在这里遇到问题...
我很确定我的设计很糟糕,但找不到正确的方法。有什么帮助吗?
已添加:
这是我试过的:
1.- 在公共库中,定义了一个接口:
public interface IMyInterface {
System.Data.Entity.IDbSet<CustomRole> Roles { get; set; }
}
2.- 在 applicationDbContext 中,修改其声明以实现接口:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>, IMyInterface {...}
3.- 然后在属性中,尝试通过添加 getter 属性:
来获取接口的实现
private IMyInterface _dbcontext { get { return DependencyResolver.Current.GetService<IMyInterface>(); } }
然后在 IsValid() 方法中:
var roldb = _dbcontext.Roles.Find(rolId);
if (roldb == null) return ValidationResult.Success;
nomRol = _dbcontext.Roles.Find(rolId).Name;
但这没有用...
解决它的一种方法是使用上下文为您的代码创建一个抽象 - IRoleFinder
并将公共项目与您的 RequiredIfRol
一起放入。然后在业务逻辑层实现,inject在MVC项目中实现。这样你应该能够将你的属性与上下文分离。
ValidationAttribute.IsValid()
有一个 ValidationContext
参数,您可以使用该参数通过 ValidationContext.GetService
方法解决依赖关系。
UPD
根据您在评论中的要求:
For simplification, lets say I have only 2 projects (the class library with the attribute, and the MVC project with everything else).
在图书馆你会有这样的东西:
interface IRoleFinder
{
CustomRole Find(int id);
}
public class RequiredIfRol : ValidationAttribute, IClientValidatable {
//...
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
// ...
var roleFinder = (IRoleFinder) validationContext.GetService(typeof(IRoleFinder));
}
}
在您的 MVC 项目中:
public class RoleFinder : IRoleFinder
{
public CustomRole Find(int id)
{
// use context here
}
}
并且在 Startup 中(这是针对 ASP.NET Core,对于 MVC 5 你应该找到另一种方法):
services.AddTransient<IRoleFinder, RoleFinder>()
我有一个解决方案只包含一个项目(MVC 5 with Identity and EF). 数据库上下文是一个 ApplicationDbContext(IdentityDbContext 的子class,它本身是 EF DbContext 的子class)。 我还有一个自定义验证属性,需要使用数据库上下文来执行它的操作:
public class RequiredIfRol : ValidationAttribute, IClientValidatable {
//...
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
// ...
string nomRol = "";
//instance and use the ApplicationDbContext
using (ApplicationDbContext db = new ApplicationDbContext()) {
var roldb = db.Roles.Find(rolId);
if (roldb == null) return ValidationResult.Success;
nomRol = db.Roles.Find(rolId).Name;
}
// more code here
}
}
这工作正常。
现在,在阅读它之后,我试图将这个 MVC 项目分成几个项目:
- class DAL 库(它将包含 EF 模型和 ApplicationDbContext),
- 另一个用于业务逻辑,
- 另一个普通东西
- 然后是 MVC 项目。
我对此一窍不通,因为我一直把所有东西都放在同一个 MVC 项目中,所以我很困惑: 我认为该属性应该驻留在 Common 项目中,以便可以从 DAL(装饰模型)和 MVC(装饰视图模型)中引用它。
由于 Common 项目将从所有其他项目中引用,我想我不能从 Common 中引用任何这些项目(循环引用?)。并且,由于 ApplicationDbContext(属性需要使用)将驻留在 DAL 项目中,我在这里遇到问题...
我很确定我的设计很糟糕,但找不到正确的方法。有什么帮助吗?
已添加:
这是我试过的:
1.- 在公共库中,定义了一个接口:
public interface IMyInterface {
System.Data.Entity.IDbSet<CustomRole> Roles { get; set; }
}
2.- 在 applicationDbContext 中,修改其声明以实现接口:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>, IMyInterface {...}
3.- 然后在属性中,尝试通过添加 getter 属性:
来获取接口的实现private IMyInterface _dbcontext { get { return DependencyResolver.Current.GetService<IMyInterface>(); } }
然后在 IsValid() 方法中:
var roldb = _dbcontext.Roles.Find(rolId);
if (roldb == null) return ValidationResult.Success;
nomRol = _dbcontext.Roles.Find(rolId).Name;
但这没有用...
解决它的一种方法是使用上下文为您的代码创建一个抽象 - IRoleFinder
并将公共项目与您的 RequiredIfRol
一起放入。然后在业务逻辑层实现,inject在MVC项目中实现。这样你应该能够将你的属性与上下文分离。
ValidationAttribute.IsValid()
有一个 ValidationContext
参数,您可以使用该参数通过 ValidationContext.GetService
方法解决依赖关系。
UPD
根据您在评论中的要求:
For simplification, lets say I have only 2 projects (the class library with the attribute, and the MVC project with everything else).
在图书馆你会有这样的东西:
interface IRoleFinder
{
CustomRole Find(int id);
}
public class RequiredIfRol : ValidationAttribute, IClientValidatable {
//...
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
// ...
var roleFinder = (IRoleFinder) validationContext.GetService(typeof(IRoleFinder));
}
}
在您的 MVC 项目中:
public class RoleFinder : IRoleFinder
{
public CustomRole Find(int id)
{
// use context here
}
}
并且在 Startup 中(这是针对 ASP.NET Core,对于 MVC 5 你应该找到另一种方法):
services.AddTransient<IRoleFinder, RoleFinder>()