NetCore+Dapper WebApi架构搭建(四):仓储的依赖注入
上一节我们讲到实体,仓储接口和仓储接口的实现需要遵循约定的命名规范,不仅是规范,而且为了依赖注入,现在我们实现仓储的依赖注入
在NetCore WebApi项目中新添加一个文件夹(Unit),当然你也可以直接放在根目录下面,关键是后期类增加了你会找对地方,看起来不是那么乱,添加一个RuntimeHelper
我先说一下实现仓储依赖注入的基本思路,就是通过反射获取所有的程序集,然后在程序集中找到 I+实体+Repository的接口和 实体+Repository的实现类,然后在依赖注入容器中注册他们的对应关系
所以这个RuntimeHelper很明显是通过反射获取程序集使用的
1 using Microsoft.AspNetCore.Mvc; 2 using Microsoft.Extensions.DependencyModel; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Reflection; 7 using System.Runtime.Loader; 8 9 namespace Dinner.WebApi.Unit 10 { 11 [ApiExplorerSettings(IgnoreApi=true)] 12 public class RuntimeHelper 13 { 14 /// <summary> 15 /// 获取项目程序集,排除所有的系统程序集(Microsoft.***、System.***等)、Nuget下载包 16 /// </summary> 17 /// <returns></returns> 18 public static IList<Assembly> GetAllAssemblies() 19 { 20 List<Assembly> list = new List<Assembly>(); 21 var deps = DependencyContext.Default; 22 //排除所有的系统程序集、Nuget下载包 23 var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package"); 24 foreach (var lib in libs) 25 { 26 try 27 { 28 var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name)); 29 list.Add(assembly); 30 } 31 catch (Exception ex) 32 { 33 // 34 } 35 } 36 return list; 37 } 38 39 public static Assembly GetAssembly(string assemblyName) 40 { 41 return GetAllAssemblies().FirstOrDefault(f => f.FullName.Contains(assemblyName)); 42 } 43 44 public static IList<Type> GetAllTypes() 45 { 46 List<Type> list = new List<Type>(); 47 foreach (var assembly in GetAllAssemblies()) 48 { 49 var typeinfos = assembly.DefinedTypes; 50 foreach (var typeinfo in typeinfos) 51 { 52 list.Add(typeinfo.AsType()); 53 } 54 } 55 return list; 56 } 57 58 /// <summary> 59 /// 根据AssemblyName获取所有的类 60 /// </summary> 61 /// <param name="assemblyName"></param> 62 /// <returns></returns> 63 public static IList<Type> GetTypesByAssembly(string assemblyName) 64 { 65 List<Type> list = new List<Type>(); 66 var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName)); 67 var typeinfos = assembly.DefinedTypes; 68 foreach (var typeinfo in typeinfos) 69 { 70 list.Add(typeinfo.AsType()); 71 } 72 return list; 73 } 74 75 public static Type GetImplementType(string typeName, Type baseInterfaceType) 76 { 77 return GetAllTypes().FirstOrDefault(t => 78 { 79 if (t.Name == typeName && t.GetTypeInfo().GetInterfaces().Any(b => b.Name == baseInterfaceType.Name)) 80 { 81 var typeinfo = t.GetTypeInfo(); 82 return typeinfo.IsClass && !typeinfo.IsAbstract && !typeinfo.IsGenericType; 83 } 84 return false; 85 }); 86 } 87 } 88 }
上面的那个[ApiExplorerSettings(IgnoreApi=true)]是使用Swagger时使用的,这个我们后面会讲
上面的类就是是反射对程序集的操作
这个我们要使用第三方的Autofac依赖注入框架,所以先引入Nuget包:Autofac.Configuration和Autofac.Extensions.DependencyInjection
下面打开startUp.cs类
先把ConfigureServices方法的返回值由void变为IServiceProvider
然后在ConfigureServices的AddMvc()之后添加下面代码
1 #region 依赖注入 2 3 var builder = new ContainerBuilder();//实例化容器 4 //注册所有模块module 5 builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly()); 6 //获取所有的程序集 7 //var assemblys = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray(); 8 var assemblys = RuntimeHelper.GetAllAssemblies().ToArray(); 9 10 //注册所有继承IDependency接口的类 11 builder.RegisterAssemblyTypes().Where(type => typeof(IDependency).IsAssignableFrom(type) && !type.IsAbstract); 12 //注册仓储,所有IRepository接口到Repository的映射 13 builder.RegisterAssemblyTypes(assemblys).Where(t => t.Name.EndsWith("Repository") && !t.Name.StartsWith("I")).AsImplementedInterfaces(); 14 //注册服务,所有IApplicationService到ApplicationService的映射 15 //builder.RegisterAssemblyTypes(assemblys).Where(t => t.Name.EndsWith("AppService") && !t.Name.StartsWith("I")).AsImplementedInterfaces(); 16 builder.Populate(services); 17 ApplicationContainer = builder.Build(); 18 19 return new AutofacServiceProvider(ApplicationContainer); //第三方IOC接管 core内置DI容器 20 //return services.BuilderInterceptableServiceProvider(builder => builder.SetDynamicProxyFactory()); 21 #endregion
这样以来注入就可以了
现在添加一个UsersController进行测试
1 using Dinner.Dapper.Entities; 2 using Dinner.Dapper.IRepository; 3 using Microsoft.AspNetCore.Mvc; 4 using System; 5 using System.Collections.Generic; 6 using System.Threading.Tasks; 7 8 namespace Dinner.WebApi.Controllers 9 { 10 11 [Route("api/[controller]/[action]")] 12 public class UsersController : Controller 13 { 14 private readonly IUserRepository userRepository; 15 public UsersController(IUserRepository _userRepository) 16 { 17 userRepository = _userRepository; 18 } 19 20 /// <summary> 21 /// 获取所有用户 22 /// </summary> 23 /// <returns></returns> 24 /// 25 [HttpGet] 26 public async Task<JsonResult> GetUsers() 27 { 28 List<Users> list = await userRepository.GetUsers(); 29 return Json(list); 30 } 31 32 /// <summary> 33 /// 新增用户 34 /// </summary> 35 /// <param name="entity"></param> 36 /// <returns></returns> 37 [HttpPost] 38 public async Task PostUser(Users entity) 39 { 40 entity.Password = Dapper.Helpers.Encrypt.Md5(entity.Password).ToUpper(); 41 await userRepository.PostUser(entity); 42 } 43 44 /// <summary> 45 /// 修改用户信息 46 /// </summary> 47 /// <param name="entity"></param> 48 /// <returns></returns> 49 [HttpPut] 50 public async Task PutUser(Users entity) 51 { 52 try 53 { 54 entity.Password = Dapper.Helpers.Encrypt.Md5(entity.Password).ToUpper(); 55 await userRepository.PutUser(entity); 56 } 57 catch (Exception ex) 58 { 59 throw new ArgumentException(ex.Message); 60 } 61 } 62 63 /// <summary> 64 /// 删除用户 65 /// </summary> 66 /// <param name="Id"></param> 67 /// <returns></returns> 68 [HttpDelete] 69 public async Task DeleteUser(Guid Id) 70 { 71 try 72 { 73 await userRepository.DeleteUser(Id); 74 } 75 catch (Exception ex) 76 { 77 throw new ArgumentException(ex.Message); 78 } 79 } 80 } 81 }
自己测试一下仓储的增删改查吧,看看写的有问题没有
下一节我们讲解Swagger构建WebApi界面
赠送一个Framework版本的依赖注入
1 #region autofac IOC容器配置 2 var builder = new ContainerBuilder(); 3 4 //注册所有的controller 5 builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired(); 6 //注册所有模块module 7 builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly()); 8 9 var assemblys = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray(); 10 11 //注册所有继承IDependency接口的类 12 builder.RegisterAssemblyTypes(assemblys) 13 .Where(type => typeof(IDependency).IsAssignableFrom(type) && !type.IsAbstract); 14 15 //注册服务,所有IxxxxRepository=>xxxxRepository 16 builder.RegisterAssemblyTypes(assemblys).Where(t => t.Name.EndsWith("Repository") && !t.Name.StartsWith("I")).AsImplementedInterfaces(); 17 18 var container = builder.Build(); 19 20 BaseInfo._container = container; 21 22 DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 23 #endregion
源码地址: https://github.com/wangyulong0505/Dinner