OWIN support for the Web API 2 and MVC 5 integrations in Autofac
Currently, in the both the Web API and MVC frameworks, dependency injection support does not come into play until after the OWIN pipeline has started executing. This is simply a result of the OWIN support being added to both frameworks after their initial release. In fact, the OWIN support in MVC does not yet extend to the self hosting scenario and is limited to plugging in OWIN middleware.
I had two primary objectives when creating these new OWIN packages for Autofac:
- Extend the Autofac lifetime scope from the OWIN pipeline into the MVC and Web API integrations
- Make dependency injection avaialable to OWIN middleware components
Due to the somewhat fragmented nature of the DI support in the ASP.NET stack, achieving this goal required a bit of trickery and black magic. For that reason the packages are currently pre-release and marked as alpha. Hopefully you can pull them from NuGet and help test them out.
Enabling DI for OWIN middleware
Lets start with a service interface for a logging dependency...
public interface ILogger
{
void Write(string message, params object[] args);
}
...along with its rather unimaginative implementation (just imagine something more interesting).
public class Logger : ILogger
{
public void Write(string message, params object[] args)
{
Debug.WriteLine(message, args);
}
}
To enable dependency injection for OWIN middleware derive from OwinMiddleware
as usual, and add any additional constructor dependencies after the constructor parameter for the next middleware in the chain. In the example below we are adding the ILogger
dependency to the middleware.
public class LoggerMiddleware : OwinMiddleware
{
private readonly ILogger _logger;
public LoggerMiddleware(OwinMiddleware next, ILogger logger) : base(next)
{
_logger = logger;
}
public override async Task Invoke(IOwinContext context)
{
_logger.Write("Inside the 'Invoke' method of the 'LoggerMiddleware' middleware.");
foreach (var pair in context.Environment)
_logger.Write("Key: {0}, Value: {1}", pair.Key, pair.Value);
await Next.Invoke(context);
}
}
To wire this up we have to register the middleware and its dependencies with the container, and then enable the middleware dependency injection support via a call to UseAutofacMiddleware
. This call should be the first piece of middleware registered with the IAppBuilder
.
var builder = new ContainerBuilder();
builder.RegisterType<LoggerMiddleware>().InstancePerApiRequest();
builder.Register(c => new Logger()).As<ILogger>().InstancePerLifetimeScope();
app.UseAutofacMiddleware(container);
This particular extension method is included in the Autofac.Owin
package which is shared by the Autofac.WebApi2.Owin
and Autofac.Mvc5.Owin
packages. You would not normally use this package by itself because of the second role the shared package plays. Not only is it responsible for adding middleware dependency injection support, it also creates an Autofac ILifetimeScope
instance for each request early in the OWIN pipeline. You can access this lifetime scope using the GetAutofacLifetimeScope
method on IOwinContext
. The OWIN packages for the Web API and MVC integrations use this method to access the lifetime scope and make it available further along in the request.
Extending the lifetime scope to Web API
To enable the lifetime scope created during the OWIN request to extend into the Web API dependency scope call the UseAutofacWebApi
method.
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(GlobalConfiguration.Configuration);
This will add a DelegatingHandler
which extracts the ILifetimeScope
from the IOwinContext
. Once it has a hold of the ILifetimeScope
an AutofacWebApiDependencyScope
is created and added into the appropriate HttpRequestMessage
property that Web API expects the IDependencyScope
to be available from. The code below shows this task being performed during the SendAsync
method of the handler.
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request == null) throw new ArgumentNullException("request");
var owinContext = request.GetOwinContext();
if (owinContext == null) return base.SendAsync(request, cancellationToken);
var lifetimeScope = owinContext.GetAutofacLifetimeScope();
if (lifetimeScope == null) return base.SendAsync(request, cancellationToken);
var dependencyScope = new AutofacWebApiDependencyScope(lifetimeScope);
request.Properties[HttpPropertyKeys.DependencyScope] = dependencyScope;
return base.SendAsync(request, cancellationToken);
}
Notice that we still made a call to UseAutofacMiddleware
. This is required because along with enabling the middleware DI support, this is also responsible for placing the lifetime scope in the OWIN context. I'm not totally happy with this dual responsibility but it does reduce the API surface area and means less IAppBuilder
extensions are required. For now, if you don't want to use middleware DI support, don't register your middleware with the container.
Extending the lifetime scope to MVC
To enable the lifetime scope created during the OWIN request to extend into the MVC request call the UseAutofacMvc
method on your IAppBuilder
instance.
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
Just like with Web API we need to ensure that UseAutofacMiddleware
has been called first. You only need to call this method once, even when using both the MVC and Web API integrations together. Remember, the call to UseAutofacMiddleware
should be made as early as possible during the bootstrapping process.
In the MVC middleware we are also retrieving the ILifetimeScope
from the IOwinContext
, but in this case we are placing it in the HttpContext
as is expected by the MVC integration. The code below shows this process directly implemented in a middleware method.
public static IAppBuilder UseAutofacMvc(this IAppBuilder app)
{
return app.Use(async (context, next) =>
{
var lifetimeScope = context.GetAutofacLifetimeScope();
var httpContext = CurrentHttpContext();
if (lifetimeScope != null && httpContext != null)
httpContext.Items[typeof(ILifetimeScope)] = lifetimeScope;
await next();
});
}
In case you are wondering, CurrentHttpContext
is an internal property that returns a HttpContextBase
allowing for mocking of the HTTP context during unit testing.
NuGet Packages
As mentioned earlier the packages are currently pre-release, so don't forget the -Pre
switch on the command line, or the Include Prerelease
option in the GUI. Please report any issues that you find on GitHub.
Autofac Web API OWIN Integration:
Install-Package Autofac.WebApi2.Owin -Pre
Autofac MVC 5 OWIN Integration:
Install-Package Autofac.Mvc5.Owin -Pre
Please note that you still need to configure the relevant dependency resolver for each integration: AutofacWebApiDependencyResolver
for Web API, and AutofacDependencyResolver
for MVC.
OWIN support for the Web API 2 and MVC 5 integrations in Autofac的更多相关文章
- 使用 OWIN 作为 ASP.NET Web API 的宿主
使用 OWIN 作为 ASP.NET Web API 的宿主 ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动 设备)的 HTTP 服务. ASP.NET ...
- 使用 OWIN Self-Host ASP.NET Web API 2
Open Web Interface for .NET (OWIN)在Web服务器和Web应用程序之间建立一个抽象层.OWIN将网页应用程序从网页服务器分离出来,然后将应用程序托管于OWIN的程序而离 ...
- ASP.NET Web API - ASP.NET MVC 4 系列
Web API 项目是 Windows 通信接口(Windows Communication Foundation,WCF)团队及其用户激情下的产物,他们想与 HTTP 深度整合.WCF ...
- web api .net C# mvc API返回XML文档的解析并取值
[HttpGet] public System.Net.Http.HttpResponseMessage GetNotify() { var xmlstring = @" <xml&g ...
- 购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(3)--Idetity,OWIN前后端验证
原文:购物车Demo,前端使用AngularJS,后端使用ASP.NET Web API(3)--Idetity,OWIN前后端验证 chsakell分享了前端使用AngularJS,后端使用ASP. ...
- Use OWIN to Self-Host ASP.NET Web API 2
Open Web Interface for .NET (OWIN)在Web服务器和Web应用程序之间建立一个抽象层.OWIN将网页应用程序从网页服务器分离出来,然后将应用程序托管于OWIN的程序 ...
- CORS support for ASP.NET Web API (转载)
CORS support for ASP.NET Web API Overview Cross-origin resource sharing (CORS) is a standard that al ...
- Asp.Net Web API VS Asp.Net MVC
http://www.dotnet-tricks.com/Tutorial/webapi/Y95G050413-Difference-between-ASP.NET-MVC-and-ASP.NET-W ...
- 关于 Web Api 2 认证与授权
认证与授权 认证与授权,Authentication and Authorize,这个是两个不同的事.认证是对访问身份进行确认,如验证用户名和密码,而授权是在认证之后,判断是否具有权限进行某操作,如 ...
随机推荐
- jQuery 图片等比缩放
$(function(){ $('.img-box img').load(function(){ var w = $(this).width(); var h =$(this).height(); i ...
- Elasticsearch 2.X 版本Java插件开发简述
1:elasticsearch插件分类简述 2:Java插件开发要点 3:如何针对不同版本elasticsearch提供多版本的插件 4:插件具有外部依赖时遇到的一些问题(2016-09-07更新) ...
- WordPress 博客文章时间格式the_time()设置
国外设计的WordPress 主题里的文章的时间格式是类似“十一月 21, 2010”这种格式的,而中国人习惯的是年在前,月紧跟其后,日在末尾,所以看国外的就显得很别扭,但是我们可以通过修改WP时间代 ...
- java的重写规则
重写不能破坏父类的访问性和逻辑结构性.对于异常重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常.但是可以抛出更少,更有限或者不抛出异常. 重写规则之一:重写方法不能比被重写方法限制 ...
- 【USACO 1.2】Palindromic Squares
进制转换,然后判断是否是回文 /******************************************* TASK: palsquare LANG: C++ Created Time: ...
- ARP协议工作流程
地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议.主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机, ...
- 解决不能访问远程mysql的问题
一般是没有给用户访问权限 给用户test_user授权,让他可以从外部登陆和本地登陆注意:@左边是用户名,右边是域名.IP和%,表示可以访问mysql的域名和IP,%表示外部任何地址都能访问. m ...
- 简进祥--iOS开发基础知识
1:App跳转至系统Settings 跳转在IOS8以上跟以下是有区别的,如果是IOS8以上可以如下设置: NSURL *url = [NSURL URLWithString:UIApplicatio ...
- CruiseControl.NET配置文件(生产环境版本,与SVN结合自动部署)
配置如下: 说明:此配置文件的功能是当有SVN修改时,会自动触发并编译发布,间隔为10秒. 由于配置文件上面有注释,如果提示节点配置错误,请删除这些注释. 官方详细节点配置说明:http://www. ...
- Spring MVC exception - Invoking request method resulted in exception : public static native long java.lang.System.currentTimeMillis()
最近在线上系统发现下面的异常信息: 2014-10-11 11:14:09 ERROR [org.springframework.web.servlet.mvc.annotation.Annotati ...