.net webapi+autofac+autoMapper
介绍
github:https://github.com/QQ2287991080/AutofacSolution
webapi+autofac+autoMapper单元测试:https://www.cnblogs.com/aqgy12138/p/13283977.html
看到标题大伙可能会想,现在不都是学.net core了吗。
我想说的是,学的人是不少,但是有多少是能够在公司拍板技术方向的人呢,很多时候也是身不由己吧。
.net core webapi+autofac+autoMapper这种模式可以说百度上多如牛毛。
下面开始。。
首先创建一个.net webapi项目 framework的版本是4.72
这里我附带创建了一个单元测试。后续用来做测试。
🆗,项目建好之后把没用的东西先删除去。
然后我们需要安装nuget包,尽量都用最新的吧。
主要是三个包Autofac、Autofac.WebApi2、AutoMapper
包装好后创建一下做测试的类。
不要忘记让Concrete继承Interfacs中对应的接口哦。
然后在ITest系列类中加一个抽象方法,再到Test中去实现。
好的,我们的测试类就这样搞定了。
在App_Start文件夹下创建一个类,用于实现autofac。并且把我们的测试类都放到容器中。
public class AutofacRegister { public static void Register() { //初始化容器 var builder = new ContainerBuilder(); /* * 把我们的测试类放到容器中 */ builder.RegisterType<TestA>().As<ITestA>().AsImplementedInterfaces(); builder.RegisterType<TestB>().As<ITestB>().AsImplementedInterfaces(); builder.RegisterType<TestC>().As<ITestC>().AsImplementedInterfaces(); //获取global配置 var configuration = GlobalConfiguration.Configuration; //注册控制器 builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); //创建容器 var container = builder.Build(); //将DI解析程序设置为autofac configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container); } }
按照管理,类似这种更改了web初始配置的都需要到Global.asax配置一下。
public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() {
AutofacRegister.Register(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); } }
在Global里加上AutofacRegister.Register(); 这里可能有人问我为什么只有三行代码,因为最开始将项目的时候把没用的都删除,相应一些配置在这里也需要去掉。
建一个控制器然后写上我们需要测试的东西。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Http; using WEBAPI.Autofac.AutoMapper.Demo.Interfacs; namespace WEBAPI.Autofac.AutoMapper.Demo.Controllers { public class TestController:ApiController { readonly ITestA _testA; readonly ITestB _testB; readonly ITestC _testC; public TestController( ITestA testA, ITestB testB, ITestC testC ) { _testA = testA; _testB = testB; _testC = testC; } [HttpGet] public IHttpActionResult TestA() { return this.Json(_testA.Get()); } [HttpGet] public IHttpActionResult TestB() { return this.Json(_testB.Get()); } [HttpGet] public IHttpActionResult TestC() { return this.Json(_testC.Get()); } } }
写好之后就用Postman来测试一下吧。
咳咳,出了个错误,然我来瞅瞅啥错误。看样子好像是路由有问题。
不慌。
给控制上加个[RoutePrefix("api/test")]特性,然后方法上加个Route试试先。
成了!!!
控制的完整代码贴一下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Http; using WEBAPI.Autofac.AutoMapper.Demo.Interfacs; namespace WEBAPI.Autofac.AutoMapper.Demo.Controllers { [RoutePrefix("api/test")] public class TestController:ApiController { readonly ITestA _testA; readonly ITestB _testB; readonly ITestC _testC; public TestController( ITestA testA, ITestB testB, ITestC testC ) { _testA = testA; _testB = testB; _testC = testC; } [HttpGet] [Route("TestA")] public IHttpActionResult TestA() { return this.Json(_testA.Get()); } [HttpGet] [Route("TestB")] public IHttpActionResult TestB() { return this.Json(_testB.Get()); } [HttpGet] [Route("TestC")] public IHttpActionResult TestC() { return this.Json(_testC.Get()); } } }
到目前位置所做的其实是autofac做依赖注入的基操,开文所将的automapper咋还没有用上。
这次主要想讲的是automapper的两种实现。
先来做做准备工作
创建文件夹Profiles
创建抽象接口IProfile,这个后面会讲到
/// <summary> /// 需要注册automapper都实现该接口 /// </summary> public interface IProfile { }
然后我再弄两个测试用的类,这个放在Models文件夹下的。
/// <summary> /// 这里便于测试我就随便弄弄 /// </summary> public class TestModel { public int Age { get; set; } public string Name { get; set; } } public class TestModelDto { public int Age { get; set; } public string Name { get; set; } }
创建关系映射类
public class TestProfile:Profile,IProfile { public TestProfile() { CreateMap<TestModel, TestModelDto>(); } }
下面说的第一种做法,这个是官网的例子我就直接复制过来了。
using Autofac; using AutoMapper; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using Module = Autofac.Module; namespace WEBAPI.Autofac.AutoMapper.Demo.Profiles { public class AutoMapperRegister:Module { private readonly IEnumerable<Assembly> assembliesToScan; public AutoMapperRegister(IEnumerable<Assembly> assembliesToScan) => this.assembliesToScan = assembliesToScan; public AutoMapperRegister(params Assembly[] assembliesToScan) : this((IEnumerable<Assembly>)assembliesToScan) { } protected override void Load(ContainerBuilder builder) { base.Load(builder); var assembliesToScan = this.assembliesToScan as Assembly[] ?? this.assembliesToScan.ToArray(); var allTypes = assembliesToScan .Where(a => !a.IsDynamic && a.GetName().Name != nameof(AutoMapper)) .Distinct() // avoid AutoMapper.DuplicateTypeMapConfigurationException .SelectMany(a => a.DefinedTypes) .Where(w => w.IsAssignableFrom(typeof(IProfile)))//默认继承IProfile,排除不需要configuration的实例 .ToArray(); var openTypes = new[] { typeof(IValueResolver<,,>), typeof(IMemberValueResolver<,,,>), typeof(ITypeConverter<,>), typeof(IValueConverter<,>), typeof(IMappingAction<,>) }; foreach (var type in openTypes.SelectMany(openType => allTypes.Where(t => t.IsClass && !t.IsAbstract && ImplementsGenericInterface(t.AsType(), openType)))) { builder.RegisterType(type.AsType()).InstancePerDependency(); } //configuration配置 builder.Register<IConfigurationProvider>(ctx => new MapperConfiguration(cfg => { cfg.AddMaps(assembliesToScan); cfg.AllowNullCollections = true;//允许空集合 }) ); builder.Register<IMapper>(ctx => new Mapper(ctx.Resolve<IConfigurationProvider>(), ctx.Resolve)).InstancePerDependency(); } private static bool ImplementsGenericInterface(Type type, Type interfaceType) => IsGenericType(type, interfaceType) || type.GetTypeInfo().ImplementedInterfaces.Any(@interface => IsGenericType(@interface, interfaceType)); private static bool IsGenericType(Type type, Type genericType) => type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == genericType; } }
这种做法呢,其实就是遍历程序集,把程序集中注册过映射关系的类型都Configuration掉,另外我等下要说的第二种做法来说就是直接用在MapperConfiguration注册映射类。
上面写好之后 需要在AutofacRegister中加入一句话,放在builder.RegisterType<TestC>().As<ITestC>().AsImplementedInterfaces();后面就好了。
builder.RegisterModule(new AutoMapperRegister(Assembly.Load("WEBAPI.Autofac.AutoMapper.Demo")));
接下测试
using AutoMapper; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Http; using WEBAPI.Autofac.AutoMapper.Demo.Models; namespace WEBAPI.Autofac.AutoMapper.Demo.Controllers { [RoutePrefix("api/Mapper")] public class MapperController:ApiController { readonly IMapper _mapper; public MapperController(IMapper mapper) { _mapper = mapper; } [HttpGet] [Route("Get")] public IHttpActionResult Get() { //初始化一些数据 var test = new TestModel() { Age = 1, Name = "zero" }; var dto= _mapper.Map<TestModelDto>(test); return this.Json(dto); } } }
康康效果
映射成功。
接下来是第二种方法,第二种其实是我在研究这个的过程中的发现的一种方式,其实也没啥把,理解了就都知道了。
为了省时间我就直接贴代码了。
using Autofac; using Autofac.Integration.WebApi; using AutoMapper; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Web.Compilation; using System.Web.Http; using WEBAPI.Autofac.AutoMapper.Demo.Concreate; using WEBAPI.Autofac.AutoMapper.Demo.Interfacs; using WEBAPI.Autofac.AutoMapper.Demo.Models; using WEBAPI.Autofac.AutoMapper.Demo.Profiles; namespace WEBAPI.Autofac.AutoMapper.Demo.App_Start { public class AutofacRegister { public static void Register() { //初始化容器 var builder = new ContainerBuilder(); /* * 把我们的测试类放到容器中 */ builder.RegisterType<TestA>().As<ITestA>().AsImplementedInterfaces(); builder.RegisterType<TestB>().As<ITestB>().AsImplementedInterfaces(); builder.RegisterType<TestC>().As<ITestC>().AsImplementedInterfaces(); //automapper配置 //builder.RegisterModule(new AutoMapperRegister(Assembly.Load("WEBAPI.Autofac.AutoMapper.Demo"))); builder.Register<IMapper>(r => { var mapperConfiguration = new MapperConfiguration(c => { c.AddProfile(new TestProfile());//刚刚我们注册的Profile类。 }); mapperConfiguration.AssertConfigurationIsValid(); return new Mapper(mapperConfiguration); }); //获取global配置 var configuration = GlobalConfiguration.Configuration; //注册控制器 builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); //创建容器 var container = builder.Build(); //将DI解析程序设置为autofac configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container); } } }
测试一下,避免翻车。
这两种方式其实明眼就能看出差别,第一种更加适合项目,第二种更倾向于做测试,主要我每次写好Profile类之后我还需要去注册一下,其实是不够方便的。