記錄:如何使用ASP.NET Core和EnityFramework Core實現 數據庫操做 和 數據庫實體 的項目分離

前情提要:app

  現有一個網站框架,包括主體項目WebApp一個,包含 IIdentityUser 接口的基架項目 A。用於處理用戶身份驗證的服務 AuthenticationService 位於命名空間B。用於保存數據的實體 User : IIdentityUser 位置項目C。項目之間的關係是B和C依賴項目A。框架

 

需求:ide

  如今有一個新項目D,在這個項目裏有一個DUser : IIdentityUser 。如何處理才能最優雅的在不添加引用和修改項目B的前提下,將用戶保存至DUser。函數

 

實際例子:網站

  在ASP.NET CORE中,有一個東西叫IdentityServer。裏面就有這個東西,他寫的是相似IdentityServerBuilder.AddService<TUser, TRole>()這種代碼,如何實現?ui

 

解決方案:this

  一、新建一個泛類(這個類能夠標記爲internal,外部不須要了解,也不須要訪問):orm

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();
        }
    }

  二、新建一個用以操做的服務(注意,全部須要的操做都往這個裏面寫,將來暴露的也是這個接口)對象

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);
   }
    }

  

  三、添加一個注射器blog

    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))

  至此,咱們就已經將泛類的類型名拆到了變量裏面。而後就能夠玩出一萬種花樣了。

  四、在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擺出一萬種姿式。

相關文章
相關標籤/搜索