autofac解析Mvc和Webapi的坑
我们在项目中很早就开始使用autofac,也以为知道与mvc和webapi集成的做法。

var builder = new ContainerBuilder(); // Mvc Register
builder.RegisterControllers(Assembly.GetExecutingAssembly()).AsSelf().PropertiesAutowired();
builder.RegisterFilterProvider();
builder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope(); //WebApi Register
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).AsSelf().PropertiesAutowired();
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
builder.RegisterWebApiModelBinderProvider(); var container = builder.Build(); // Set the dependency resolver for Web API.
var webApiResolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = webApiResolver; // Set the dependency resolver for MVC.
var resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);

在实际Controller和ApiController中通过构造函数注入,这不必多说。
但是,在实际项目需求的时候,有些地方不方便使用构造函数,或者说就要使用服务定位IContainer.Resolve(ServiceType)的方式来获得服务的实例。
曾经在项目中看到过有人通过把Container设区全局静态变量来获得对象容器。这个方式在Local的情况下,不会有太大问题。在Mvc中,容器DependencyResolver.Current本身也是通过尽量变量来实现的。

public class DependencyResolver
{
public DependencyResolver(); public static IDependencyResolver Current { get; }
...
}

但是和C端不同的是,Web服务是基于请求的,autofac内部的InstancePerLifetimeScope,InstancePerHttpRequest,InstancePerApiRequest等都是基于每次请求的Scope,而静态的Container明显生命周期不符合。
所以我们写代码的时候都是通过DependencyResolver.Current.GetService()和GlobalConfiguration.Configuration.DependencyResolver.GetService()来分别获取Mvc和WebApi的对象。那么问题来了,我有一段业务逻辑在BLL中,Mvc和WebApi可以都调用到,其中需要Resolve一个服务,那么如何来指定容器呢?
带着问题,我们先来看看DependencyResolver.Current和GlobalConfiguration.Configuration.DependencyResolver,通过一组实验来对比一下:

public class WebApiApplication : System.Web.HttpApplication
{
public static System.Web.Mvc.IDependencyResolver mvcResolver;
public static System.Web.Http.Dependencies.IDependencyResolver apiResolver; protected void Application_Start()
{
...
builder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope();
// Set the dependency resolver for Web API.
var webApiResolver = new AutofacWebApiDependencyResolver(container);
apiResolver = webApiResolver;
GlobalConfiguration.Configuration.DependencyResolver = webApiResolver; // Set the dependency resolver for MVC.
var resolver = new AutofacDependencyResolver(container);
mvcResolver = resolver;
DependencyResolver.SetResolver(mvcResolver);
}
}
public interface IUserService
{
} public class UserService : IUserService
{
}

我们分别定义了两个静态变量mvcResolver和apiResolver来存储两个不同的容器,并注册了一组服务,指定其生命周期为InstancePerLifetimeScope,先看看Mvc的容器

public class HomeController : Controller
{
IUserService _userservice; public HomeController(IUserService userService)
{
_userservice = userService;
var a = DependencyResolver.Current.GetService<IUserService>();
var b = WebApiApplication.mvcResolver.GetService<IUserService>();
var c1 = ReferenceEquals(userService, a); //true
var c2 = ReferenceEquals(userService, b); //true
var c3 = ReferenceEquals(b, a); //true
}
}

我们在HomeContorller中通过三种不同方法来获取对象,目的是三个对象都应该是同一个对象,结果也符合预期,再看看WebApi的:

public class ValuesController : ApiController
{
IUserService _userservice; public ValuesController(IUserService userService)
{
_userservice = userService;
var a = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUserService));
var b = WebApiApplication.apiResolver.GetService(typeof(IUserService));
var c1 = ReferenceEquals(userService, a); //false
var c2 = ReferenceEquals(userService, b); //false
var c3 = ReferenceEquals(b, a); //true
}
}

发现通过GlobalConfiguration.Configuration.DependencyResolver来获取的对象,竟然不等于构造函数解析出来的对象,有点毁三观。说明它并不是当前上下文的对象,也就是说这个对象的生命周期不在控制范围内。
那么Mvc和WebApi可不可以用同一个容器来指定呢?
我们先来看看stackoverflow上的这篇文章:Is it possible to configure Autofac to work with ASP.NET MVC and ASP.NET Web Api
其实Mvc和WebApi分别是两个独立的依赖解析器,这点没什么问题,一个是System.Web.Mvc.IDependencyResolver另一个是System.Web.Http.Dependencies.IDependencyResolver,两个互相不串。
最后,一个很重要的对象来了,那就是Autofac.IComponentContext,它就是解析的上下文,通过它来解析的对象是符合当前上下文的,我们再来看看之前的例子:

public class HomeController : Controller
{
IUserService _userservice; public HomeController(IUserService userService, IComponentContext com)
{
_userservice = userService;
var a = DependencyResolver.Current.GetService<IUserService>();
var b = WebApiApplication.mvcResolver.GetService<IUserService>();
var d = com.Resolve<IUserService>();
var d1 = ReferenceEquals(userService, d); //true
var c1 = ReferenceEquals(userService, a); //true
var c2 = ReferenceEquals(userService, b); //true
var c3 = ReferenceEquals(b, a); //true
}
}

WebApi:

