autofac本身只提供了基本的ioc容器的功能

要想在mvcwcfweb api中使用,除了autofac本身,还需要引入对应的包(点击对应连接可查看文档)

除此之外,使用Common Service Locator 也可以用aotofac来做真正的容器

为了说明下面的实例管理,先准备2个类

  1. public class ClassA
  2. {
  3. }
  4.  
  5. public class ClassB
  6. {
  7. public ClassB(ClassA a)
  8. {
  9. this.A = a;
  10. }
  11.  
  12. public ClassA A { get; set; }
  13. }

类A是一个最简单的类,类B有一个类A的属性

在global中构造ioc容器

  1. var builder = new ContainerBuilder();
  2.  
  3. builder.RegisterType<ClassA>();
  4. builder.RegisterType<ClassB>();
  5.  
  6. builder.RegisterControllers(Assembly.GetExecutingAssembly());
  7. builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
  8. var container = builder.Build();
  9.  
  10. DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
  11. GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

为了之后说明在mvc和web api中的使用,我们需要设置一些与mvc和web api有关的代码。详细的可以查看官方文档

controller中的也很简单

  1. private ClassA a;
  2. private ClassB b;
  3. public HomeController(ClassA a, ClassB b)
  4. {
  5. this.a = a;
  6. this.b = b;
  7. }
  8.  
  9. public ActionResult Index()
  10. {
  11. var instanceEqual = a == b.A;
  12. return Content(instanceEqual.ToString());
  13. }

在autofac的实例管理中(文档)。

最基本的(不做任何设置)为InstancePerDependency 也就是说,每个依赖,会创建一个新的实例

按照以上的代码,当在HomeController里需要ClassA的实例的时候,创建了一个新的,HomeController中还需要ClassB,此时会创建一个新的ClassB,而ClassB在创建时,也需要一个ClassA,当为InstancePerDependency的时候,ClassB需要的ClassA,是重新创建了一个ClassA的实例,而与HomeController中需要的那个,是不同的实例

可以看到,homecontroller中,a与b.A是不同的

另一种比较常用的实例管理方式为 Instance Per Lifetime Scope,意思是每一个生命周期内,只会存在一个。这个在UnitOfWork模式中是非常重要的

我们把ClassA的实例管理设置为仅一个

  1. builder.RegisterType<ClassA>().InstancePerLifetimeScope();

可以看到,此时两个引用是同一个实例

有时候,我们从容器中获取实例,不是用构造注入,属性注入等方式,而是直接从容器中获取

到目前为止,运行的方式与我们预期的是一样的。

下面说当引入Common Service Locator时的情况

Common Service Locator是微软定义的一个基础接口,各大ico容器提供了各自的实现

我们根据Autofac官方网站上的说明设置

  1. var csl = new AutofacServiceLocator(container);
  2. ServiceLocator.SetLocatorProvider(() => csl);

以上代码添加在global中

然后再controller里加入代码如下

  1. var insSL = ServiceLocator.Current.GetInstance<ClassA>();
  2. var insSLEqualA = insSL == a;
  3. var insSLEqualBa = insSL == b.A;

为了简化,直接在controller调用common service locator,其实这个在写组件时时很好用的一种手段。

在我们的预期中,通过common service locator获取到的应该也是同一个实例,他也根据设置的InstancePerLiefttimeScope起作用。

很遗憾,并不是一个.

通过查看autofac相关的源码,发现

