第一步,使用VS2019新建MVC-Web API應用程序
創建BridgeApi
第二步,運行將生成默認的示例網頁,網頁Url為
https://localhost:44361/home/index
右鍵 項目 添加 WebAPI控制器類
?添加?
我們可以看到App_Start目錄下 有三個文件:
BundleConfig.cs代表 捆綁文件的引用?
有腳本文件ScriptBundle的引用(javascript文件,后綴名.js)
和層疊樣式表文件StyleBundle(即css網頁排版文件,后綴名.css)
FilterConfig.cs代表全局篩選器
RouteConfig.cs代表url路由模式和action信息
右鍵,項目,將類庫項目更新為控制臺應用程序,并添加類Program
添加開源框架Topshelf的引用,添加Owin框架的引用
Topshelf 框架
Topshelf 是一個開源的跨平臺的宿主服務框架,支持 Windows 和 Mono,只需要幾行代碼就可以構建一個很方便使用的服務宿主。
使用 Topshelf 可以非常方便的將一個 C# 控制臺程序部署成為一個 Windows Service, 使用它可以很方便的構建跨平臺服務寄主,而在調試時直接以控制臺的形式運行即可,非常方便。
Owin框架
OWIN 允許 Web 應用從 Web 服務器分離。 它定義了在管道中使用中間件來處理請求和相關響應的標準方法。?WebAPI應用程序和中間件可以與基于 OWIN 的應用程序、服務器和中間件進行互操作。
我們在web.config(有些是app.config)增加webAPI地址和端口
ApiAddress和ApiPort
<?xml version="1.0" encoding="utf-8"?>
<!--有關如何配置 ASP.NET 應用程序的詳細信息,請訪問https://go.microsoft.com/fwlink/?LinkId=301880-->
<configuration><appSettings><add key="webpages:Version" value="3.0.0.0" /><add key="webpages:Enabled" value="false" /><add key="ClientValidationEnabled" value="true" /><add key="UnobtrusiveJavaScriptEnabled" value="true" /><add key="ApiAddress" value="" /><add key="ApiPort" value="45678" /></appSettings>
</configuration>
Program.cs如下:
using Microsoft.Owin.Hosting;
using Owin;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using Topshelf;
using Topshelf.HostConfigurators;
/*
* Topshelf 是一個開源的跨平臺的宿主服務框架,支持 Windows 和 Mono,只需要幾行代碼就可以構建一個很方便使用的服務宿主。
* 使用 Topshelf 可以非常方便的將一個 C# 控制臺程序部署成為一個 Windows Service, 使用它可以很方便的構建跨平臺服務寄主,
* 而在調試時直接以控制臺的形式運行即可,非常方便。
* Owin框架
* OWIN 允許 Web 應用從 Web 服務器分離。 它定義了在管道中使用中間件來處理請求和相關響應的標準方法。
* WebAPI應用程序和中間件可以與基于 OWIN 的應用程序、服務器和中間件進行互操作。
*/namespace BridgeApi
{public class Program{static void Main(string[] args){Console.WriteLine("WebAPI程序啟動開始...");HostFactory.Run(new Action<HostConfigurator>(HostConf));Console.ReadLine();}public static void HostConf(HostConfigurator hostConfigurator){// 服務使用NETWORK_SERVICE內置帳戶運行。身份標識,有好幾種方式,如:x.RunAs("username", "password"); x.RunAsPrompt(); x.RunAsNetworkService(); 等hostConfigurator.RunAsLocalService();//以服務//x.StartAutomatically();//StartModeExtensions//x.StartManually();//手動模式hostConfigurator.SetDescription("WebAPIServer 斯內科 Topshelf Host服務的描述"); //安裝服務后,服務的描述hostConfigurator.SetDisplayName("WebAPIServerSnake"); //顯示名稱hostConfigurator.SetServiceName("WebAPIServerSnake"); //服務名稱Type t = hostConfigurator.GetType();//Topshelf.HostConfigurators.HostConfiguratorImplConsole.WriteLine(t.ToString());hostConfigurator.Service<TownCrier>(s =>{s.ConstructUsing(name => new TownCrier()); //配置一個完全定制的服務,對Topshelf沒有依賴關系。常用的方式。//the start and stop methods for the services.WhenStarted(tc => tc.Start()); //4s.WhenStopped(tc => tc.Stop());});} }public class TownCrier{public TownCrier(){}public void Start(){Task.Factory.StartNew(() =>{bool IsStarted = false;while (!IsStarted){try{string log = "服務啟動成功。";string urlKey = "ApiAddress";string portKey = "ApiPort";if (!ConfigurationManager.AppSettings.AllKeys.Contains(urlKey)){log = $"服務啟動出現異常:App.config文件中不存在配置[{urlKey}]";Console.WriteLine(log);return;}if (!ConfigurationManager.AppSettings.AllKeys.Contains(portKey)){log = $"服務啟動出現異常:App.config文件中不存在配置[{portKey}]";Console.WriteLine(log);return;}string apiUrl = ConfigurationManager.AppSettings[urlKey].ToString();string apiPort = ConfigurationManager.AppSettings[portKey].ToString();bool rtn = int.TryParse(apiPort, out int port);if (!rtn){log = $"服務啟動出現異常:App.config文件中配置[{portKey}]值錯誤";Console.WriteLine(log);return;}StartOptions options = new StartOptions();//options.Urls.Add($"http://localhost:{apiPort}");options.Urls.Add($"http://127.0.0.1:{apiPort}");//options.Urls.Add($"http://{Environment.MachineName}:{apiPort}");if (!string.IsNullOrEmpty(apiUrl)){options.Urls.Add($"http://{apiUrl}:{apiPort}");}else{#region //自動綁定所有IPstring hostName = Dns.GetHostName();IPAddress[] iPAddresses = Dns.GetHostAddresses(hostName);foreach (IPAddress ipAddress in iPAddresses){//IPv4if (ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork){options.Urls.Add($"http://{ipAddress}:{apiPort}");}}#endregion}string urls = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(options.Urls);log = $"開始啟動服務,服務地址:{urls}";Console.WriteLine(log);//OWIN 托管服務器問題:StartOptions WebApp.Start TargetInvocationException// Start OWIN host ,啟動一個webapi程序// public static IDisposable Start(string url, Action<IAppBuilder> startup);WebApp.Start(options, startup: Configuration);Console.WriteLine($"服務啟動成功。");IsStarted = true;}catch (Exception ex){Console.WriteLine($"服務啟動出現異常:{ex.Message}");Thread.Sleep(2000);}}});}public void Stop(){Console.WriteLine($"WebApi服務退出");}public void Configuration(IAppBuilder appBuilder){// Configure Web API for self-host. HttpConfiguration config = new HttpConfiguration();config.MapHttpAttributeRoutes();config.Routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "{controller}/{action}/{id}",defaults: new { id = RouteParameter.Optional });appBuilder.UseWebApi(config);}}
}
?控制器類BridgeController如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;namespace BridgeApi
{[RoutePrefix("Bridge")]public class BridgeController : ApiController{/// <summary>/// 測試API端口,假設傳入一個json字符串{"TestName":"斯內科"}/// 請求路由Url不區分大小寫/// http://127.0.0.1:45678/Bridge/testApi/// </summary>/// <param name="json"></param>/// <returns></returns>[Route("TestApi")][HttpPost]public HttpResponseMessage TestApi(object objText) {try{Microsoft.Owin.OwinContext context = ((Microsoft.Owin.OwinContext)Request.Properties["MS_OwinContext"]);string RemoteClient = context.Request.RemoteIpAddress + ":" + context.Request.RemotePort;if (objText == null){string returnDataNG = Newtonsoft.Json.JsonConvert.SerializeObject(new ResponseContent(){Code = 12345,Message = $"解析失敗,請求參數為空,源文本【{objText}】"});return new HttpResponseMessage(){Content = new StringContent(returnDataNG, System.Text.Encoding.UTF8, mediaType: "application/json")};}string json = objText.ToString();TestClass testClass = Newtonsoft.Json.JsonConvert.DeserializeObject<TestClass>(json);if (testClass == null || string.IsNullOrEmpty(testClass.TestName)){string returnDataNG = Newtonsoft.Json.JsonConvert.SerializeObject(new ResponseContent(){Code = 12345,Message = $"解析失敗,TestName為空,源json【{json}】"});return new HttpResponseMessage(){Content = new StringContent(returnDataNG, System.Text.Encoding.UTF8, mediaType: "application/json")};}string returnData = Newtonsoft.Json.JsonConvert.SerializeObject(new ResponseContent(){Code = 0,Message = "",Data = $"接收到【{RemoteClient}】上拋數據【{json}】,已處理OK,返回一個隨機數【{new Random().Next(1, 100)}】"});return new HttpResponseMessage(){Content = new StringContent(returnData, System.Text.Encoding.UTF8, mediaType: "application/json")};}catch (Exception ex) {string returnDataNG = Newtonsoft.Json.JsonConvert.SerializeObject(new ResponseContent(){Code = -1,Message = $"處理時出現錯誤【{ex.Message}】"});return new HttpResponseMessage(){Content = new StringContent(returnDataNG, System.Text.Encoding.UTF8, mediaType: "application/json"),StatusCode = HttpStatusCode.BadRequest};}}}public class TestClass{public string TestName { get; set; }}/// <summary>/// 接口反饋的響應內容對象/// </summary>public class ResponseContent {/// <summary>/// 錯誤號,code為0代表OK/// </summary>public int Code { get; set; }/// <summary>/// 錯誤描述,Code為0,這里顯示空/// </summary>public string Message { get; set; }/// <summary>/// 相關數據信息,該Data可以是數組、鍵值對字典、字符串等任意類型數據/// </summary>public object Data { get; set; }}
}