使用WPF、OwinSelfHost和Swagger创建自托管的Web API

发布时间 2023-06-01 15:08:36作者: 凉生凉忆亦凉心

在本篇博客中,我将介绍如何在WPF应用程序中使用OwinSelfHost和Swagger来创建自托管的Web API。我们将使用WPF作为我们的应用程序界面,OwinSelfHost来自托管我们的Web API,并使用Swagger来为我们的API生成文档。

首先,确保你的计算机上已安装了以下组件:

  • Visual Studio2017
  • .NET Framework(至少需要4.5版本)

接下来,按照以下步骤进行操作:

步骤1:创建新的WPF项目 在Visual Studio中创建一个新的WPF项目。命名它为"SwaggerBlog"。

步骤2:安装必要的NuGet包 在解决方案资源管理器中,右键单击项目名称,选择"管理NuGet程序包"。然后,按照以下步骤安装所需的包:

  • Microsoft.AspNet.WebApi.OwinSelfHost
  • Microsoft.Owin.Cors
  • Swashbuckle
  • .。。。。

步骤3:创建API控制器 在解决方案资源管理器中,右键单击"Controllers"文件夹,选择"添加" -> "类"。命名为"模拟接口Controller.cs"。在类中添加以下代码:

using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using System.Web.Http;

namespace MockAPI.Controllers
{
    /// <summary>
    /// 模拟接口
    /// </summary>
    [RoutePrefix("api")]
    public class 模拟接口Controller : BaseController
    {
        /// <summary>
        /// 同步信息
        /// </summary>
        /// <returns></returns>
        [Route("fs_syncPayinfo")]
        [HttpGet]
        public IHttpActionResult SyncPayInfo()
        {
            string json = @"{""code"":1,""message"":""同步成功""}";
            return Json(JObject.Parse(json));
        }
}

步骤4:配置Swagger 在解决方案资源管理器中,右键单击"Properties"文件夹,选择"添加" -> "新建文件"。命名为"Startup.cs"。在文件中添加以下代码:

其中包含了记录日志中间件等类,具体看下载的代码

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http;
using System.Web.Http.Filters;
using System.Xml;
using Microsoft.Owin;
using Microsoft.Owin.Cors;
using MockAPI.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Owin;
using Swashbuckle.Application;
using Swashbuckle.Swagger;

[assembly: OwinStartup(typeof(MockAPI.Startup))]

namespace MockAPI
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();

            JsonSerializerSettings setting = new JsonSerializerSettings()
            {
                //日期类型默认格式化处理
                DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
                DateFormatString = "yyyy-MM-dd HH:mm:ss",
                //驼峰样式
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                //空值处理
                //NullValueHandling = NullValueHandling.Ignore,
                //设置序列化的最大层数
                MaxDepth = 10,
                //解决json序列化时的循环引用问题
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            };
            config.Formatters.JsonFormatter.SerializerSettings = setting;
            config.Formatters.Remove(config.Formatters.XmlFormatter);

            config.Filters.Add(new HandlerErrorAttribute());
            //config.Routes.MapHttpRoute(
            //    name: "DefaultApi",
            //    routeTemplate: "api/{controller}/{action}/{id}",
            //    defaults: new
            //    {
            //        id = RouteParameter.Optional
            //    }
            //);
            ConfigureSwagger(config);
            //添加路由路径
            config.MapHttpAttributeRoutes();
            app.UseCors(CorsOptions.AllowAll);