当有一个新的request请求时,autofac会自动的创建一个lifetime scope

  1. /// <summary>
  2. /// Begin a new nested scope. Component instances created via the new scope
  3. /// will be disposed along with it.
  4. ///
  5. /// </summary>
  6. ///
  7. /// <returns>
  8. /// A new lifetime scope.
  9. /// </returns>
  10. ILifetimeScope BeginLifetimeScope();
  1.  
  1. 之后的容器,是这个ILifetimeScope,而不是builder.Build()处理的那个container
  1. 所以我们才可以通过DependencyResolver.Current取到正确的值。
  1. 而设置common service locator,我们给定的是固定的一个值,而这个值是根容器。
  1. 查看ServiceLocator的源码可以发现
  1. public static class ServiceLocator
  2. {
  3. private static ServiceLocatorProvider currentProvider;
  4.  
  5. /// <summary>
  6. /// The current ambient container.
  7. ///
  8. /// </summary>
  9. public static IServiceLocator Current
  10. {
  11. get
  12. {
  13. return ServiceLocator.currentProvider();
  14. }
  15. }
  16.  
  17. /// <summary>
  18. /// Set the delegate that is used to retrieve the current container.
  19. ///
  20. /// </summary>
  21. /// <param name="newProvider">Delegate that, when called, will return
  22. /// the current ambient container.</param>
  23. public static void SetLocatorProvider(ServiceLocatorProvider newProvider)
  24. {
  25. ServiceLocator.currentProvider = newProvider;
  26. }
  27. }
  1. ServiceLocatorProvider是一个委托,而每次访问Current时,去执行这个委托。
  1. 我们之前按照autofac的官方文档中的写法
  1. var csl = new AutofacServiceLocator(container);
  2. ServiceLocator.SetLocatorProvider(() => csl);
  1. 委托每次执行,返回的都是根容器,而不是与当前请求有关的ILifetimeScope
  1. 改造一些这个委托的写法
  1. var csl = new AutofacServiceLocator(container);
  2. ServiceLocator.SetLocatorProvider(() =>
  3. {
  4. var httpContext = HttpContext.Current;
  5. if (httpContext.CurrentHandler is MvcHandler)
  6. {
  7. return new AutofacServiceLocator(AutofacDependencyResolver.Current.RequestLifetimeScope);
  8. }
  9. return csl;
  10. });

如果是一个mvc请求,则使用当前的请求scope去设置common service locator

看到,从common service locator中获取的,也是同样的一个实例了。

mvc对应的LifetimeScope可以从AutofacDependencyResolver.Current.RequestLifetimeScope获取

wcf对应的可以从AutofacInstanceContext.Current获取

而web api的有些麻烦

目前我找到的方式是

  1. Request.GetDependencyScope().GetRequestLifetimeScope()

此处这个Request是ApiController里的那个Request属性,他的类型是HttpRequestMessage

在global里如果获得这个Request的实例呢

根据最新的release文档,我们可以发现,他提供了一个新的方法

  1. builder.RegisterHttpRequestMessage(GlobalConfiguration.Configuration);

此方法的意思是,我们可以通过容器来获取当前的request

但是尝试了很多种方法,都无法正确的从容器中把它获取出来。

不过到是给我们提供了一种思路,可以通过自己添加一个MessageHandler来把Request变得可以访问。

  1. public sealed class CommonServiceLocatorApiHandler : DelegatingHandler
  2. {
  3.     public HttpRequestMessage Request { get; private set; }
  4.  
  5.     protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
  6.     {
  7.         Request = request;
  8.         return base.SendAsync(request, cancellationToken);
  9.     }
  10. }

新建一个继承api的handler,把request保存下,用public公开出来

  1. GlobalConfiguration.Configuration.MessageHandlers.Add(new CommonServiceLocatorApiHandler());

把刚建的添加到handlers里

  1. var csl = new AutofacServiceLocator(container);
  2. ServiceLocator.SetLocatorProvider(() =>
  3. {
  4.     var httpContext = HttpContext.Current;
  5.     if (httpContext.CurrentHandler is MvcHandler)
  6.     {
  7.         return new AutofacServiceLocator(AutofacDependencyResolver.Current.RequestLifetimeScope);
  8.     }
  9.     else if(httpContext.CurrentHandler is HttpControllerHandler)
  10.     {
  11.         var handler =
  12.             GlobalConfiguration.Configuration.MessageHandlers.FirstOrDefault(
  13.                 x => x is CommonServiceLocatorApiHandler) as CommonServiceLocatorApiHandler;
  14.         if (handler != null)
  15.         {
  16.             return new AutofacServiceLocator(handler.Request.GetDependencyScope().GetRequestLifetimeScope());
  17.         }
  18.     }
  19.     return csl;
  20. });

