1. 程式人生 > >OWIN 自宿主模式WebApi專案,WebApi層作為單獨類庫供OWIN呼叫

OWIN 自宿主模式WebApi專案,WebApi層作為單獨類庫供OWIN呼叫

為什麼我們需要OWIN

過去,IIS作為.NET開發者來說是最常用的Web Server(沒有之一),源於微軟產品的緊耦合關係,我們不得不將Website、Web Application、Web API等部署在IIS上,事實上在2010年前並沒有什麼不妥,但隨著近些年來Web的發展,特別是移動網際網路飛速發展,IIS作為Web Server已經暴露出他的不足了。主要體現在兩個方面,ASP.NET (System.Web)緊耦合IIS,IIS緊耦合OS,這就意味著,我們的Web Framework必須部署在微軟的作業系統上,難以跨平臺。 ... OWIN是什麼?在本文裡面就不進行贅述,網上有很多介紹OWIN的資訊以及優缺點的博文,這裡可以給幾個連結大家進行自行參考: .. 下面我們重點介紹我在搭建OWIN自宿主平臺的過程,對於我是學習的過程,對於想要接觸他的大家來說,也是一種幫助。 很多人搭建的OWIN+WebApi專案都是寫在一個專案中的,我個人為了程式碼的隔離,將控制器層寫在了另外一個專案中,這樣有助於後期大型框架的形成。 下面是搭建步驟: 1、首先新建一個控制檯應用程式和一個.NETFramework類庫專案,控制檯引用類庫專案。 專案結構如下圖所示:

OWIN.WebApi WebApi層

OWIN.WebApi.Sv WebApi服務層,將要作為啟動項!

2、控制檯專案使用NuGet引用需要的類庫:   OWIN   Microsoft.Owin.Hosting   Microsoft.Owin.Host.HttpListener   Microsoct.AspNet.WebApi.Owin   這裡需要手動從WebApi專案裡面找到System.Web.Web,System.Net.Http等Web類庫進行引用。   OWIN.WebApi.Srv層的引用情況(我這裡有跨域配置,不需要的請忽略)      在OWIN.WebApi層,我們需要同樣引用Web的類庫,我們才可以在WebApi專案控制器層繼承自ApiController     OWIN.WebApi層的引用情況(我這裡有跨域配置,不需要的請忽略)   
 3、因為WebApi層要分開類庫專案寫,所以這裡比一般的OWIN要多一些配置,在我專案的OWIN.WebApi層的config目錄下,我新建了一個Global.cs類,裡面的程式碼是對控制器的解析,程式碼展示如下: 複製程式碼
  1 using System.Web.Http;
  2 using System.Web.Http.Dispatcher;
  3 using System;
  4 using System.Collections.Concurrent;
  5 using System.Collections.Generic;
  6 using System.Linq;
  7
