标签:handle net ram target thread 处理 github values .net
将OWIN App部署在IIS上
要想将Owin App部署在IIS上,只添加Package:Microsoft.OWIN.Host.SystemWeb包即可。它提供了所有Owin配置,Middleware注册等方面的Api.我们需要做的其实和SelfHost差不多。
SystemWeb其实是实现了一个OwinHttpModule来根据MiddleWare的需求注册IIS的各种事件,然后执行相关的Middleware.
先看一下IIS集成模式的HttpRequest处理的管道模型。
我们的Middleware运行在IIS管道中哪个环节是通过调用appBuilder.UseStageMarker(PipelineStage.Authenticate);这个扩展方法来定义的。其中PipelineState有如下可选值:
public enum PipelineStage { Authenticate = 0, PostAuthenticate = 1, Authorize = 2, PostAuthorize = 3, ResolveCache = 4, PostResolveCache = 5, MapHandler = 6, PostMapHandler = 7, AcquireState = 8, PostAcquireState = 9, PreHandlerExecute = 10, }
以上枚举值对应IIS管道中的对应环节。Stage的指定有如下规则:
1. 默认的Stage为PreHandlerExecute
2. 每次UseStageMaker的调用指定了该次调用与前一次调用之间的注册的Middleware均在该次UseStageMaker中指定的Stage中运行
3. Stage的指定顺序应该与IIS管道的处理顺序一致
4. 如果Stage的指定顺序与IIS管道处理顺序不一致,在后面指定的在IIS管道中靠前的Stage会覆盖在其前面指定的在IIS管道中靠后的Stage.
听上去有点绕口。其实理解了原因和实现就容易理解了。这种规则的原因是:IIS管道是有固定顺序的,而OWIN中Middleware的执行也是按照注册的先后顺序的,而当OWIN部署在IIS中时Middleware的执行又是依赖与IIS管道事件的,所以只有当指定的Stage顺序与IIS管道顺序一致时才不会有冲突。
为Web Api添加Authenticate OWIN Middleware
我们首先创建一个普通的web api工程,添加如下接口,然后部署在IIS上。
[RoutePrefix("api/persons")] public class PersonController : ApiController { [Route("{id}")] [Authorize] // GET api/values/5 public string Get(int id) { return "Jensen"; } }
这时候如果去访问该接口会得到401未授权的错误。
接下来通过添加AuthMiddleware来作为WebApi验证模块。
首先添加AuthenticateMiddleware
public class AuthenticateMiddleware { private Func<IDictionary<string, object>, Task> nextAppFunc; public AuthenticateMiddleware(Func<IDictionary<string, object>, Task> nextMiddleWareFunc) { nextAppFunc = nextMiddleWareFunc; } public async Task Invoke(IDictionary<string, object> parameters) { Trace.WriteLine("Auth Middleware"); Trace.WriteLine(HttpContext.Current.CurrentNotification); var identity = new GenericIdentity("jensen"); parameters["server.User"] = new GenericPrincipal(identity, new string[] { "admin" }); if (nextAppFunc != null) { await nextAppFunc.Invoke(parameters); } } }
然后添加Startup类来注册AuthenticateMiddleware,并指定运行Stage为Authenticate.
[assembly: OwinStartup(typeof(OwinIISHost.Startup))] namespace OwinIISHost { public class Startup { public void Configuration(IAppBuilder appBuilder) { appBuilder.Use<AuthenticateMiddleware>(); appBuilder.UseStageMarker(PipelineStage.Authenticate); } } }
这样当我们再次访问前面定义的api时,就能得到期望的结果了。因为在AuthenticateMiddleware中我们对所有请求都通过了验证。
这里一开始有点疑问,WebApi中是根据HttpContext.User来获取当前请求的用户信息的。但是我们在AuthenticateMiddleware中并没有直接给HttpContext.User赋值,而是将User信息赋值到key 为server.user的OWIN环境参数中。这中间有个断档。通过查看SystemWeb Package的源码,解答了我的疑问。
首先,我们的Middleware中接收到的OWIN环境参数类型为AspNetDictionary,可以查看其实现:
internal AspNetDictionary(IPropertySource propertySource)//构造函数,这里propertySource由外部传入 { _propertySource = propertySource; } object IDictionary<string, object>.this[string key]//索引属性,我们设置User信息给server.user key时该方法会被调用 { get { object value; return PropertiesTryGetValue(key, out value) ? value : Extra[key]; } set { if (!PropertiesTrySetValue(key, value)) { StrongExtra[key] = value; } } } private bool PropertiesTrySetValue(string key, object value) { switch (key.Length) { //....ignore some code here case 11: if (string.Equals(key, "server.User", StringComparison.Ordinal)) { ServerUser = (IPrincipal)value;//赋值给ServerUser属性 return true; } break; //...ignore some code here } return false; } internal IPrincipal ServerUser { get { return _propertySource.GetServerUser(); } set { _propertySource.SetServerUser(value);//最后还是调了propertySource的SetServerUser方法 } }
那现在关键就看_propertySource是如何实现的了。通过查看创建AspNetDictionary的代码发现_propetySource为OwinCallContext类型的实例。看看它对SetServerUser的实现:
void AspNetDictionary.IPropertySource.SetServerUser(IPrincipal value) { _httpContext.User = value;//真相大白,其实当我们给server.User key赋值时,value其实直接就赋给了HttpContext。 Thread.CurrentPrincipal = value; }
参考:
AspNetKatana源码,包含SystemWebPackage
为IIS Host ASP.NET Web Api添加Owin Middleware
标签:handle net ram target thread 处理 github values .net
原文地址:http://www.cnblogs.com/Code-life/p/7467318.html