我正在使用实体Framework Core在asp.net Core应用程序中创建Crud服务。我的原始服务具有事件和处理程序,例如OnCreated,OnUpdated。
这些事件也应该能够调用其他Crud服务。
如何实现?
这是我注入CRUD服务的方式:
services.AddTransient<IRoleManager, RoleManager>();
services.AddTransient<IOfficeManager, OfficeManager>();
services.AddTransient<IProjectManager, ProjectManager>();
以下是我的CRUD服务之一:
public class ProjectManager : IProjectManager
{
protected AppDbContext Db;
public ProjectManager(AppDbContext db)
{
Db = db;
}
public IQueryable<Project> GetProjects()
{
return Db.Projects;
}
public Project CreateProject (Project project)
{
Project Project = Db.Projects.Add(project).Entity;
Db.SaveChanges();
OnProjectCreated(Project);
return Project;
}
public Project UpdateProject (Project project)
{
Project Project = Db.Projects.Update(project).Entity;
Db.SaveChanges();
OnProjectUpdated(Project);
return Project;
}
public Project DeleteProject (Project project)
{
Db.Projects.Remove(project);
Db.SaveChanges();
OnProjectDeleted(project);
return project;
}
public event EventHandler<ProjectManagerEventArgs> ProjectCreated;
public event EventHandler<ProjectManagerEventArgs> ProjectUpdated;
public event EventHandler<ProjectManagerEventArgs> ProjectDeleted;
protected virtual void OnProjectCreated(Project project)
{
ProjectCreated?.Invoke(this, new ProjectManagerEventArgs(project));
}
protected virtual void OnProjectUpdated(Project project)
{
ProjectUpdated?.Invoke(this, new ProjectManagerEventArgs(project));
}
protected virtual void OnProjectDeleted(Project project)
{
ProjectDeleted?.Invoke(this, new ProjectManagerEventArgs(project));
}
}
我可以这样订阅...
services.AddTransient(sp =>
{
AppDbContext dependency = sp.GetService<AppDbContext>();
ProjectManager target = new ProjectManager(dependency);
target.ProjectCreated += new ProjectManagerListener().OnProjectCreated;
return (IProjectManager)target;
});
但是这种方式很草率,并且阻止了我的处理程序/侦听器访问其他CRUD服务。
如何将事件与DI一起使用?
聆听者代码
public class ProjectManagerListener
{
private readonly IClaimManager ClaimManager;
private readonly IRoleManager RoleManager;
public ProjectManagerListener(IClaimManager claimManager, IRoleManager roleManager)
{
ClaimManager = claimManager;
RoleManager = roleManager;
}
public void OnProjectCreated(object source, ProjectManagerEventArgs ProjectEventArgs)
{
foreach (Role role in RoleManager.GetRoles())
{
ClaimManager.CreateClaim(new ProjectRoleClaim() { ProjectId = ProjectEventArgs.Project.Id, RoleId = role.Id });
}
}
}
助听器注射代码
services.AddTransient(sp =>
{
AppDbContext dependency = sp.GetService<AppDbContext>();
IClaimManager ClaimManager = sp.GetService<IClaimManager>();
IRoleManager RoleManager = sp.GetService<IRoleManager>();
ProjectManager target = new ProjectManager(dependency);
target.ProjectCreated += new ProjectManagerListener(ClaimManager, RoleManager).OnProjectCreated;
return (IProjectManager)target;
});
答案 0 :(得分:0)
一种实现此目的的方法是为事件发布/侦听创建服务,而不是使用C#事件。然后,您可以将DI与这些服务一起使用。在绝对最原始的形式中,您需要以下元素:
事件:
public class ProjectCreatedEvent
{
public int ProjectId { get; }
public ProjectCreatedEvent(int projectId)
{
ProjectId = projectId;
}
}
这些可能是不可变的POCO。
听众:
public interface IListener
{
}
public interface IListener<T> : IListener
{
void HandleMessage(T message);
}
public class ProjectCreatedEventListener : IListener<ProjectCreatedEvent>
{
private readonly IClaimManager _claimManager;
public ProjectCreatedEventListener(IClaimManager claimManager)
{
_claimManager = claimManager;
}
public void HandleMessage(ProjectCreatedEvent message)
{
_claimManager.CreateClaim(message.ProjectId);
}
}
由于这些将在DI容器中注册,因此可以轻松注入依赖项。
调度员:
public interface IDispatcher
{
void Publish<T>(T message);
}
public class Dispatcher : IDispatcher
{
private readonly IEnumerable<IListener> _listeners;
public Dispatcher(IEnumerable<IListener> listeners)
{
_listeners = listeners;
}
public void Publish<T>(T message)
{
foreach (var listener in _listeners.OfType<IListener<T>>())
{
listener.HandleMessage(message);
}
}
}
这只是注入所有侦听器,然后提供一种向其侦听器发布消息的方法。
然后您将发布以下事件:
public class ProjectManager : IProjectManager
{
private readonly IDispatcher _dispatcher;
public ProjectManager(IDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void CreateProject(string name)
{
// Do the CRUD...
Console.WriteLine($"Creating project '{name}'");
_dispatcher.Publish(new ProjectCreatedEvent(43));
}
}
这是一个在DI中连接起来的可行示例:
public static void Main(string[] args)
{
var serviceProvider = new ServiceCollection()
.AddTransient<IProjectManager, ProjectManager>()
.AddTransient<IClaimManager, ClaimManager>()
.AddTransient<IListener<ProjectCreatedEvent>, ProjectCreatedEventListener>()
.AddTransient<IListener>(sp => sp.GetService<IListener<ProjectCreatedEvent>>())
.AddTransient<IDispatcher, Dispatcher>()
.BuildServiceProvider();
var service = serviceProvider.GetService<IProjectManager>();
service.CreateProject("My project.");
}
哪个给出结果:
答案 1 :(得分:0)
我使用SQL触发器解决了这个问题
使用Nuget的EntityFrameworkCore.Triggers
在我的模型中(角色示例):
static Role()
{
Triggers<Role>.Inserted += e =>
{
e.Context.Add(new RoleClaim() { RoleId = e.Entity.Id });
IEnumerable<Office> offices = e.Context.Set<Office>();
foreach(Office office in offices)
{
e.Context.Add(new OfficeRoleClaim() { Office = office, Role = e.Entity });
}
IEnumerable<Project> projects = e.Context.Set<Project>();
foreach (Project project in projects)
{
e.Context.Add(new ProjectRoleClaim() { Project = project, Role = e.Entity });
}
e.Context.SaveChanges();
};
}
在DbContext中:
public override int SaveChanges()
{
return this.SaveChangesWithTriggers(base.SaveChanges, acceptAllChangesOnSuccess: true);
}