public class ValuesController : ApiController
{
IUserService _userservice; public ValuesController(IUserService userService, IComponentContext com)
{
_userservice = userService;
var a = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IUserService));
var b = WebApiApplication.apiResolver.GetService(typeof(IUserService));
var d = com.Resolve<IUserService>();
var d1 = ReferenceEquals(userService, d); //true
var c1 = ReferenceEquals(userService, a); //false
var c2 = ReferenceEquals(userService, b); //false
var c3 = ReferenceEquals(b, a); //true
}
}

autofac解析Mvc和Webapi的坑的更多相关文章
- 转:autofac在mvc和webapi集成的做法
本文转自:http://www.cnblogs.com/Hai--D/p/5992573.html var builder = new ContainerBuilder(); // Mvc Regis ...
- Autofac 同时支持MVC 与Webapi
1.引用 using Autofac; using Autofac.Integration.Mvc; using Autofac.Integration.WebApi; 2.在Global中的Appl ...
- AutoFac mvc和WebAPI 注册Service (接口和实现)
AutoFac mvc和WebAPI 注册Service (接口和实现) 1.准备组件版本:Autofac 3.5.0 Autofac.Integration.Mvc 3.3.0.0 (I ...
- AutoFac在MVC中的使用
在asp.net mvc控制器中使用Autofac来解析依赖 如下Controller中使用构造函数依赖注入接口IUserService: public IUserService _IUserServ ...
- 【半小时大话.net依赖注入】(下)详解AutoFac+实战Mvc、Api以及.NET Core的依赖注入
系列目录 上|理论基础+实战控制台程序实现AutoFac注入 下|详解AutoFac+实战Mvc.Api以及.NET Core的依赖注入 前言 本来计划是五篇文章的,每章发个半小时随便翻翻就能懂,但是 ...
- SlickOne -- 基于Dapper, Mvc和WebAPI 的快速开发框架
前言:在两年前,项目组推出了基于Dapper,Mvc和WebApi的快速开发框架,随着后续Slickflow产品的实践和应用,今再次对SlickOne项目做以回顾和总结.其目的是精简,持续改进,保持重 ...
- 也说Autofac在MVC的简单实践:破解在Controller构造函数中的实例化 - winhu
相信大家对Autofac并不陌生,很多人都在使用.本文只是介绍一下本人在使用时的一点想法总结. 在使用一个框架时,肯定要去它的官网查阅一下.autofac的官网给出了一些经典的使用案例.如注册容器: ...
- 记一次autofac+dapper+mvc的框架搭建实践
1,环境 .net framework4.7.2,Autofac,Autofac.Mvc5,sql server 2,动机 公司项目用的是ef,之前留下代码的大哥,到处using,代码没有分层,连复用 ...
- SlickOne敏捷开发框架介绍(一) -- 基于Dapper, Mvc和WebAPI 的快速开发框架
前言:在两年前(最初发布时间:2013年1月9日(csdn),当前文章时间2015年11月10日),项目组推出了基于Dapper,Mvc和WebApi的快速开发框架,随着后续Slickflow产品的实 ...
随机推荐
- Linux/CentOS关闭图形界面(X-window)和启用图形界面命令
1.在图像界面关闭x window:1.1 shell中运行 init 3 进入文本模式,同时会关闭相关的服务(Xserver 肯定关闭)1.2 Alt+Ctrl+F1~F6到字符界面,root登陆 ...
- 【驱动】DM9000网卡驱动分析
Preface 内核源码版本:linux-2.6.18 网卡驱动·linux内核网络分层结构:http://infohacker.blog.51cto.com/6751239/122114 ...
- pre 标签的使用注意事项
.news-msg{ // padding: 5px; white-space: pre-wrap; word-wrap: break-word; font-family:'微软雅黑'; } < ...
- Mybatis根据配置文件获取session(多数据源)
1.config.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configura ...
- 系统清理工具CCleaner被植入后门
概述 2017年9月18日,有情报披露,著名的系统优化工具CCleaner的某个版本被发现植入后门,大量使用该工具的用户恐将面临泄密风险.这是继Xshell后门事件后,又一起严重的软件供应链来源攻击事 ...
- 使用一层神经网络训练mnist数据集
import numpy as np import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_dat ...
- css优化建议
1.不要使用过小的图片做背景平铺.这就是为何很多人都不用 1px 的原因,这才知晓.宽高 1px 的图片平铺出一个宽高 200px 的区域,需要 200*200=40, 000 次,占用资源. 2.无 ...
- Linux给tomcat指定jdk
在安装jenkins的时候,发现必须是jdk1.8,所以就只能单独安装一个tomcat,在给tomcat配置jdk1.8了,以免破坏以前的项目 安装就不多说了.这里需要修改两个配置文件: 安装的tom ...
- MySQL5.7 添加用户、删除用户与授权
mysql -uroot -proot MySQL5.7 mysql.user表没有password字段改 authentication_string: 一. 创建用户: 命令:CREATE USER ...
- PHP写的一个轻量级的DI容器类(转)
理解什么是Di/IoC,依赖注入/控制反转.两者说的是一个东西,是当下流行的一种设计模式.大致的意思就是,准备一个盒子(容器),事先将项目中可能用到的类扔进去,在项目中直接从容器中拿,也就是避免了直接 ...