环境:VS2013
搭建项目框架如下:
Web为WebAPI接口层,Model层用于存放接口的输入输出参数
在网上参考了很多文档,把help page改造方法整理如下:
vs2013在创建webAPI项目时是默认安装了help page的,不过生成的帮助文档不符合我们需要,可以卸载掉然后安装2.2版本的
搜索help page,找到安装即可
在WebAPI项目Areas/HelpPage下添加类文件MultiXmlDocumentationProvider.cs
类内容如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Description;
namespace PP.JiJin.Web.Areas.HelpPage
{
///
/// A custom that reads the API documentation from a collection of XML documentation files.
///
public class MultiXmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
{
/*********
** Properties
*********/
/// The internal documentation providers for specific files.
private readonly XmlDocumentationProvider[] Providers;
/*********
** Public methods
*********/
/// Construct an instance.
/// The physical paths to the XML documents.
public MultiXmlDocumentationProvider(params string[] paths)
{
this.Providers = paths.Select(p => new XmlDocumentationProvider(p)).ToArray();
}
/// Gets the documentation for a subject.
/// The subject to document.
public string GetDocumentation(MemberInfo subject)
{
return this.GetFirstMatch(p => p.GetDocumentation(subject));
}
/// Gets the documentation for a subject.
/// The subject to document.
public string GetDocumentation(Type subject)
{
return this.GetFirstMatch(p => p.GetDocumentation(subject));
}
/// Gets the documentation for a subject.
/// The subject to document.
public string GetDocumentation(HttpControllerDescriptor subject)
{
return this.GetFirstMatch(p => p.GetDocumentation(subject));
}
/// Gets the documentation for a subject.
/// The subject to document.
public string GetDocumentation(HttpActionDescriptor subject)
{
return this.GetFirstMatch(p => p.GetDocumentation(subject));
}
/// Gets the documentation for a subject.
/// The subject to document.
public string GetDocumentation(HttpParameterDescriptor subject)
{
return this.GetFirstMatch(p => p.GetDocumentation(subject));
}
/// Gets the documentation for a subject.
/// The subject to document.
public string GetResponseDocumentation(HttpActionDescriptor subject)
{
return this.GetFirstMatch(p => p.GetDocumentation(subject));
}
/*********
** Private methods
*********/
/// Get the first valid result from the collection of XML documentation providers.
/// The method to invoke.
private string GetFirstMatch(Func expr)
{
return this.Providers
.Select(expr)
.FirstOrDefault(p => !String.IsNullOrWhiteSpace(p));
}
}
}
点击类中报错的地方,根据VS智能提示添加对应引用即可
本例中,接口引用的输入输出参数类在另外一个子项目PP.TradeCenter.Model中,因此,右键PP.TradeCenter.Model子项目→属性
勾选“XML文档文件”,填写生成的xml文件路径,本例指定为App_Data\XmlDocument.xml
同理,对WebAPI项目做同样的修改
然后在WebAPI项目属性的生成事件中添加命令:
copy "$(SolutionDir)PP.TradeCenter.Model\App_Data\XmlDocument.xml" "$(ProjectDir)\App_Data\PP.TradeCenter.Model.XmlDocument.xml"
这条命令的含义是在项目生成时,将PP.TradeCenter.Model子项目中App_Data文件夹下XmlDocument.xml文件复制到当前子项目(即PP.TradeCenter.Web)的App_Data文件夹下,并重命名为PP.TradeCenter.Model.XmlDocument.xml
使用时将PP.TradeCenter.Model改成自己Model项目名称即可,PP.TradeCenter.Model.XmlDocument.xml这个文件名也可以根据自己需要命名,下一步注册时候需要使用
增加一行代码:
config.SetDocumentationProvider(new MultiXmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml"), HttpContext.Current.Server.MapPath("~/App_Data/PP.TradeCenter.Model.XmlDocument.xml")));
这行代码里的两个xml文件名字需要和上一步子项目生成属性中配置的一致。
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
VS2013创建的WebAPI项目默认的路由是没有action的,这个有点小坑
到这里已经配置完成了,生成项目即可
新建一个API控制器
最终生成的help文档如下:
对接口的输入参数进行验证可以保证接口的安全
右键Model项目,添加引用
勾选对System.ComponentModel.DataAnnotations的引用,确认
然后我们右键这个添加的引用,选择“在对象浏览器中查看”
可以看到很多验证供选择:常用的有Require必填,Range验证数字范围,StringLength验证字符串长度,MaxLength最大长度、MinLength最小长度,Phone验证手机号,Email验证邮件地址,复杂的可以使用RegularExpression正则表达式验证
使用也比较方便,在输入参数对应属性上加上验证特性即可,示例如下:
验证添加完以后还不会生效,我们还需要把这些验证进行注册,微软官网示例的用法是在调用的类上加上
[MetadataType(typeof(input类名))]
webapi的用法参考:https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api
这里对输入参数验证进行一些整合
(1)在Model中Output中添加InputParamInvalidInfoOutput类、Result类、BusinessState类
InputParamInvalidInfoOutput类内容如下:
///
/// Web Api输入参数异常信息
///
public class InputParamInvalidInfoOutput
{
///
/// 输入参数
///
public string Key { set; get; }
///
/// 错误列表
///
public List Errors { set; get; }
}
Result类,用于封装API接口返回结果内容如下:
///
/// 返回结果
///
public class Result
{
private int code = BusinessState.RESULT_UnLogin.Code;
object body = new { };
///
/// 业务码
///
public int Code
{
get { return code; }
set { code = value; }
}
///
/// 业务信息
///
public string Msg { get; set; }
///
/// 数据实体
///
public object Body
{
get { return body; }
set { body = value; }
}
}
///
/// 返回结果
///
/// 数据实体类型
public class Result
{
private int code = BusinessState.RESULT_UnLogin.Code;
///
/// 业务码
///
public int Code
{
get { return code; }
set { code = value; }
}
///
/// 业务信息
///
public string Msg { get; set; }
T body = default(T);
///
/// 数据实体
///
public T Body
{
get { return body; }
set { body = value; }
}
}
BusinessState类,用于定义Result类的Code属性编码
///
/// 业务编码和提示信息
///
public class CodeMsg
{
public CodeMsg(int code, string msg)
{
Code = code;
Msg = msg;
}
///
/// 业务码
///
public int Code { get; set; }
///
/// 业务消息
///
public string Msg { get; set; }
}
public class BusinessState
{
///
/// 成功结果
///
public static CodeMsg SUCC = new CodeMsg(0, "成功");
///
/// token过期
///
public static CodeMsg RESULT_TOKEN_TIMEOUT = new CodeMsg(1, "请重新登录");//token过期
public static CodeMsg RESULT_UnLogin = new CodeMsg(2, "未登录");
public static CodeMsg RESULT_TOKEN_LOST = new CodeMsg(3, "请重新登录");//token失效
public static CodeMsg RESULT_EXCEPTION = new CodeMsg(4, "系统异常,稍后重试");
public static CodeMsg PARAM_INPUT_MODEL_INVALID = new CodeMsg(5, "查询参数无效,");
}
(2)在webAPI子项目下新建Filter文件夹,添加类ValidateModelAttribute
ValidateModelAttribute类内容如下:
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ModelState.IsValid == false)
{
//获取model验证失败字段
List errorList = new List();
foreach(var key in actionContext.ModelState.Keys){
InputParamInvalidInfoOutput errorItem = new InputParamInvalidInfoOutput() { Key = string.Empty, Errors = new List() };
errorItem.Key = key;
foreach (var error in actionContext.ModelState[key].Errors)
{
errorItem.Errors.Add(error.ErrorMessage);
}
errorList.Add(errorItem);
}
ErrorObj errObj = new ErrorObj() { ErrorList = errorList };
var result = new Result()
{
Code = BusinessState.PARAM_INPUT_MODEL_INVALID.Code,
Msg = BusinessState.PARAM_INPUT_MODEL_INVALID.Msg
,
Body = errObj
};
//PP.JiJin.BLL.LogBLL.Error("errObj=" + JsonHelper.Serializer(result));
//组装Response
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new ObjectContent>(result, new JsonMediaTypeFormatter());
response.RequestMessage = actionContext.Request;
//赋值Response
actionContext.Response = response;
}
}
public class ErrorObj
{
public List ErrorList { set; get; }
}
(3)在WebAPI项目的路由配置文件中注册Model的验证逻辑
//注册Model验证逻辑
config.Filters.Add(new ValidateModelAttribute());
到此大功告成,使用谷歌浏览器插件postman测试下接口: