Asp.Net MVC<九>:OWIN,关于StartUp.cs

https://msdn.microsoft.com/zh-cn/magazine/dn451439.aspx (Katana 项目入门)html

一不当心写了个WEB服务器git

快刀斩乱麻之 Katanagithub

OWIN知识

OWIN的全称是Open Web Interface For .Net。web

OWIN提供的只是一种规范,而没有具体实现。其目的是在web服务器和应用程序组件之间隔离出一个抽象层,使它们之间解耦。json

应用程序委托和环境字典

OWIN将服务器与应用程序之间的交互减小到一小部分类型和单个函数签名,这个函数签名被称为应用程序委托(即 AppFunc):api

using AppFunc = Func<IDictionary<string, object>, Task>;

基于 OWIN 的应用程序中的每一个组件都向服务器提供应用程序委托。 而后,这些组件连接成一个管道,基于 OWIN 的服务器将会向该管道推送请求。 服务器

 

一个符合OWIN的web服务器,须要将请求信息(应用程序状态、请求状态和服务器状态等全部相关信息)包装到一个字典里(应用程序委托上指定的 IDictionary<string, object>,这种数据结构称为环境字典),从而使得许多不一样的框架和组件做者能够在一个 OWIN 管道中进行互操做,而没必要强制实施对特定 .NET 对象模型的协议。数据结构

虽然任何键/值数据均可以插入到环境字典中,但 OWIN 规范为某些 HTTP 核心元素定义了键: 架构

key value
"owin.RequestBody" 一个带有请求正文(若是有)的流。若是没有请求正文,Stream.Null 能够用做占位符。
"owin.RequestHeaders" 请求标头的 IDictionary<string, string[]>。
"owin.RequestMethod" 一个包含请求的 HTTP 请求方法的字符串(例如 GET 和 POST)。
"owin.RequestPath" 一个包含请求路径的字符串。 此路径必须是应用程序委托的“根”的相对路径。
"owin.RequestPathBase" 一个字符串,包含对应于应用程序委托的“根”的请求路径部分。
"owin.RequestProtocol" 一个包含协议名称和版本的字符串(例如 HTTP/1.0 或 HTTP/1.1)。
"owin.RequestQueryString" 一个字符串,包含 HTTP 请求 URI 的查询字符串组成部分,不带前导“?”(例如 foo=bar&baz=quux)。 该值能够是空字符串。
"owin.RequestScheme" 一个字符串,包含用于请求的 URI 方案(例如 HTTP 或 HTTPS)。

随着请求在OWIN管道中流动,每一个中间件(Middleware,集成到管道中的组件或应用程序)所要作的就是读取、修改这个字典的数据。最后,Web服务器获得这个层层处理过的字典,而后输出网页到客户端。app

 

与ASP.NET管道相比,OWIN规范很是简洁,且并无引用.Net Framework中的System.Web.dll。

   1. 新的组件可以很是简单的开发和应用
   2. 程序可以简便地在host和OS上迁移

Katana

Katana 项目是 Microsoft 建立和推出的基于 OWIN 的组件和框架集合。

https://katanaproject.codeplex.com

但上面这个项目最后一次提交是15年1月

目前它的托管代码已经被拆分:

New 'Katana' Source:

Katana 体系结构

 

  • 主机:运行应用程序的进程,能够是从 IIS 或独立可执行文件到您本身的自定义程序的任何内容。 主机负责启动、加载其余 OWIN 组件和正常关闭。
  • 服务器:负责绑定到 TCP 端口,构造环境字典和经过 OWIN 管道处理请求。
  • 中间件:这是为处理 OWIN 管道中的请求的全部组件指定的名称。 它能够是从简单压缩组件到 ASP.NET Web API 这样的完整框架,不过从服务器的角度而言,它只是一个公开应用程序委托的组件。
  • 应用程序:这是您的代码。 因为 Katana 并不取代 ASP.NET,而是一种编写和托管组件的新方式,所以现有的 ASP.NET Web API 和 SignalR 应用程序将保持不变,由于这些框架能够参与 OWIN 管道。 事实上,对于这些类型的应用程序,Katana 组件只需使用一个小的配置类便可见。

在体系结构方面,Katana 能够按其中每一个层都可以轻松替代的方式分解,一般不须要从新生成代码。 在处理 HTTP 请求时,各个层一块儿工做,方式相似于下图中所示的数据流。

————

