IIS是Windows平臺很是關鍵的組件,它是微軟自帶的Web服務器,能夠很方便的幫助咱們運行起一個網站,WebApi等服務,提供給外部來訪問。即便它被不少java或者ruby的同窗各類鄙視,被.Net平臺的同窗們吐槽性能很差,不夠靈活,部署受限等等,它依然在默默的幫助咱們很是輕鬆的構建起一個Web應用。在.Net Core中微軟提供了更爲強大的Web服務器 Kestrel ,它 是一個跨平臺ASP.NET Core 的 web 服務器基於libuv,跨平臺的異步 I/O 庫。它能夠單獨使用來host一個web服務,也能夠與反向代理服務器(如 IIS、Nginx 或 Apache)結合使用。 反向代理服務器接收到來自 Internet 的 HTTP 請求,並在進行一些初步處理後將這些請求轉發到 Kestrel。java
那麼今天咱們來聊一聊另外的兩種能夠self host的解決方案:git
Owin 是 Open Web Interface for .NET 的簡稱,從字面意思解釋能夠看出OWIN是針對.NET平臺的開放Web接口。那Web接口是誰和誰之間的接口呢?是Web應用程序與Web服務器之間的 接口,OWIN就是.NET Web應用程序與Web服務器之間的接口。爲何須要這樣一個接口呢?由於.NET Web應用程序是運行於Web服務器之中的,.NET Web應用程序須要經過Web服務器接收用戶的請求,而且經過Web服務器將響應內容發送用戶。若是沒有這樣一個接口,.NET Web應用程序就要依賴於所運行的具體Web服務器,好比ASP.NET應用程序要依賴於IIS。有了這個接口,ASP.NET應用程序只需依賴這個抽象接口,不用關心所運行的Web服務器。因此咱們能夠得出下面的結論:github
OWIN的做用就是經過引入一組抽象接口,解耦了.NET Web應用程序與Web服務器,再次體現了接口的重要性。web
而咱們知道在軟件開發中,每次解耦都是一次很大的進步。express
更近一層咱們能夠理解爲:OWIN是對ASP.NET Runtime的抽象。它將應用與服務器解耦, 使得便攜式 .NET Web 應用以及跨平臺的願望成爲現實, 標準的 OWIN 應用能夠在任何OWIN 兼容的服務器上運行,再也不依賴與 Windows 和 IIS,咱們更能夠不用裝一大堆笨重的IDE(如 visual studio)來開發web應用程序,也再也不那麼的依賴於IIS去Host咱們的程序。 咱們能夠用下面的一張圖來表示它究竟能夠作什麼:windows
具體使用以下:ruby
新建EventsController 繼承自:System.Web.Http.ApiController 服務器
public class EventsController : ApiController { [Authorize] [Route("events")] public IEnumerable<Event> Get() { return GetAllEventsFromRepo(); } [Route("events/{id}")] public Event GetById(Guid id) { return GetAllEventsFromRepo().First(x => x.EventId == id); } [Route("events")] public IEnumerable<Event> GetByType(string type) { return GetAllEventsFromRepo().Where(x => x.EventType.Equals(type, StringComparison.InvariantCultureIgnoreCase)); } [Route("events")] public HttpResponseMessage Post(Event @event) { if (@event == null) { return new HttpResponseMessage(HttpStatusCode.BadRequest); } return new HttpResponseMessage(HttpStatusCode.Created); } private IEnumerable<Event> GetAllEventsFromRepo() { return new List<Event> { new Event { EventId = Guid.Parse("45D80D13-D5A2-48D7-8353-CBB4C0EAABF5"), Timestamp = DateTime.Parse("2014-06-30T01:37:41.0660548"), EventType = "SearchView" }, new Event { EventId = Guid.Parse("83F9262F-28F1-4703-AB1A-8CFD9E8249C9"), Timestamp = DateTime.Parse("2014-06-30T01:37:52.2618864"), EventType = "DetailsView" }, new Event { EventId = Guid.Parse("3E83A96B-2A0C-49B1-9959-26DF23F83AEB"), Timestamp = DateTime.Parse("2014-06-30T01:38:00.8518952"), EventType = "SearchView" } }; } }
而後新建一個Startup.cs的class,咱們能夠看到這裏體現了Middleware(中間件)的思想,即插即用,熟悉.Net Core的同窗的對它並不陌生。 app
public class Startup { public void Configuration(IAppBuilder app) { var config = new HttpConfiguration(); config.MapHttpAttributeRoutes(); app.UseWebApi(config); var builder = new ContainerBuilder(); builder.RegisterApiControllers(typeof(EventsController).Assembly); var container = builder.Build(); app.UseAutofacMiddleware(container); app.UseAutofacWebApi(config); } }
上面代碼中的ContainerBuilder 是Autofac提供的功能,它可讓咱們動態的註冊Controller到容器中,還有一個很是重要的東西就是 HttpConfiguration,它用來表示 HttpServer 實例的配置。異步
而後咱們只須要下面一句代碼就可讓咱們API 工做起來了:
WebApp.Start<TestStartup>("http://localhost:51502")
這樣經過 http://localhost:51502 地址就能夠訪問咱們的服務了,很是的簡單。
iisexpress.exe咱們很熟悉,它是windows平臺自帶的IIS 的運行文件,默認路徑在: C:\Program Files\IIS Express 目錄下,咱們能夠在代碼中建立進程運行起這個exe就能夠了。具體代碼以下:
public class IISExpress : IDisposable { /// <summary> /// Stores whether this instance has been disposed. /// </summary> private bool _isDisposed; /// <summary> /// Stores the IIS Express process. /// </summary> private Process _process; /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// Starts IIS Express using the specified directory path and port. /// </summary> /// <param name="directoryPath"> /// The directory path. /// </param> /// <param name="port"> /// The port. /// </param> /// <param name="address"> /// The address. /// </param> public void Start(string directoryPath, int port, Uri address) { if (_process != null) { throw new InvalidOperationException("The IISExpress process is already running."); } if (address != null) { try { var request = (HttpWebRequest)WebRequest.Create(address); var webResponse = (HttpWebResponse)request.GetResponse(); if (webResponse.StatusCode == HttpStatusCode.OK) { return; } } catch (Exception ex) { Trace.WriteLine(ex); } } var iisExpressPath = DetermineIisExpressPath(); var arguments = string.Format(CultureInfo.InvariantCulture, "/path:\"{0}\" /port:{1}", directoryPath, port); var info = new ProcessStartInfo(iisExpressPath) { WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = true, LoadUserProfile = true, CreateNoWindow = false, UseShellExecute = false, Arguments = arguments }; var startThread = new Thread(() => StartIisExpress(info)) { IsBackground = true }; startThread.Start(); } /// <summary> /// Releases unmanaged and - optionally - managed resources. /// </summary> /// <param name="disposing"> /// <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources. /// </param> protected virtual void Dispose(bool disposing) { if (_isDisposed) { return; } if (disposing) { if (_process != null) { // Free managed resources if (_process.HasExited == false) { SendStopMessageToProcess(_process.Id); _process.Close(); } _process.Dispose(); } } // Free native resources if there are any _isDisposed = true; } /// <summary> /// Determines the IIS express path. /// </summary> /// <returns> /// A <see cref="String" /> instance. /// </returns> private static string DetermineIisExpressPath() { string iisExpressPath; if (Environment.Is64BitOperatingSystem) { iisExpressPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); } else { iisExpressPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); } iisExpressPath = Path.Combine(iisExpressPath, @"C:\Program Files\IIS Express\iisexpress.exe"); return iisExpressPath; } /// <summary> /// The send stop message to process. /// </summary> /// <param name="processId"> /// The process id. /// </param> private static void SendStopMessageToProcess(int processId) { try { for (var ptr = NativeMethods.GetTopWindow(IntPtr.Zero); ptr != IntPtr.Zero; ptr = NativeMethods.GetWindow(ptr, 2)) { uint num; NativeMethods.GetWindowThreadProcessId(ptr, out num); if (processId == num) { var handle = new HandleRef(null, ptr); NativeMethods.PostMessage(handle, 0x12, IntPtr.Zero, IntPtr.Zero); return; } } } catch (ArgumentException) { } } /// <summary> /// Starts the IIS express. /// </summary> /// <param name="info"> /// The info. /// </param> [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Required here to ensure that the instance is disposed.")] private void StartIisExpress(ProcessStartInfo info) { try { _process = Process.Start(info); _process.WaitForExit(); } catch (Exception) { Dispose(); } } /// <summary> /// The native methods. /// </summary> private static class NativeMethods { /// <summary> /// The get top window. /// </summary> /// <param name="hWnd"> /// The h wnd. /// </param> /// <returns> /// The <see cref="IntPtr"/>. /// </returns> [DllImport("user32.dll", SetLastError = true)] internal static extern IntPtr GetTopWindow(IntPtr hWnd); /// <summary> /// The get window. /// </summary> /// <param name="hWnd"> /// The h wnd. /// </param> /// <param name="uCmd"> /// The u cmd. /// </param> /// <returns> /// The <see cref="IntPtr"/>. /// </returns> [DllImport("user32.dll", SetLastError = true)] internal static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); /// <summary> /// The get window thread process id. /// </summary> /// <param name="hwnd"> /// The hwnd. /// </param> /// <param name="lpdwProcessId"> /// The lpdw process id. /// </param> /// <returns> /// The <see cref="uint"/>. /// </returns> [DllImport("user32.dll", SetLastError = true)] internal static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint lpdwProcessId); /// <summary> /// The post message. /// </summary> /// <param name="hWnd"> /// The h wnd. /// </param> /// <param name="Msg"> /// The msg. /// </param> /// <param name="wParam"> /// The w param. /// </param> /// <param name="lParam"> /// The l param. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> [return: MarshalAs(UnmanagedType.Bool)] [DllImport("user32.dll", SetLastError = true)] internal static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam); }
代碼比較簡單,你們都能看得懂,咱們只須要指定須要host的文件目錄,訪問端口,以及公開Uri地址就能夠了,這樣就能調用起IIS的服務,幫助咱們host服務。
可能不只限於這兩種方式,我只是把我最近使用到的兩種方式分享給出來,若是你們有更好的方式,歡迎交流分享。