前言
自從幾年前拋棄wcf,使用web api 來做服務器端開發(fā)之后,就不再迷惑了。但是因為本來從事傳統(tǒng)行業(yè)管理軟件開發(fā),一般都以分布式應用開發(fā)為主。純BS還是比較少,于是比較喜歡用windows service來宿主web api。發(fā)現這種場景網上文章還是比較少。這次就結合最近的技術嘗試(DI、IOC),整體介紹一下這方面的實踐。
名詞解釋
依賴注入:
依賴倒置原則 A.高層次的模塊不應該依賴于低層次的模塊,他們都應該依賴于抽象。B.抽象不應該依賴于具體實現,具體實現應該依賴于抽象。 DI—Dependency Injection,即“依賴注入”:組件之間依賴關系由容器在運行期決定,形象的說,即由容器動態(tài)的將某個依賴關系注入到組件之中。依賴注入的目的并非為軟件系統(tǒng)帶來更多功能,而是為了提升組件重用的頻率,并為系統(tǒng)搭建一個靈活、可擴展的平臺。通過依賴注入機制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業(yè)務邏輯,而不需要關心具體的資源來自何處,由誰實現。
理解DI的關鍵是:“誰依賴誰,為什么需要依賴,誰注入誰,注入了什么”,那我們來深入分析一下:
●誰依賴于誰:當然是應用程序依賴于IoC容器;
●為什么需要依賴:應用程序需要IoC容器來提供對象需要的外部資源;
●誰注入誰:很明顯是IoC容器注入應用程序某個對象,應用程序依賴的對象;
●注入了什么:就是注入某個對象所需要的外部資源(包括對象、資源、常量數據)。
控制反轉:控制反轉即IoC (Inversion of Control),它把傳統(tǒng)上由程序代碼直接操控的對象的調用權交給容器,通過容器來實現對象組件的裝配和管理。所謂的“控制反轉”概念就是對組件對象控制權的轉移,從程序代碼本身轉移到了外部容器。 我綁架了一個人質,對圍觀的警察說:我要一輛紅色法拉利,才能釋放人質。但其實我只是希望要一輛車而已。要法拉利很容易被拒絕,還可能引起很嚴重的后果。如果我說要一輛車,那么警察估計更容易給我一輛普通車... 在軟件開發(fā)里面的就是盡量使用接口對象,而不使用具體明確的對象(依賴外部注入的接口對象),以此達到解除耦合的目的。哎我自己也理解得不深刻,其實我要說的是:owin+web api+autofac.上面的解釋是我抄的,理解不了就算了吧。后面這些總該知道什么東西吧。
開發(fā)工具和包
IDE: VS2015
Package:
1234567891011121314151617181920212223 | <? xml version="1.0" encoding="utf-8"?> < packages > < package id="Autofac" version="4.4.0" targetFramework="net45" /> < package id="Autofac.Owin" version="4.0.0" targetFramework="net45" /> < package id="Autofac.WebApi2" version="4.0.1" targetFramework="net45" /> < package id="Autofac.WebApi2.Owin" version="4.0.0" targetFramework="net45" /> < package id="EntityFramework" version="6.1.3" targetFramework="net45" /> < package id="EntityFramework.zh-Hans" version="6.1.3" targetFramework="net45" /> < package id="LitJson" version="0.7.0" targetFramework="net45" /> < package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net45" /> < package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net45" /> < package id="Microsoft.AspNet.WebApi.Owin" version="5.2.3" targetFramework="net45" /> < package id="Microsoft.AspNet.WebApi.OwinSelfHost" version="5.2.3" targetFramework="net45" /> < package id="Microsoft.Owin" version="3.0.1" targetFramework="net45" /> < package id="Microsoft.Owin.Host.HttpListener" version="3.0.1" targetFramework="net45" /> < package id="Microsoft.Owin.Hosting" version="3.0.1" targetFramework="net45" /> < package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" /> < package id="Owin" version="1.0" targetFramework="net45" /> < package id="System.Data.SQLite" version="1.0.104.0" targetFramework="net45" /> < package id="System.Data.SQLite.Core" version="1.0.104.0" targetFramework="net45" /> < package id="System.Data.SQLite.EF6" version="1.0.104.0" targetFramework="net45" /> < package id="System.Data.SQLite.Linq" version="1.0.104.0" targetFramework="net45" /> </ packages > |
targetFramework:net45,注意一下運行時是4.5以上,也是說服務程序必須在win7 sp1以上的操作系統(tǒng)才能運行。
編碼細節(jié)和要點
1、windows服務宿主web api
1234567891011121314151617181920212223242526272829303132333435363738 | //protected override public new void OnStart( string [] args) { try { string middleware_url = string .Join( "" , new string [] { "http://" , MiddlewareIP, ":" , MiddlewarePort }); hostObject = WebApp.Start<Startup>(middleware_url); if (hostObject != null ) Com.DataCool.DotNetExpand.LogHelper.Info( "中間件宿主WebApi成功,URL:" + middleware_url); else Com.DataCool.DotNetExpand.LogHelper.Error( "中間件宿主WebApi錯誤!" ); string result = HttpAPIRequest(); if (! string .IsNullOrEmpty(result)) Com.DataCool.DotNetExpand.LogHelper.Info(result); } catch (Exception ex) { Com.DataCool.DotNetExpand.LogHelper.Error(ex); } IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0); EndPoint epSender = (EndPoint)ipeSender; serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 首次探測時間5 秒, 間隔偵測時間2 秒 byte [] inValue = new byte [] { 1, 0, 0, 0, 0x88, 0x13, 0, 0, 0xd0, 0x07, 0, 0 }; serverSocket.IOControl(IOControlCode.KeepAliveValues, inValue, null ); IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(MiddlewareIP), 5880); try { serverSocket.Bind(ipEndPoint); serverSocket.Listen(1024); socketThread = new Thread(ListenClientConnect); socketThread.Start(); } catch (Exception ex) { Com.DataCool.DotNetExpand.LogHelper.Error( "服務啟動失敗,原因:" + ex.Message); } } |
其實就一句話:hostObject = WebApp.Start<Startup>(middleware_url);這個Startup是用來配置web api的路由規(guī)則和實現autofac初始流程的。
123456789101112131415161718192021222324252627282930313233343536 | public class Startup { public void Configuration(IAppBuilder appBuilder) { HttpConfiguration config = new HttpConfiguration(); //自定義路由 config.Routes.MapHttpRoute( name: "CustomApi" , routeTemplate: "api/{controller}/{action}/{id}" , defaults: new { id = RouteParameter.Optional } ); //規(guī)范api格式僅僅支持XML var xmlFormatter = new XmlMediaTypeFormatter(); config.Services.Replace( typeof (IContentNegotiator), new XmlContentNegotiator(xmlFormatter)); var builder = new ContainerBuilder(); //注冊本程序集內的ApiControllers builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); //內置日志服務注冊 builder.Register(c => new ServiceLog()).As<IServiceLog>().InstancePerRequest(); var iServices = Assembly.Load( "Van.Interface" ); var services = Assembly.Load( "Van.Service" ); //根據名稱約定(服務層的接口和實現均以Service結尾),實現服務接口和服務實現的依賴 builder.RegisterAssemblyTypes(iServices, services) .Where(t => t.Name.EndsWith( "Service" )) .AsImplementedInterfaces(); var container = builder.Build(); config.DependencyResolver = new AutofacWebApiDependencyResolver(container); appBuilder.UseAutofacMiddleware(container); appBuilder.UseAutofacWebApi(config); appBuilder.UseWebApi(config); } } |
請看一下注釋,友情提示本篇文章的“高潮“部分就在這里,任何解釋都是蒼白的。哈哈哈...
2、使用注入的接口對象
http://www.cnblogs.com/datacool/p/datacool_2017_webapi_owin_autofac.html