使用IIS作Host和Server

首先创建一个空的web应用程序。由于默认的 Katana 主机会在此 /bin 文件夹中查找程序集。而Web应用程序默认会将编译的程序集直接放在 /bin 文件夹而不是 /bin/debug 文件夹中。

删除无关文件,引入OWIN的支持包

添加Startup启动类

Startup类的做用是用来初始化OWIN管道,这里,咱们添加和初始化OWIN管道中的Middleware.

 在Startup.Configuration方法中,添加以下代码:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // New code:
        app.Run(context =>
        {
            context.Response.ContentType = "text/plain";
            return context.Response.WriteAsync("Hello, world."+ context.Request.Uri);
        });
    }
}

上面的代码作的事情,就是把一个简单的Middleware注册到OWIN管道中。

其中context的类型是IOwinContext:

public interface IOwinContext
{
    //     Gets the Authentication middleware functionality available on the current request.
    IAuthenticationManager Authentication { get; }

    //     Gets the OWIN environment.
    IDictionary<string, object> Environment { get; }

    //     Gets a wrapper exposing request specific properties.
    IOwinRequest Request { get; }

    //     Gets a wrapper exposing response specific properties.
    IOwinResponse Response { get; }

    //     Gets or sets the host.TraceOutput environment value.
    TextWriter TraceOutput { get; set; }

    //     Gets a value from the OWIN environment, or returns default(T) if not present.
    T Get<T>(string key);

    //     Sets the given key and value in the OWIN environment.
    IOwinContext Set<T>(string key, T value);
}

 运行结果:

 如图 能够顺利解析到不一样的访问Url,天然也就能够在后续的处理中作出不一样的处理,直接分支处理或读取静态文件或者实现MVC架构等等……。

改用其余形式的Host和Server

上例中IIS同时充当了Host和Server的角色, 

首先建立一个简单的Console应用程序,用Nuget添加Microsoft.Owin.SelfHost

 

以一样的方式添加Startup启动类

将控制台程序改造为Host

class Program
{
    static void Main(string[] args)
    {
        using (Microsoft.Owin.Hosting.WebApp.Start<Startup1>("http://localhost:9000"))
        {
            Console.WriteLine("Press [enter] to quit...");
            Console.ReadLine();
        }
    }
}

运行结果:

Startup类

不管使用IIS, IIS Express仍是OWIN Host, 微软在这些Host上实现的Service都会依照特定的规则来寻找到Startup类,执行Configuration方法,注册Middleware。

默认名称匹配
能够定义Startup.cs类,只要这个类的namespace和Assembly的名称相同。那么,这个Startup.cs中的Configuration方法,就会在OWIN管道初始化的时候执行。

使用OwinStartup Attribute
直接指定哪一个具体类是Startup类。

在配置文件的appSetting 节点设置

<appSettings>  
  <add key="owin:appStartup" value="StartupDemo.ProductionStartup" />
</appSettings>

路由配置

protected void Application_Start(object sender, EventArgs e)
{
     // Registers a route for the default OWIN application.
     RouteTable.Routes.MapOwinPath("/owin");
	 // Invokes the System.Action startup delegate to build the OWIN application and
     // then registers a route for it on the given path.
     RouteTable.Routes.MapOwinPath("/special", app =>
     {
         app.Run(OwinApp2.Invoke);
     });
} 
public class OwinApp2
{
    // Invoked once per request.
    public static Task Invoke(IOwinContext context)
    {
        context.Response.ContentType = "text/plain";
        return context.Response.WriteAsync("Hello World 2");
    }
}

自定义Middleware

经过继承OwinMiddleware基类能够便捷地新建中间件:

public class HelloWorldMiddleware : OwinMiddleware
{
   public HelloWorldMiddleware(OwinMiddleware next) : base(next)
   {
   }

   public override Task Invoke(IOwinContext context)
   {
       var response = "Hello World! It is " + DateTime.Now;
       context.Response.Write(response);
       return Next.Invoke(context);
   }
}

注册:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Use<HelloWorldMiddleware>();
    }
} 

 

应用

ASP.NET Web Form,ASP.NET MVC5项目结合OWIN

因为ASP.NET Web Form和ASP.NET MVC5依赖于System.Web.dll中的不少类型,而在OWIN管道中,是没法提供这些依赖的。因此ASP.NET Web Form和ASP.NET MVC5不能做为一个中间件直接集成到OWIN管道中。

