asp.net web api 构建api帮助文档

1 概要

创建ASP.NET Web Api 时模板自带Help Pages框架。

2 问题

1)使用VS创建Web Api项目时,模板将Help Pages框架自动集成到其中,使得Web Api项目引入了MVC框架开发包,使得项目看起来杂乱。

2)自带的Help Pages框架无法针对Odata控制器生成API文档。

3 问题解决方案

1)独立Help Pages项目,以插件形式添加服务

步骤1,添加类ServiceAssembliesResolver,获得服务集

   /// <summary>
    /// 获取插件服务
    /// </summary>
    public class ServiceAssembliesResolver : DefaultAssembliesResolver
    {
        public override ICollection<Assembly> GetAssemblies()
        {
            //获得已有的服务
            ICollection<Assembly> baseAssemblies = base.GetAssemblies();
            //初始化
            List<Assembly> assemblies = new List<Assembly>(baseAssemblies);
            //服务插件dll路径
            var path = WebConfigSetting.ServicesLocation;
            //加载每一个服务插件
            foreach (string file in Directory.GetFiles(path, "*.dll"))
            {
                var controllersAssembly = Assembly.LoadFrom(file);
                assemblies.Add(controllersAssembly);
            }

            return assemblies;
        }
}

步骤2,替换现有服务

在WebApiConfig.Register方法中添加代码

config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver());

完整代码如下:

namespace HY_WebApi.HelpPages
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务
            config.Services.Replace(typeof(IAssembliesResolver), new ServiceAssembliesResolver());

            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            //OData路由,将路由名称设置为控制器(去掉Controller)名称,以便生成Api帮助文档
            config.MapODataServiceRoute(
                routeName: "ODataSearch",
                routePrefix: "odata",
                model: GetEdmModel(),
                batchHandler: new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));

        }
        private static IEdmModel GetEdmModel()
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Institution>("ODataSearch");

            builder.Namespace = "Search";
            //builder.EntityType<Institution>().Collection.Function("GetByIdEq2").Returns<string>();
            return builder.GetEdmModel();
        }

        public class Institution
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Address { get; set; }
        }
    }
}

步骤3,添加MultiXmlDocumentationProvider类,读取多个XML文档

   /// <summary>
    /// 加载目录下的所有Xml文档
    /// </summary>
    public class MultiXmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
    {
        private IList<XmlDocumentationProvider> _documentationProviders;

        public MultiXmlDocumentationProvider(string xmlDocFilesPath)
        {
            _documentationProviders = new List<XmlDocumentationProvider>();

            foreach (string file in Directory.GetFiles(xmlDocFilesPath, "*.xml"))
            {
                _documentationProviders.Add(new XmlDocumentationProvider(file));
            }
        }

        public string GetDocumentation(HttpParameterDescriptor parameterDescriptor)
        {
            return _documentationProviders.Select(x => x.GetDocumentation(parameterDescriptor)).FirstOrDefault(x => !string.IsNullOrEmpty(x));
        }

        public string GetDocumentation(Type type)
        {
            return _documentationProviders.Select(x => x.GetDocumentation(type)).FirstOrDefault(x => !string.IsNullOrEmpty(x));
        }

        //成员导航
        public string GetDocumentation(MemberInfo member)
        {
            return _documentationProviders
          .Select(x => x.GetDocumentation(member))
          .FirstOrDefault(x => !string.IsNullOrWhiteSpace(x));
        }

        //action 描述
        public string GetDocumentation(HttpActionDescriptor actionDescriptor)
        {
            return _documentationProviders.Select(x => x.GetDocumentation(actionDescriptor)).FirstOrDefault(x => !string.IsNullOrEmpty(x));
        }

        //Controller 描述
        public string GetDocumentation(HttpControllerDescriptor controllerDescriptor)
        {
            return _documentationProviders.Select(x => x.GetDocumentation(controllerDescriptor)).FirstOrDefault(x => !string.IsNullOrEmpty(x));
        }

        public string GetResponseDocumentation(HttpActionDescriptor actionDescriptor)
        {
            return _documentationProviders.Select(x => x.GetDocumentation(actionDescriptor)).FirstOrDefault(x => !string.IsNullOrEmpty(x));

        }  }

