前情提要:
現有一個網站框架,包括主體專案WebApp一個,包含 IIdentityUser 介面的基架專案 A,用于處理用戶身份驗證的服務 AuthenticationService 位于命名空間B,用于保存資料的物體 User : IIdentityUser 位置專案C,專案之間的關系是B和C依賴專案A,
需求:
現在有一個新專案D,在這個專案里有一個DUser : IIdentityUser ,如何處理才能最優雅的在不添加參考和修改專案B的前提下,將用戶保存至DUser,
實際例子:
在ASP.NET CORE中,有一個東西叫IdentityServer,里面就有這個東西,他寫的是類似IdentityServerBuilder.AddService<TUser, TRole>()這種代碼,如何實作?
解決方案:
1、新建一個泛類(這個類可以標記為internal,外部不需要了解,也不需要訪問):
public class UserContext<TUser>
where TUser : class, IIdentityUser, new ()
{
public YourContext dbContext;
public UserContext(YourContext ctx) => dbContext = ctx;
public DbSet<TUser> Users
{
get
{
return dbContext.Set<TUser>();
}
}
public void SaveChanges()
{
dbContext.SaveChanges();
}
}
2、新建一個用以操作的服務(注意,所有需要的操作都往這個里面寫,未來暴露的也是這個介面)
public class UserService<TUser> : IUserService
where TUser: class, IIdentityUser, new()
{
private UserContext<TUser> dbContext;
public UserService(YourContext ctx, IServiceProvider provider)
{
dbContext = new PermissionContext<TUser>(ctx.DbContext);
}
public TUser GetUserById(Guid id)
{
return dbContext.Users.FirstOrDefault(e => e.ID == id);
}
}
3、添加一個注射器
public static class AuthenticationInject
{
public static IServiceCollection AddAuthenticationContext<TUser>(this IServiceCollection services)
where TUser: IIdentityUser
{
var serviceType = typeof(UserService<>).MakeGenericType(typeof(TUser));
services.AddSingleton(typeof(IUserService), serviceType );
return services;
}
}
技術點:使用MakeGenericType方法可以動態加載泛類實體,如果型別是 UserService<TUser, TRole>,則寫成 typeof(UserService<,>).MakeGenericType(typeof(T1), typeof(T2))
至此,我們就已經將泛類的型別名拆到了變數里面,然后就可以玩出一萬種花樣了,
4、在WebApp里,注入相關變數
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthenticationContext<DUser>();
}
分析依賴關系:
執行專案WebApp依賴A,B,D,B和D專案只依賴A,甚至于,這里還能再解耦,把函式AddAuthenticationContext從泛型函式改成 AddAuthenticationContext(Type userType),還可以再進一步,改成AddAuthenticationContext(string type),通過反射和配置來取型別,做到A專案和D專案解耦,
擴展性:
在未來,有新專案E,EUser,只需要將D和A解除分離,再將E和A進行關聯,只需要修改 AddAuthenticationContext 函式,即可滿足要求,當然,如果要有心情,你甚至可以搞一個自動發現的代碼(比如我專案里就是這么搞的,自動分析IIdentityUser的物件,然后附加給Context,為了保證有多個實作時能正確附加,我做了一個Attribute用來標記這個專案要用哪個User),再有心情還可以做成配置式的,反正你可以把EF Core擺出一萬種姿勢,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/1056.html
標籤:領域驅動設計
下一篇:DDD領域驅動的前生今世
