为什么我们需要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的信息以及优缺点的博文,这里可以给几个链接大家进行自行参考: 1、http://www.cnblogs.com/dudu/p/what-is-owin.html 2、http://blog.csdn.net/hk_5788/article/details/51607211 .. 下面我们重点介绍我在搭建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控制器接口。
然后我们可以进行试运行:
服务启动成功!
测试通过,我们可以尽情地探索后续开发步骤!