OWIN 自宿主模式WebApi項目,WebApi層做爲單獨類庫供OWIN調用

OWIN是Open Web Server Interface for .NET的首字母縮寫,他的定義以下:html

OWIN在.NET Web Servers與Web Application之間定義了一套標準接口,OWIN的目標是用於解耦Web Server和Web Application。基於此標準,鼓勵開發者開發簡單、靈活的模塊,從而推動.NET Web Development開源生態系統的發展。

爲何咱們須要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項目都是寫在一個項目中的,我我的爲了代碼的隔離,將控制器層寫在了另一個項目中,這樣有助於後期大型框架的造成。
下面是搭建步驟:
一、首先新建一個控制檯應用程序和一個.NETFramework類庫項目,控制檯引用類庫項目。
項目結構以下圖所示:

OWIN.WebApi WebApi層git

OWIN.WebApi.Sv WebApi服務層,將要做爲啓動項!github

二、控制檯項目使用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層的引用狀況(我這裏有跨域配置,不須要的請忽略)
  
 三、由於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 }

四、在OWIN.WebApi.Srv層裏面新建AppStart.cs類,而且寫以下代碼:json

 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 }

裏面對地址進行了配置,固然能夠根據需求自行配置,顯示信息也進行了適當的展現,須要說明的一點是,我這裏進行了跨域的配置,沒有配置或者是不須要的請註釋掉並忽略!api

這裏須要注意的是第53行,這裏引用的是剛纔的OWIN.WebApi層的Global.cs裏面的類,請對照上述兩段代碼進行查找。跨域

這行是關鍵,有了這行,程序才能夠掃描到WebApi層的Controller。好了,咱們進行Controller的書寫。
五、在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控制器接口。app

 而後咱們能夠進行試運行:框架

服務啓動成功!ide

測試經過,咱們能夠盡情地探索後續開發步驟!oop

 

該項目源代碼GitHub地址:https://github.com/dong666/AHelloDotNet_DG (10-Code文件夾內)

相關文章
相關標籤/搜索