asp.netmvc抽取控制器备注说明
程序员文章站
2024-02-27 18:17:39
...
主要是读取xml描述和通过反射获取dll中的type,思想参考swagger,但是因为swagger没有mvc包,只能自己写一个了
1、首先需要把项目属性→生成→输出→xml文档文件 勾选上,勾选上之后你的bin目录下就会有一个xml文件,保存的是当前项目的所有类和方法属性备注
如果有一些用到的model类在别的项目里,那那个项目也需要勾选上
2、由于有时需要返回的model的说明,所以我写了一个特性什么都不做,只用来标记需要描述的返回的类,方便反射读取方法的自定义特性,
public class ResponseTypeAttribute : Attribute
{
public ResponseTypeAttribute(Type t)
{
}
}
3、首先定义一些需要用到的类
/// <summary>
/// 接口描述类
/// </summary>
public class InterfaceSpecificationDesc
{
public string ActionSummary { get; set; }
public string ControllerName { get; set; }
public string ActionName { get; set; }
public string HttpType { get; set; }
public List<ParamSpecification> Params { get; set; }
public string ResponseDesc { get; set; }
public List<ParamSpecification> ResponseModel { get; set; }
}
/// <summary>
/// 参数描述类
/// </summary>
public class ParamSpecification
{
public string Name { get; set; }
public string @Type { get; set; }
public string Desc { get; set; }
public string DefaultValue { get; set; }
public List<ParamSpecification> @params { get; set; }
}
/// <summary>
/// xml读记录的属性方法的描述
/// </summary>
public class XmlInfo
{
public string member { get; set; }
public string summary { get; set; }
public string returns { get; set; }
public List<XmlParam> @params { get; set; }
}
/// <summary>
/// xml中记录的方法参数
/// </summary>
public class XmlParam
{
public string name { get; set; }
public string desc { get; set; }
}
4、获取描述的主要代码
var xmls = getXmlFile(xml);//读取xml到内存中,转换成List<XmlInfo>格式
var a = Assembly.LoadFile(path);//读取一个dll
Type[] types = a.GetTypes();//获取曾程序集中定义的类型
var descs = new List<InterfaceSpecificationDesc>();//最终结果
var rg = new Regex("^[A-Za-z]+$");
foreach (var controller in types)
{
if (!rg.IsMatch(controller.Name) || !controller.Name.EndsWith("Controller"))//过滤掉不是控制器的类型,正则太难了QAQ
{
continue;
}
foreach (var action in controller.GetMethods())//获取当前控制器的所有方法
{
if (action.Name.StartsWith("get_") || action.Name.StartsWith("set_") || new string[] { "Dispose", "Equals", "GetHashCode", "GetType", "ToString" }.Contains(action.Name))//过滤到不是我们需要的方法和
{
continue;
}
var @params = new List<ParamSpecification>();//当前方法的参数
var paramsdesc = xmls.FirstOrDefault(p => p.member.Contains(controller.Name + "." + action.Name))?.@params;
foreach (var param in action.GetParameters())
{
var paramModel = new List<ParamSpecification>();
var rmpType = param.ParameterType;
if (!names.Contains(rmpType.Name))
{
paramModel = getParamSpecification(rmpType, xmls);//自定义类型,从xml中读取备注
}
@params.Add(new ParamSpecification
{
Name = param.Name,
Type = param.ParameterType.Name == "List`1" ? param.ParameterType.GenericTypeArguments[0].Name + "[]" : param.ParameterType.Name,
DefaultValue = param.DefaultValue + "",
Desc = paramsdesc?.FirstOrDefault(p => p.name == param.Name)?.desc,
@params = paramModel
});
}
var tmp = action.Attributes;
string httptype = "", respons = "";
var responseModel = new List<ParamSpecification>();
foreach (var attribute in action.CustomAttributes)//自定义特性
{
if (attribute.AttributeType.Name.Contains("ost"))
{
httptype = "Post";
}
else if (attribute.AttributeType.Name.Contains("et"))
{
httptype = "Get";
}
if (attribute.AttributeType.Name.Contains("ResponseType"))//专门标注的返回类型
{
var value = attribute.ConstructorArguments.FirstOrDefault().Value as Type;
respons = value.FullName;
responseModel = getParamSpecification(value, xmls);//自定义类型,从xml中读取备注
}
}
descs.Add(new InterfaceSpecificationDesc
{
ControllerName = controller.Name.Replace("Controller", ""),
ActionName = action.Name,
ActionSummary = xmls.FirstOrDefault(p => p.member.Contains(controller.Name + "." + action.Name))?.summary,
HttpType = string.IsNullOrWhiteSpace(httptype) ? "Post/Get" : httptype,
Params = @params,
ResponseDesc = respons,
ResponseModel = responseModel
});
}
}
//JsonConvert
descs = descs.OrderBy(p => p.ControllerName).ToList();
用到的一些方法
/// <summary>
/// 从xml中拿到目标type的备注
/// </summary>
/// <param name="value"></param>
/// <param name="xmls"></param>
/// <returns></returns>
private static List<ParamSpecification> getParamSpecification(Type value, List<XmlInfo> xmls)
{
var ret = new List<ParamSpecification>();
while (value.Name != "Object")
{
if (value.Name == "List`1")
{
value = value.GenericTypeArguments[0];
}
if (names.Contains(value.Name))
{
return ret;
}
if (value.Name.Contains("[]"))
{
value = value.Assembly.GetType(value.FullName.Replace("[]", ""));
}
foreach (var property in value.GetProperties())
{
ret.Add(new ParamSpecification
{
Name = property.Name,
Type = property.PropertyType.Name,
Desc = xmls.FirstOrDefault(p => p.member.Contains(value.FullName + "." + property.Name))?.summary
});
}
value = value.BaseType;
}
return ret;
}
private static string getName(string str)
{
var ret = rgName.Match(str).Value;
ret = ret.Replace("name=", "");
if (ret.Length > 0)
{
ret = ret.TrimEnd('"');
ret = ret.TrimStart('"');
}
return ret;
}
private static string getValue(string str)
{
var ret = rgValue.Match(str).Value;
ret = ret.TrimStart('>');
ret = ret.TrimEnd('<');
return ret;
}
5、前端页面简单写做一下
6、最终效果:
需要分析的dll中,控制器是这么写的:
返回model和参数model:
最终效果:
上一篇: 模拟进程调度
下一篇: Easy Code代码生成器
推荐阅读