.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类之后我还需要去注册一下,其实是不够方便的。

 

posted @ 2020-07-11 15:12  飞天猪皮怪  阅读(1469)  评论(2编辑  收藏  举报