            app.Use<LoggingMiddleware>();
            app.UseWebApi(config);

        }
        private static void ConfigureSwagger(HttpConfiguration config)
        {
            var thisAssembly = typeof(Startup).Assembly;
            config.EnableSwagger(c =>
             {
                 c.SingleApiVersion("v1", "MockAPI");

                    //设置接口描述xml路径地址
                    var webApiXmlPath = string.Format(string.Format("{0}/MockAPI.xml", AppDomain.CurrentDomain.BaseDirectory));

                 c.IncludeXmlComments(webApiXmlPath);
                 c.UseFullTypeNameInSchemaIds();
                    //加入控制器描述
                    c.CustomProvider((defaultProvider) => new SwaggerControllerDescProvider(defaultProvider, webApiXmlPath));
             })
             .EnableSwaggerUi(c =>
             {
                 c.DocumentTitle("MockAPI");
                 c.InjectJavaScript(thisAssembly, "MockAPI.Common.Swagger.js");
             });
        }

        public class HandlerErrorAttribute : ExceptionFilterAttribute
        {
            /// <summary>
            /// 控制器方法中出现异常,会调用该方法捕获异常
            /// </summary>
            /// <param name="context">提供使用</param>
            public override void OnException(HttpActionExecutedContext context)
            {
                base.OnException(context);
                LogFile.WriteError(context.Exception.Message);
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new StringContent(
                   JsonConvert.SerializeObject(
                    new
                    {
                        code = -1,
                        data = "xxx",
                        msg = context.Exception.Message
                    }), Encoding.UTF8, "text/json")
                });
            }
        };

        public class SwaggerControllerDescProvider : ISwaggerProvider
        {
            private readonly ISwaggerProvider _swaggerProvider;
            private static ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>();
            private readonly string _xml;
            /// <summary>
            /// 
            /// </summary>
            /// <param name="swaggerProvider"></param>
            /// <param name="xml">xml文档路径</param>
            public SwaggerControllerDescProvider(ISwaggerProvider swaggerProvider, string xml)
            {
                _swaggerProvider = swaggerProvider;
                _xml = xml;
            }

            public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
            {

                var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion);
                SwaggerDocument srcDoc = null;
                //只读取一次
                if (!_cache.TryGetValue(cacheKey, out srcDoc))
                {
                    srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion);

                    srcDoc.vendorExtensions = new Dictionary<string, object> { { "ControllerDesc", GetControllerDesc() } };
                    _cache.TryAdd(cacheKey, srcDoc);
                }
                return srcDoc;
            }

            /// <summary>
            /// 从API文档中读取控制器描述
            /// </summary>
            /// <returns>所有控制器描述</returns>
            public ConcurrentDictionary<string, string> GetControllerDesc()
            {
                string xmlpath = _xml;
                ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>();
                if (File.Exists(xmlpath))
                {
                    XmlDocument xmldoc = new XmlDocument();
                    xmldoc.Load(xmlpath);
                    string type = string.Empty, path = string.Empty, controllerName = string.Empty;

                    string[] arrPath;
                    int length = -1, cCount = "Controller".Length;
                    XmlNode summaryNode = null;
                    foreach (XmlNode node in xmldoc.SelectNodes("//member"))
                    {
                        type = node.Attributes["name"].Value;
                        if (type.StartsWith("T:"))
                        {
                            //控制器
                            arrPath = type.Split('.');
                            length = arrPath.Length;
                            controllerName = arrPath[length - 1];
                            if (controllerName.EndsWith("Controller"))
                            {
                                //获取控制器注释
                                summaryNode = node.SelectSingleNode("summary");
                                string key = controllerName.Remove(controllerName.Length - cCount, cCount);
                                if (summaryNode != null && !string.IsNullOrEmpty(summaryNode.InnerText) && !controllerDescDict.ContainsKey(key))
                                {
                                    controllerDescDict.TryAdd(key, summaryNode.InnerText.Trim());
                                }
                            }
                        }
                    }
                }
                return controllerDescDict;
            }
        }
    }
}
View Code

步骤5:配置OwinSelfHost 启动等等 

  private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            setMin();
            wsl = this.WindowState;
            this.Hide();//启动后直接最小化
            this.ResizeMode = ResizeMode.CanMinimize;
            this.txtDevice.Text = DeviceNo;
            this.txtDevice.IsReadOnly = true;

            var registry = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);//检索指定的子项
            if (registry != null)
            {
                object a = registry.GetValue(Path.GetFileName(System.Windows.Forms.Application.ExecutablePath));
                if (a != null) this.cboAuto.IsChecked = true;
                registry.Close();
            }
            this.cboAuto.Checked += BtnClickTurnOn;
            this.cboAuto.Unchecked += BtnClickTurnOff;

            StartOptions options = new StartOptions();
            options.Urls.Add("http://+:8033");
            // 启动 OWIN host
            _disposable = WebApp.Start<Startup>(options);
        }

这里代码只有部分截图,具体下载代码查看   点击下载

 点击API地址打开文档界面

 

 

至此,我们已成功创建了一个使用WPF、OwinSelfHost和Swagger的自托管Web API。你可以根据自己的需求进一步扩展和定制这个应用程序。