记录:如何使用ASP.NET Core和EnityFramework Core实现 数据库操作 和 数据库实体 的项目分离
前情提要:
现有一个网站框架,包括主体项目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摆出一万种姿势。
上一篇: 关于 webassebmly Blazor RPC 调用
下一篇: mysql增加外键约束具体方法