步骤4,使用MultiXmlDocumentationProvider

将config.SetDocumentationProvider(new MultiXmlDocumentationProvider(WebConfigSetting.ServicesLocation));添加到Register方法中

步骤5,创建服务插件文件夹,将服务插件及其XML文档放在文件夹中。

2)重构ApiExplorer,获得Odata控制器的API文档

步骤1,重构ApiExplorer

public class CustomApiExplorer : ApiExplorer
    {
        private HttpConfiguration configuration;
        public CustomApiExplorer(HttpConfiguration configuration)
            : base(configuration)
        {
            this.configuration = configuration;
        }
        public override bool ShouldExploreController(string controllerVariableValue, HttpControllerDescriptor controllerDescriptor, IHttpRoute route)
        {
            if (controllerDescriptor == null)
            {
                throw new ArgumentNullException("controllerDescriptor");
            }

            if (route == null)
            {
                throw new ArgumentNullException("route");
            }
            var c = controllerDescriptor.ControllerName;
            //获得OData路由
            IEdmModel edm = EdmModelCreater.GetEdmModel();
            List<string> collectionFromEdms = new List<string>();
            foreach (var item in edm.EntityContainer.Elements)
            {
                collectionFromEdms.Add(item.Name);
            }

            //如果是Odata控制器,那么忽略ApiExplorerSettingsAttribute
            ApiExplorerSettingsAttribute setting = controllerDescriptor.GetCustomAttributes<ApiExplorerSettingsAttribute>().FirstOrDefault();
            bool isOdataController = collectionFromEdms.Contains(controllerDescriptor.ControllerName);
            bool isBaseApi = controllerDescriptor.ControllerName != "BaseApi";
            return isBaseApi||isOdataController ||
                ((setting == null || !setting.IgnoreApi) && MatchRegexConstraint(route, RouteValueKeys.Controller, controllerVariableValue));
        }

        public override bool ShouldExploreAction(string actionVariableValue, HttpActionDescriptor actionDescriptor, IHttpRoute route)
        {
            if (actionDescriptor == null)
            {
                throw new ArgumentNullException("actionDescriptor");
            }

            if (route == null)
            {
                throw new ArgumentNullException("route");
            }

            //获得OData路由
            IEdmModel edm = EdmModelCreater.GetEdmModel();
            List<string> collectionFromEdms = new List<string>();
            foreach (var item in edm.EntityContainer.Elements)
            {
                collectionFromEdms.Add(item.Name);
            }

            //如果是Odata控制器,那么忽略ApiExplorerSettingsAttribute
            ApiExplorerSettingsAttribute setting = actionDescriptor.ControllerDescriptor.GetCustomAttributes<ApiExplorerSettingsAttribute>().FirstOrDefault();
            bool isOdataController = collectionFromEdms.Contains(actionDescriptor.ControllerDescriptor.ControllerName);
            bool isBaseApi = actionDescriptor.ControllerDescriptor.ControllerName != "BaseApi";
            return isBaseApi||isOdataController ||
                ((setting == null || !setting.IgnoreApi) && MatchRegexConstraint(route, RouteValueKeys.Action, actionVariableValue));
        }

        private static bool MatchRegexConstraint(IHttpRoute route, string parameterName, string parameterValue)
        {
            IDictionary<string, object> constraints = route.Constraints;
            if (constraints != null)
            {
                object constraint;
                if (constraints.TryGetValue(parameterName, out constraint))
                {
                    // treat the constraint as a string which represents a Regex.
                    // note that we don‘t support custom constraint (IHttpRouteConstraint) because it might rely on the request and some runtime states
                    string constraintsRule = constraint as string;
                    if (constraintsRule != null)
                    {
                        string constraintsRegEx = "^(" + constraintsRule + ")$";
                        return parameterValue != null && Regex.IsMatch(parameterValue, constraintsRegEx, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
                    }
                }
            }

            return true;
        }
    }

添加RouteValueKeys类

internal static class RouteValueKeys
{
        // Used to provide the action and controller name
        public const string Action = "action";
        public const string Controller = "controller";
}

添加OdataRelativePath类

public static class OdataRelativePath
    {
        public static void GetOdataRelativePath(CustomApiExplorer customApiExplorer, HttpConfiguration configuration)
        {
            IEdmModel edm = EdmModelCreater.GetEdmModel();
            List<string> collectionFromEdms = new List<string>();
            foreach(var item in edm.EntityContainer.Elements)
            {
                collectionFromEdms.Add(item.Name);
            }
            Collection<ApiDescription> apiColloction = customApiExplorer.ApiDescriptions;
            foreach (ApiDescription api in apiColloction)
            {
                string controllerName = api.ActionDescriptor.ControllerDescriptor.ControllerName;
                //去掉Odata中控制器的版本号
                var controllerSelector = configuration.Services.GetService(typeof(IHttpControllerSelector)) as VersionControllerSelector;
                string oldString = controllerSelector.RouteVersionSuffixMapping.First(m => m.Key.Contains("OdataRouteVersioning")).Value;
                controllerName = controllerName.Replace(oldString, "");
                if (collectionFromEdms.Contains(controllerName))
                {
                    string actionName = api.ActionDescriptor.ActionName;
                    var parameters = api.ActionDescriptor.GetParameters();
                    string paramStr = null;
                    foreach (var parameter in parameters)
                    {
                        var t = parameter.ParameterType;
                        if (parameter.ParameterType.IsClass)
                        {
                            continue;
                        }
                        if (paramStr != null)
                        {
                            paramStr = string.Format("{0}&({1}={1})", paramStr, parameter.ParameterName);
                        }
                        else
                        {
                            paramStr = string.Format("({0}={0})", parameter.ParameterName);
                        }
                    }
                    api.RelativePath = string.Format("{0}/{1}/{2}/Service.{3}{4}", "odata", "{Version}", controllerName, actionName, paramStr);
                }
                else
                {
                    Regex reg=new Regex("[0-9]");
                    Match match = reg.Match(api.RelativePath);
                    if(match.Success)
                    {
                        api.RelativePath = api.RelativePath.Replace(string.Format("V{0}",match.Value),"");
                    }
                }
            }
        }
    }

步骤2;根据OData路由拼出api的URI

使用OdataRelativePath.GetOdataRelativePath方法修改ApiExplorer.ApiDescriptions中的URI
例如在控制器中

     public ActionResult Index()
        {
            ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider();
            CustomApiExplorer customApiExplorer = new CustomApiExplorer(Configuration);
            OdataRelativePath.GetOdataRelativePath(customApiExplorer,Configuration);
            Collection<ApiDescription> apiDescriptions = new Collection<ApiDescription>();
            List<ApiDescription> list = new List<ApiDescription>();
            foreach (ApiDescription ad in customApiExplorer.ApiDescriptions)
            {
                if (ad.ActionDescriptor.ControllerDescriptor.ControllerName != "Metadata" && ad.ActionDescriptor.ActionName != "ToJson")
                {
                    list.Add(ad);
                }
            }
            list = list.OrderBy(m => m.ActionDescriptor.ControllerDescriptor.ControllerName).ToList();
            list.ForEach(m =>
            {
                apiDescriptions.Add(m);
            });
            return View(apiDescriptions);
        }

注意:配置Odata路由时,将路由名称配置为控制器名称(不含Controller字符串),并且编写服务程序时,遵循一个实体对应一个控制器,对应一个Odata路由。

-----------------------------------------------------------------------------------------

转载与引用请注明出处。

时间仓促,水平有限,如有不当之处,欢迎指正。

时间: 2024-10-07 00:56:22

asp.net web api 构建api帮助文档的相关文章

利用iStylePDF的API实现在PDF文档中动态插入一幅图片

PDF的交互特性里面有一种叫Annotation的注释和标记对象,我们可以在一个注释对象中放入自己想要的数据.在这篇文章中所讲到的插入一幅图片,是我们在PDF应用中经常需要这样做的,比如个人签名的图片等. 首先我们来认识下PDF里面中的Annotations是何东东.一个annotation关联了一些注释.声音.电影等对象,PDF标准中预定义了一些常用的注释类型.在我们的帮助文档中有详细的说明,等下也会用到的,我列举出来了,如下所示 名称 数值 描述 spAnnotText 0 文本 spAnn

ASP.NET WebAPI使用Swagger生成测试文档

ASP.NET WebAPI使用Swagger生成测试文档 SwaggerUI是一个简单的Restful API测试和文档工具.简单.漂亮.易用(官方demo).通过读取JSON配置显示API .项目本身仅仅也只依赖一些html,css,js静态文件.你可以几乎放在任何Web容器上使用 捣鼓了好久最终效果如下 1.API控制器和action描述 2.测试接口 使用swagger 1.创建webapi项目解决方案 2.引用swagger nuget包 swashbuckle和swagger.NET

Java之------socket查看指定URL的Web页编辑器及HTML文档

本例只能用于查看比较简单的网页,像是现在jsp开发的网页有很多地方时无法显示的,但这种程序还是值得学习一下的 package cn.hncu.url; import java.util.Date; import java.text.SimpleDateFormat; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.io.*; import java.net.*; publ

Java实现web在线预览office文档与pdf文档实例

https://yq.aliyun.com/ziliao/1768?spm=5176.8246799.blogcont.24.1PxYoX 摘要: 本文讲的是Java实现web在线预览office文档与pdf文档实例, 1.首先我们需要找到可以把office转换成pdf的方法,查找资料发现有openoffice这一软件可以把office转换成pdf,这一软件先下载下来,然后记住自己安装的在那个位置.然后在cmd环境下进入安装目录的program目 云计算 云服务器ECS 大数据 建站 备案 文档

Web Api 自动生成帮助文档

新建Web Api项目之后,会在首页有API的导航菜单,点击即可看到API帮助文档,不过很遗憾,Description 是没有内容的. 怎么办呢? 第一步: 如果用VS2013 新建项目的(VS2012没试过),项目中会有 Areas/HelpPage 这样的目录,你没看错,文档就是这货生成的. 如果要是删除了或者,没有这个目录怎么办呢?没关系,你只需要使用NuGet添加  [Microsoft.AspNet.WebApi.HelpPage]这货,然后你就发现,你的项目自动添加了 Areas/H

Web API 自动生成帮助文档并使用Web API Test Client 测试

之前在项目中有用到webapi对外提供接口,发现在项目中有根据webapi的方法和注释自动生成帮助文档,还可以测试webapi方法,功能很是强大,现拿出来与大家分享一下. 先看一下生成的webapi文档. 1.下图展示的是生成帮助文档首页面,其中Values是controller,API下面的列表展示出请求的http方法(Get,POST等),请求的action,方法的描述. 2.点击红框内的链接,打开api方法的详情页面,如下图所示, 3.点击Test API打开如下页面 4.输入参数,点击S

ASP.NET Web Pages (Razor) API Quick Reference

By Tom FitzMacken|February 10, 2014 Print This page contains a list with brief examples of the most commonly used objects, properties, and methods for programming ASP.NET Web Pages with Razor syntax. Descriptions marked with "(v2)" were introduc

Asp.Net Core Api 使用Swagger管理文档教程的安装与使用

这周因为公司的需求需要我做一个Api的程序,这周的三天时间我一直在Core Api和 framework Api之间做纠结.不知道要使用哪一个去做项目,想着想着就决定了.既然两个我都没用过那个何不来使用Core Api来做呢.也是对自己的一种锻炼! OK,接下来回归正题! Core下的Swagger和传统framework  Mvc下的Swagger是不一样的!  两者的差距:       其一:引用的程序集不一样.          其二:安装完程序集后需要配置的地方不一样,        

hadoop2.6.0汇总:新增功能最新编译 32位、64位安装、源码包、API下载及部署文档

相关内容: hadoop2.5.2汇总:新增功能最新编译 32位.64位安装.源码包.API.eclipse插件下载Hadoop2.5 Eclipse插件制作.连接集群视频.及hadoop-eclipse-plugin-2.5.0插件下载hadoop2.5.1汇总:最新编译 32位.64位安装.源码包.API下载及新特性等 新手指导:hadoop官网介绍及如何下载hadoop(2.4)各个版本与查看hadoop API介绍 从零教你在Linux环境下(ubuntu 12.04)如何编译hadoo