using System.Net; 8 using System.Net.Http; 9 using System.Web.Http.Controllers; 10 11 namespace OWIN.WebApi.config 12 { 13 public class WebApiApplication : System.Web.HttpApplication 14 { 15 protected void Application_Start() 16 { 17 //ignore the xml return it`s setting let json return only 18 GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 19 GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter); 20 21 GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), 22 new WebApiControllerSelector(GlobalConfiguration.Configuration)); 23 } 24 } 25 /// <summary> 26 /// the WebApiControllerSelector 27 /// author:qixiao 28 /// time:2017-1-31 19:24:32 29 /// </summary> 30 public class WebApiControllerSelector : DefaultHttpControllerSelector 31 { 32 private const string NamespaceRouteVariableName = "Namespace"; 33 private readonly HttpConfiguration _configuration; 34 private readonly Lazy<ConcurrentDictionary<string, Type>> _apiControllerCache; 35 36 public WebApiControllerSelector(HttpConfiguration configuration) 37 : base(configuration) 38 { 39 _configuration = configuration; 40 _apiControllerCache = new Lazy<ConcurrentDictionary<string, Type>>( 41 new Func<ConcurrentDictionary<string, Type>>(InitializeApiControllerCache)); 42 } 43 44 private ConcurrentDictionary<string, Type> InitializeApiControllerCache() 45 { 46 IAssembliesResolver assembliesResolver = this._configuration.Services.GetAssembliesResolver(); 47 var types = this._configuration.Services.GetHttpControllerTypeResolver() 48 .GetControllerTypes(assembliesResolver).ToDictionary(t => t.FullName, t => t); 49 50 return new ConcurrentDictionary<string, Type>(types); 51 } 52 53 public IEnumerable<string> GetControllerFullName(HttpRequestMessage request, string controllerName) 54 { 55 object namespaceName; 56 var data = request.GetRouteData(); 57 IEnumerable<string> keys = _apiControllerCache.Value.ToDictionary<KeyValuePair<string, Type>, string, Type>(t => t.Key, 58 t => t.Value, StringComparer.CurrentCultureIgnoreCase).Keys.ToList(); 59 60 if (!data.Values.TryGetValue(NamespaceRouteVariableName, out namespaceName)) 61 { 62 return from k in keys 63 where k.EndsWith(string.Format(".{0}{1}", controllerName, 64 DefaultHttpControllerSelector.ControllerSuffix), StringComparison.CurrentCultureIgnoreCase) 65 select k; 66 } 67 68 string[] namespaces = (string[])namespaceName; 69 return from n in namespaces 70 join k in keys on string.Format("{0}.{1}{2}", n, controllerName, 71 DefaultHttpControllerSelector.ControllerSuffix).ToLower() equals k.ToLower() 72 select k; 73 } 74 75 public override HttpControllerDescriptor SelectController(HttpRequestMessage request) 76 { 77 Type type; 78 if (request == null) 79 { 80 throw new ArgumentNullException("request"); 81 } 82 string controllerName = this.GetControllerName(request); 83 if (string.IsNullOrEmpty(controllerName)) 84 { 85 throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound, 86 string.Format("No route providing a controller name was found to match request URI '{0}'", new object[] { request.RequestUri }))); 87 } 88 IEnumerable<string> fullNames = GetControllerFullName(request, controllerName); 89 if (fullNames.Count() == 0) 90 { 91 throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound, 92 string.Format("No route providing a controller name was found to match request URI '{0}'", new object[] { request.RequestUri }))); 93 } 94 95 if (this._apiControllerCache.Value.TryGetValue(fullNames.First(), out type)) 96 { 97 return new HttpControllerDescriptor(_configuration, controllerName, type); 98 } 99 throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound, 100 string.Format("No route providing a controller name was found to match request URI '{0}'", new object[] { request.RequestUri }))); 101 } 102 } 103 }
複製程式碼

4、在OWIN.WebApi.Srv層裡面新建AppStart.cs類,並且寫如下程式碼:

複製程式碼
 1 using Microsoft.Owin.Hosting;
 2 using System;
 3 using Owin;
 4 using System.Web.Http;
 5 using System.Web.Http.Dispatcher;
 6 using QX_Frame.App.WebApi.Extends;
 7 using System.Web.Http.Cors;
 8 
 9 namespace OWIN.WebApi.Srv
10 {
11     class AppStart
12     {
13         static void Main(string[] args)
14         {
15             //string baseAddress = "http://localhost:3999/";    //localhost visit
16             string baseAddress = "http://+:3999/";              //all internet environment visit  
17             try
18             {
19                 WebApp.Start<StartUp>(url: baseAddress);
20                 Console.WriteLine("BaseIpAddress is " + baseAddress);
21                 Console.WriteLine("\nApplication Started !");
22             }
23             catch (Exception ex)
24             {
25                 Console.WriteLine(ex.ToString());
26             }
27 
28             for (;;)
29             {
30                 Console.ReadLine();
31             }
32         }
33     }
34     //the start up configuration
35     class StartUp
36     {
37         public void Configuration(IAppBuilder appBuilder)
38         {
39             HttpConfiguration config = new HttpConfiguration();
40 
41             // Web API configuration and services
42             //跨域配置 //need reference from nuget
43             config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
44             //enabing attribute routing
45             config.MapHttpAttributeRoutes();
46             // Web API Convention-based routing.
47             config.Routes.MapHttpRoute(
48                 name: "DefaultApi",
49                 routeTemplate: "api/{controller}/{id}",
50                 defaults: new { id = RouteParameter.Optional },
51                 namespaces: new string[] { "OWIN.WebApi" }
52             );
53             config.Services.Replace(typeof(IHttpControllerSelector), new OWIN.WebApi.config.WebApiControllerSelector(config));
54 
55             //if config the global filter input there need not write the attributes
56             //config.Filters.Add(new App.Web.Filters.ExceptionAttribute_DG());
57 
58             //new ClassRegisters(); //register ioc menbers
59 
60             appBuilder.UseWebApi(config);
61         }
62     }
63 }
複製程式碼

裡面對地址進行了配置,當然可以根據需求自行配置,顯示資訊也進行了適當的展示,需要說明的一點是,我這裡進行了跨域的配置,沒有配置或者是不需要的請註釋掉並忽略!

這裡需要注意的是第53行,這裡引用的是剛才的OWIN.WebApi層的Global.cs裡面的類,請對照上述兩段程式碼進行查詢。

這行是關鍵,有了這行,程式才可以掃描到WebApi層的Controller。好了,我們進行Controller的書寫。 5、在OWIN.WebApi層進行控制器類的編寫,這裡隨意,我只在這裡列出我的例子。 複製程式碼
 1 using QX_Frame.App.WebApi;
 2 using QX_Frame.Helper_DG;
 3 using System.Web.Http;
 4 
 5 namespace OWIN.WebApi
 6 {
 7     /*
 8      * author:qixiao
 9      * time:2017-2-27 10:32:57
10      **/
11     public class Test1Controller:ApiController
12     {
13         //access http://localhost:3999/api/Test1  get method
14         public IHttpActionResult GetTest()
15         {
16             //throw new Exception_DG("login id , pwd", "argumets can not be null", 11111, 2222);
17             return Json(new { IsSuccess = true, Msg = "this is get method" });
18         }
19         //access http://localhost:3999/api/Test1  post method
20         public IHttpActionResult PostTest(dynamic queryData)
21         {
22             return Json(new { IsSuccess = true, Msg = "this is post method",Data=queryData });
23         }
24         //access http://localhost:3999/api/Test1  put method
25         public IHttpActionResult PutTest()
26         {
27             return Json(new { IsSuccess = true, Msg = "this is put method" });
28         }
29         //access http://localhost:3999/api/Test1  delete method
30         public IHttpActionResult DeleteTest()
31         {
32             return Json(new { IsSuccess = true, Msg = "this is delete method" });
33         }
34     }
35 }
複製程式碼

這裡我是用的是RESTFull風格的WebApi控制器介面。

 然後我們可以進行試執行:

服務啟動成功!

測試通過,我們可以盡情地探索後續開發步驟!