摘要:本文目的是了解Owin基本原理。講述如何從控制台建立一個自宿主的OwinHost,然後再編寫一兩個中間件
準備工作
首先通過VisualStudio建立一個控制台應用
然後添加Owin的Nuget包引用
需要的包如下
Owin
Microsoft.Owin
Microsoft.Owin.Hosting
Microsoft.Owin.Host.HttpListener
準備工作到此結束
編寫OwinStartup類
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Run(HandleRequest);
}
static Task HandleRequest(IOwinContext context)
{
context.Response.ContentType = "text/plain";
return context.Response.WriteAsync("Hello world from myOwin");
}
}
當OwinHost運作時,會首先加載Startup類,
Configuration
方法是必須有的,在
Configuration
方法中向Owin管道插入中間件,所有的請求都是中間件處理。
在這個
Configuration
中
app.Run(HandleRequest);
方法的作用是向管道中添加一個沒有後續中間件的中間件,一般來講一個Owin管道中有許多中間件,不同的中間件處理不同的事情,在處理結束後選擇性的調用後面的中間件,例如某個身份驗證中間件可以在驗證失敗時結束請求。而
app.Run
方法就是插如一個沒有後續事項的中間件。稍後我們會編寫正常的中間件。
這個中間件做的事很簡單,就是向響應寫入一個字元串,無論請求是什麼結果都是一樣的。
在Main方法中啟動Host
static void Main(string[] args)
{
var url = "http://localhost:8080/";
var opt = new StartOptions(url);
using (WebApp.Start<Startup>(opt))
{
Console.WriteLine("Server run at " + url + " , press Enter to exit.");
Console.ReadLine();
}
}
StartOptions
類用來指定一些啟動參數,最少應該指定一個url,這裡一并指定了使用8080端口
啟動程式控制台輸出如下
Server run at http://localhost:8080/ , press Enter to exit.
用浏覽器打開
http://localhost:8080/效果如下:
`Hello world from myOwin`
嘗試更改路徑你得到的始終是一個結果
你可以嘗試将
Configuration
中的代碼注釋掉,在運作程式,這是通路将得到空頁面,Http代碼也将是404,因為Owin管道中沒有中間件處理請求。
編寫中間件
我們編寫一個名為Ding的中間件
public class DingMiddleware : OwinMiddleware
{
public DingMiddleware(OwinMiddleware next) : base(next)
{
}
public override Task Invoke(IOwinContext context)
{
if (context.Request.Path.Value.Equals("/home/index"))
{
context.Response.Write("hello world from home/index");
}
if (Next != null)
{
return Next.Invoke(context);
}
return Task.CompletedTask;
}
}
這個中間件在檢測到通路路徑是
/home/index
時向Response中寫入一句話,然後檢測是否有下一個中間件,如果有就調用。
添加中間件到 Configuration
Configuration
可以直接在
Configuration
中加入
app.Use<DingMiddleware>()
來插入中間件,但是我們一般使用擴充方法來做這件事。
public static class MyMidlewareExtention
{
public static IAppBuilder UseDing(this IAppBuilder app)
{
return app.Use<DingMiddleware>();
}
}
修改
Configuration
中的代碼:
public void Configuration(IAppBuilder app)
{
app.UseDing();
app.Run(HandleRequest);
}
現在管道中有兩個中間件了,現在運作程式,在位址欄中輸入
http://localhost:8080/home/index
将得到如下結果
hello world from home/indexHello world from myOwin
因為Ding中間件在處理之後繼續調用了接下來的中間件
輸入其他路徑将得到
Hello world from myOwin
這個結果
如果将
Configuration
中的兩個中間件位置調換,的到的結果隻有一個
Hello world from myOwin
,因為
app.Run(HandleRequest);
不執行後續的中間件。
第二個中間件
public class DiDiDiMiddleware : OwinMiddleware
{
public DiDiDiMiddleware(OwinMiddleware next) : base(next)
{
}
public override Task Invoke(IOwinContext context)
{
if (context.Request.QueryString.Value == "boom")
{
context.Response.Write("Boom! Boom! Boom!");
return Task.CompletedTask;
}
if (Next != null)
{
return Next.Invoke(context);
}
return Task.CompletedTask;
}
}
這個中間件在位址欄QueryString(?後邊的部分)等于boom時結束請求。
MyMidlewareExtention
代碼修改如下:
public static class MyMidlewareExtention
{
public static IAppBuilder UseDing(this IAppBuilder app)
{
return app.Use<DingMiddleware>();
}
public static IAppBuilder UseDiDiDi(this IAppBuilder app)
{
return app.Use<DiDiDiMiddleware>();
}
}
Startup
類修改如下:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseDiDiDi();
app.UseDing();
}
}
這裡去掉了
app.Run
此時,對于非
/home/index
的請求會得到404,是以我們暫時改動下代碼将
HandleRequest
方法封裝成一個預設的中間件
代碼改動如下:
public class DefaultMiddleware : OwinMiddleware
{
public DefaultMiddleware(OwinMiddleware next) : base(next)
{
}
public override Task Invoke(IOwinContext context)
{
var path = context.Request.Path.Value;
context.Response.Write($"hey you come from {path}!");
return Task.CompletedTask;
}
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseDiDiDi();
app.UseDing();
app.UseDefault();
}
}
運作程式觀察結果是否符合預期。
當位址中含有?boom時會的到一個Boom!Boom!Boom!
總結:Owin的管道概念其實簡單易懂,在程式啟動之前,向裡面插入中間件,中間件決定請求是否繼續向下走。在管道中的中間件可以拿到請求的所有資訊以對請求進行處理,管道裡的中間件執行結束之後,這個請求就被處理完成了,然後發回浏覽器。