autofac使用Common Serivce Locator跟随wcf,mvc,web api的实例控制的更多相关文章

  1. .net mvc web api Autofac依赖注入框架-戈多编程

    今天自己搭了一套基于三层的依赖注入mvc web api 的依赖注入框架,在此总结下相关配置 1.设置应用程序的.net Framework版本为 4.5 2.通过Nuget 安装autofac包 I ...

  2. mvc Web api 如何在控制器中调用

    关于如何调用 mvc Web api 的方法,网上一搜就是一大把,基本都是在前台jq中调用的,但是如何在后台调用呢? 本楼主做了一下测试,仅供参考. 先写一个简单的api,如下:[域1] namesp ...

  3. WCF、Web API、WCF REST、Web Service比较

    原文地址:http://www.dotnet-tricks.com/Tutorial/webapi/JI2X050413-Difference-between-WCF-and-Web-API-and- ...

  4. Difference between WCF and Web API and WCF REST and Web Service

    The .Net framework has a number of technologies that allow you to create HTTP services such as Web S ...

  5. ASP.NET MVC Web API Post FromBody(Web API 如何正确 Post)

    问题场景: ASP.NET MVC Web API 定义 Post 方法,HttpClient 使用 JsonConvert.SerializeObject 传参进行调用,比如 Web Api 中定义 ...

  6. ASP.NET MVC Web API For APP

    近来很多大型的平台都公开了Web API.比如百度地图 Web API,做过地图相关的人都熟悉.公开服务这种方式可以使它易于与各种各样的设备和客户端平台集成功能,以及通过在浏览器中使用 JavaScr ...

  7. WCF 、Web API 、 WCF REST 和 Web Service 的区别

    WCF .Web API . WCF REST 和 Web Service 的区别 The .Net framework has a number of technologies that allow ...

  8. 转 Difference between WCF and Web API and WCF REST and Web Service

    http://www.dotnet-tricks.com/Tutorial/webapi/JI2X050413-Difference-between-WCF-and-Web-API-and-WCF-R ...

  9. WCF、Web API、WCF REST、Web Service之区别

    http://www.dotnet-tricks.com/Tutorial/webapi/JI2X050413-Difference-between-WCF-and-Web-API-and-WCF-R ...

随机推荐

  1. “System.Runtime.InteropServices.COMException”类型的第一次机会异常在 System.Windows.Forms.dll 中发生

    最近做一个winform项目,在里面用了webbrowser控件进行html文档打印,遇到了标题所示问题.根据查到的一些资料,在调试>异常>查找中输入“System.Runtime.Int ...

  2. 解决使用ICsharpCode解压缩时候报错Size MisMatch4294967295;的错误

    如果是一个文件夹生成的zip文件,解压缩时候不会报错. 如果是一个文件夹里面包含着两个子文件夹,而且每个子文件夹里面都有着文件.生成的zip文件在解压时候就出报这个错误. 具体的解决办法,通过网上搜索 ...

  3. Unity的Shader如何控制投影颜色

    细节慢慢补充,有几个需要注意的地方,必须要有接收投影的pass也就是Name是ShadowCollector的,必须添加#pragma multi_compile_fwdbase,物体的着色器必须有T ...

  4. CentOS 7 - 安装Eclipse

    注意问题:Eclipse官方网站提供的tar文件有可能有问题,我今天下载的一个tar文件,在Windows下解压缩,随后放到CentOS 7里面不行,随后我又重新下载一份,还是不行,最终我下载了另外一 ...

  5. ubuntu 中 mongodb 数据读写权限配置

    首先,我们先对mongodb 数据库的权限做一点说明: 1 默认情况下,mongodb 没有管理员账号 2 只有在 admin 数据库中才能添加管理员账号并开启权限 3 用户只能在所在的数据库中登录, ...

  6. jmeter 中使用ServerAgen链接超时可能出错的原因之一ip不对

    因为我要压测的服务器是需要使用跳板机转发链接的,所以我开始用的是跳板机的IP+ServerAgen端口,发现连不通,实际上应该使用ServerAgen所在服务器的IP,如果:

  7. MYSQL NULL值特性

    NULL是一种“没有类型”的值,通常表示“无值”,“未知值”,“缺失值”,“超界”,“不在其中”等,我们在日常运用中很容易和NULL字符串混淆,这里大致整理了下NULL值的一些特性,以便能够正确使用N ...

  8. iOS开发总结--三方平台开发之微信支付

    1.前言 现在很多应用都有支付功能,支付也是开发中比较麻烦的一个部分.其实,最麻烦的部分是商户帐号的审核,如果没有商户帐号,就没有你要给钱的那个对公账户. 2.关于交易 在这个金融类项目的开发中,接触 ...

  9. WPF一步步开发XMPP IM客户端1:入门

    [起因&目标] 因为工作原因接触openfire服务端和spark客户端开发,主要是基于openfire扩展开发了针对企业用途的服务器插件,还开发了各个平台上的客户端(Windows\mac\ ...

  10. 2d旋转(css3实现过度效果和动画效果)

    效果: 源码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...