但在这些项目中,也能够添加Startup.cs, 指定成为OWIN的初始化类型,那么请求会先通过OWIN管道处理,最后转向ASP.NET Web Form或者ASP.NET MVC程序。这种方式,经常用来配置log, authentication, cache等等这些Middleware。

引入OWIN后的管道执行顺序

Web API做为Middleware注册到OWIN管道中

Web API因为无任何依赖于System.web.dll, 因此能够做为Middleware注册到OWIN管道中。

public class Startup
{
    // Invoked once at startup to configure your application.
    public void Configuration(IAppBuilder builder)
    {
        HttpConfiguration config = new HttpConfiguration();
        config.Routes.MapHttpRoute("Default", "api/{controller}/{customerID}", new { controller = "Customer", customerID = RouteParameter.Optional });//定义web api route
        //xml格式输出结果 
        config.Formatters.XmlFormatter.UseXmlSerializer = true;

        config.Formatters.Remove(config.Formatters.JsonFormatter);
        // config.Formatters.JsonFormatter.UseDataContractJsonSerializer = true;
        //将web api以Middleware注册到OWIN管道中
        builder.UseWebApi(config);
    }
}

ASP.NET 5

ASP.NET 5中终于去System.web.dll化,MVC,Web API都统一在了OWIN管道中。

ASP.NET 5 的 project.json 配置文件(Microsoft.Owin改作Microsoft.AspNet 了):

ASP.NET 5 中Startup.cs 的两个重要方法:

// This method gets called by the runtime.
public void ConfigureServices(IServiceCollection services)
{
    // Add EF services to the services container.
    services.AddEntityFramework(Configuration)
        .AddSqlServer()
        .AddDbContext<ApplicationDbContext>();

    // Add Identity services to the services container.
    services.AddDefaultIdentity<ApplicationDbContext, ApplicationUser, IdentityRole>(Configuration);

    // Add MVC services to the services container.
    services.AddMvc();

    // Uncomment the following line to add Web API servcies which makes it easier to port Web API 2 controllers.
    // You need to add Microsoft.AspNet.Mvc.WebApiCompatShim package to project.json
    // services.AddWebApiConventions();
}

// Configure is called after ConfigureServices is called.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
    // Configure the HTTP request pipeline.
    // Add the console logger.
    loggerfactory.AddConsole();

    // Add the following to the request pipeline only in development environment.
    if (string.Equals(env.EnvironmentName, "Development", StringComparison.OrdinalIgnoreCase))
    {
        app.UseBrowserLink();
        app.UseErrorPage(ErrorPageOptions.ShowAll);
        app.UseDatabaseErrorPage(DatabaseErrorPageOptions.ShowAll);
    }
    else
    {
        // Add Error handling middleware which catches all application specific errors and
        // send the request to the following path or controller action.
        app.UseErrorHandler("/Home/Error");
    }

    // Add static files to the request pipeline.
    app.UseStaticFiles();

    // Add MVC to the request pipeline.
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller}/{action}/{id?}",
            defaults: new { controller = "Home", action = "Index" });

        // Uncomment the following line to add a route for porting Web API 2 controllers.
        // routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
    });
}

  ConfigureServices 在运行时的时候被运行,Configure 运行在 ConfigureServices 以后,查看 ConfigureServices 中的 Add 方法注释,你会发现最后一个单词老是 container(容器),这是怎么回事呢,其实就是往Ioc容器中注入类型依赖的对象,这些类型对象的管理都是在 Owin 管道中的,你只须要在 ConfigureServices 中使用 Add 方法注册相应模块就能够了,其余的东西 ASP.NET 5 会帮你完成,而 Configure 是什么做用呢?我本身以为它是配置模块的一个“配置”,用户你使用中间件或者应用程序的一个配置,好比,你使用 app.UseCookieAuthentication 进行配置用户验证的一些操做,你查看 UseCookieAuthentication 的定义,会发现其命名空间为 Microsoft.AspNet.Builder.CookieAuthenticationExtensions,所在程序集为 CookieAuthenticationExtensions(Owin 中间件),查看 Configure 中其余 Use 使用,你一样会发现命名空间都是 Microsoft.AspNet.Builder 开头,以前说 Owin 是一种协定,Extensions 就是一种中间件和应用程序的扩展,但都必须符合此协定,这样才会有无限可能。

相关文章
相关标签/搜索