使用 OWIN 作為 ASP.NET Web API 的宿主
ASP.NET Web API 是一種框架,用於輕松構建可以訪問多種客戶端(包括瀏覽器和移動 設備)的 HTTP 服務。 ASP.NET Web API 是一種用於在 .NET Framework 上構建 RESTful 應用程序的理想平台。
ASP.NET Web API 是 OWIN 兼容的, 因此可以在 OWIN 服務器上運行。
接下來使用 Xamarin Studio 創建一個 OWIN 兼容的 C# 類庫, 也就是 OWIN 中定義的“應 用 (Application)” , 然后在不同的 OWIN 服務器/宿主上運行。
創建 OWIN 兼容的 Web API 類庫
打開 Xamarin Studio, 新建一個 C# 類庫項目, 如下圖:
然后向項目中添加 Microsoft.AspNet.WebApi.Owin
包, 相關依賴的包會自動添加,
最終項目依賴的包如下表, 如果沒有在 packages.config 文件中列出, 可以再次手工添 加上去。
- Microsoft.AspNet.WebApi.Client
- Microsoft.AspNet.WebApi.Core
- Microsoft.AspNet.WebApi.Owin
- Microsoft.Owin
- Newtonsoft.Json
- Owin
我們的目的是創建 OWIN 兼容的 Web API 應用, 自然要先添加一個 OWIN 約定的 Startup 類, 來配置我們的 OWIN 應用。
向項目中添加一個 Startup 類 , 代碼如下:
public class Startup { public void Configuration(IAppBuilder appBuilder) { // 創建 Web API 的配置 var config = new HttpConfiguration(); // 啟用標記路由 config.MapHttpAttributeRoutes(); // 默認的 Web API 路由 config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); // 將路由配置附加到 appBuilder appBuilder.UseWebApi(config); } }
按照 Web API 項目的約定, 在項目中添加一個名稱為 Controllers 的文件夾, 然后新建 一個 ValuesController 類, 設置其基類為 System.Web.Http.ApiController , 作為示 例, 其內容與 Visual Studio 自帶的 Web API Controller 模板一致, 如下所示:
public class ValuesController : ApiController { // GET api/values public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // GET api/values/5 public string Get(int id) { return "value"; } // POST api/values public void Post([FromBody]string value) { } // PUT api/values/5 public void Put(int id, [FromBody]string value) { } // DELETE api/values/5 public void Delete(int id) { } }
在 OWIN 環境下運行 Web API
OWIN 目前有兩個比較成熟的服務器:
- Katana 微軟的 OWIN 服務器, 如果沒有指定 OWIN 服務器, 則作為默認的 OWIN 服務器。
- Nowin 社區版 OWIN 服務器, 純 C# 實現, 可以運行在 .NET 和 Mono 運行。
使用 Katana 服務器運行
在 Katana 下運行 OWIN 應用是很容易的, 新建一個命令行程序項目, 項目名稱為: Owin02_WebApi_Katana , 然后向項目中添加下面的 NuGet 包:
- Microsoft.AspNet.WebApi.Client
- Microsoft.AspNet.WebApi.Core
- Microsoft.AspNet.WebApi.Owin
- Microsoft.AspNet.WebApi.OwinSelfHost
- Microsoft.Owin
- Microsoft.Owin.Host.HttpListener
- Microsoft.Owin.Hosting
- Newtonsoft.Json
- Owin
在默認的 Program.cs 文件的 Main 方法中, 添加下面的代碼:
public static void Main(string[] args) { var baseAddress = "http://localhost:9000/"; var startOpts = new StartOptions(baseAddress) { // katana http listener ServerFactory = "Microsoft.Owin.Host.HttpListener" }; using (WebApp.Start<Owin02_WebApi.Startup>(startOpts)) { var client = new HttpClient { BaseAddress = new Uri(baseAddress, UriKind.Absolute) }; var requestTask = client.GetAsync("api/values"); requestTask.Wait(); var response = requestTask.Result; Console.WriteLine(response); var readTask = response.Content.ReadAsStringAsync(); readTask.Wait(); Console.WriteLine(readTask.Result); Console.ReadLine(); } }
現在運行 Owin02_WebApi_Katana 項目, 命令行顯示如下:
也可以通過瀏覽器來訪問 http://localhost:9000/api/values
, 得到的結果如下:
使用 Nowin 服務器運行
OWIN 兼容的應用可以在任何 OWIN 服務器上運行, 下面就看看如何在 Nowin 上運行。
最簡單的方法是將上面代碼中 StartOptions 的 ServerFactory 屬性設置為 Nowin , 然 后在添加 Nowin 包就可以運行了:
var baseAddress = "http://localhost:9000/"; var startOpts = new StartOptions(baseAddress) { // Nowin ServerFactory = "Nowin" };
不過這樣會依賴包 Microsoft.Owin.Hosting
, 其實 Nowin 自身也提供了 Hosting 的 功能, 下面就看如何直接從 Nowin 啟動。
新建一個 C# 命令行程序, 項目名稱為 Owin02_WebApi_Nowin , 添加下面的 NuGet 包:
- Microsoft.Owin
- Nowin
- Owin
向 Program.cs 文件中的 Main 方法添加下面的代碼:
public static void Main(string[] args) { var appBuilder = new AppBuilder(); Nowin.OwinServerFactory.Initialize(appBuilder.Properties); var startup = new Owin02_WebApi.Startup(); startup.Configuration(appBuilder); var builder = new ServerBuilder(); var ip = "127.0.0.1"; var port = 8888; builder.SetAddress(System.Net.IPAddress.Parse(ip)).SetPort(port) .SetOwinApp(appBuilder.Build()) .SetOwinCapabilities((IDictionary<string, object>)appBuilder.Properties[OwinKeys.ServerCapabilitiesKey]); using (var server = builder.Build()) { Task.Run(() => server.Start()); var baseAddress = "http://" + ip + ":" + port + "/"; Console.WriteLine("Nowin server listening " + baseAddress); var client = new HttpClient { BaseAddress = new Uri(baseAddress, UriKind.Absolute) }; var requestTask = client.GetAsync("api/values"); requestTask.Wait(); var response = requestTask.Result; Console.WriteLine(response); var readTask = response.Content.ReadAsStringAsync(); readTask.Wait(); Console.WriteLine(readTask.Result); Console