944 lines
35 KiB
C#
944 lines
35 KiB
C#
using System;
|
|
using System.Configuration;
|
|
using System.Web;
|
|
using System.Web.Security;
|
|
using System.Web.UI;
|
|
using System.Web.UI.WebControls;
|
|
using System.Web.UI.WebControls.WebParts;
|
|
using System.Web.UI.HtmlControls;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Xml.XPath;
|
|
using GThinking.N_MISPROAS.Web.AjaxServices;
|
|
using GThinking.N_MISPRO.Data;
|
|
|
|
namespace GThinking.S_XLXSBJ
|
|
{
|
|
/// <summary>
|
|
/// 服务方法管理相关服务。
|
|
/// </summary>
|
|
public class ServiceMethod
|
|
{
|
|
/// <summary>
|
|
/// 根据传入的 DLL 文件地址,反射获取其中标记了 AjaxMethod 的服务方法信息,
|
|
/// 并写入数据库表:SRCMD、SRCMETHOD、SRCMETHODPARAMS、SRCTYPE、SRCPROP。
|
|
/// </summary>
|
|
/// <param name="filePath">DLL 文件地址。</param>
|
|
/// <returns>操作结果。</returns>
|
|
[AjaxMethod(AuthRequried = false)]
|
|
public static Dictionary<string, object> SaveServiceMethodInfo(string filePath)
|
|
{
|
|
Dictionary<string, object> result = new Dictionary<string, object>();
|
|
TDatabase dberp = null;
|
|
|
|
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
|
|
{
|
|
result["success"] = false;
|
|
result["msg"] = "文件地址不能为空或文件不存在";
|
|
return result;
|
|
}
|
|
|
|
try
|
|
{
|
|
dberp = TContextDatabases.GetDatabase("DBERP");
|
|
dberp.BeginTrans();
|
|
|
|
Assembly assembly = Assembly.LoadFrom(filePath);
|
|
string macId = Truncate(assembly.GetName().Name, 20);
|
|
|
|
// 先删除该部件旧数据
|
|
DeleteOldModuleData(dberp, macId);
|
|
|
|
XmlDocHelper xmlDoc = new XmlDocHelper(filePath);
|
|
int mdIndex = 0;
|
|
Dictionary<string, string> visitedTypes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
Type[] types = null;
|
|
try
|
|
{
|
|
types = assembly.GetTypes();
|
|
}
|
|
catch (ReflectionTypeLoadException ex)
|
|
{
|
|
types = ex.Types;
|
|
}
|
|
|
|
if (types == null)
|
|
{
|
|
dberp.CommitTrans();
|
|
result["success"] = true;
|
|
result["msg"] = "未找到可扫描的类型";
|
|
result["macId"] = macId;
|
|
return result;
|
|
}
|
|
|
|
foreach (Type type in types)
|
|
{
|
|
if (type == null)
|
|
continue;
|
|
if (!type.IsClass)
|
|
continue;
|
|
|
|
Dictionary<string, ServiceMethodInfo> methods = GetServiceMethods(type);
|
|
if (methods == null || methods.Count == 0)
|
|
continue;
|
|
|
|
mdIndex++;
|
|
double mdId = (double)mdIndex;
|
|
|
|
InsertSRCMD(dberp, macId, mdId, Truncate(type.FullName, 40));
|
|
|
|
foreach (ServiceMethodInfo smi in methods.Values)
|
|
{
|
|
string methodDesc = xmlDoc.GetMethodSummary(smi.MethodInfo);
|
|
string retDesc = xmlDoc.GetMethodReturns(smi.MethodInfo);
|
|
|
|
InsertSRCMETHOD(
|
|
dberp,
|
|
macId,
|
|
mdId,
|
|
Truncate(smi.MethodName, 32),
|
|
Truncate(GetMethodModifiers(smi.MethodInfo), 80),
|
|
smi.AuthRequried ? "Y" : "N",
|
|
smi.UseHttpGet ? "Y" : "N",
|
|
Truncate(methodDesc, 4000),
|
|
Truncate(GetTypeDisplayName(smi.ReturnType), 80),
|
|
Truncate(retDesc, 1000));
|
|
|
|
if (smi.ParameterList != null)
|
|
{
|
|
int paramXh = 0;
|
|
foreach (ServiceParameterInfo spi in smi.ParameterList)
|
|
{
|
|
string paramDesc = xmlDoc.GetParameterSummary(smi.MethodInfo, spi.Name);
|
|
|
|
InsertSRCMETHODPARAMS(
|
|
dberp,
|
|
macId,
|
|
mdId,
|
|
Truncate(smi.MethodName, 32),
|
|
(double)paramXh,
|
|
Truncate(spi.Name, 32),
|
|
Truncate(GetTypeDisplayName(spi.ParameterType), 80),
|
|
Truncate(paramDesc, 1000));
|
|
|
|
ReflectType(spi.ParameterType, dberp, visitedTypes, xmlDoc);
|
|
paramXh++;
|
|
}
|
|
}
|
|
|
|
ReflectType(smi.ReturnType, dberp, visitedTypes, xmlDoc);
|
|
}
|
|
}
|
|
|
|
dberp.CommitTrans();
|
|
result["success"] = true;
|
|
result["msg"] = "扫描完成";
|
|
result["macId"] = macId;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (dberp != null && dberp.InTransaction)
|
|
dberp.RollbackTrans();
|
|
|
|
result["success"] = false;
|
|
result["msg"] = ex.Message;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据 MACID 查询已扫描的服务方法数据。
|
|
/// </summary>
|
|
/// <param name="macId">服务部件ID(程序集名称)。</param>
|
|
/// <returns>包含各表数据的结果。</returns>
|
|
[AjaxMethod(AuthRequried = false)]
|
|
public static Dictionary<string, object> GetServiceMethodData(string macId)
|
|
{
|
|
Dictionary<string, object> result = new Dictionary<string, object>();
|
|
TDatabase dberp = null;
|
|
|
|
try
|
|
{
|
|
dberp = TContextDatabases.GetDatabase("DBERP");
|
|
|
|
result["SRCMD"] = QueryTableByMacId(dberp, "SRCMD", macId);
|
|
result["SRCMETHOD"] = QueryTableByMacId(dberp, "SRCMETHOD", macId);
|
|
result["SRCMETHODPARAMS"] = QueryTableByMacId(dberp, "SRCMETHODPARAMS", macId);
|
|
result["SRCTYPE"] = QueryAll(dberp, "SRCTYPE");
|
|
result["SRCPROP"] = QueryAll(dberp, "SRCPROP");
|
|
result["success"] = true;
|
|
result["msg"] = "";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
result["success"] = false;
|
|
result["msg"] = ex.Message;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#region 数据库操作
|
|
|
|
private static void DeleteOldModuleData(TDatabase dberp, string macId)
|
|
{
|
|
string[] tables = new string[] { "SRCMETHODPARAMS", "SRCMETHOD", "SRCMD" };
|
|
TSQL sql = new TSQL(dberp);
|
|
foreach (string table in tables)
|
|
{
|
|
sql.Clear();
|
|
sql.Add("delete from " + table + " where MACID=:pMACID");
|
|
sql.ParamByName("pMACID").Value = macId;
|
|
dberp.ExecSQL(sql);
|
|
}
|
|
}
|
|
|
|
private static void DeleteTypeData(TDatabase dberp, string typeFullName)
|
|
{
|
|
TSQL sql = new TSQL(dberp);
|
|
sql.Clear();
|
|
sql.Add("delete from SRCPROP where TYPEFULLNAME=:pTYPEFULLNAME");
|
|
sql.ParamByName("pTYPEFULLNAME").Value = typeFullName;
|
|
dberp.ExecSQL(sql);
|
|
|
|
sql.Clear();
|
|
sql.Add("delete from SRCTYPE where TYPEFULLNAME=:pTYPEFULLNAME");
|
|
sql.ParamByName("pTYPEFULLNAME").Value = typeFullName;
|
|
dberp.ExecSQL(sql);
|
|
}
|
|
|
|
private static List<Dictionary<string, object>> QueryTableByMacId(TDatabase dberp, string tableName, string macId)
|
|
{
|
|
TSQL sql = new TSQL(dberp);
|
|
sql.Add("select " + GetTableColumns(tableName) + " from " + tableName + " where MACID=:pMACID");
|
|
sql.ParamByName("pMACID").Value = macId;
|
|
DataSet ds = dberp.OpenDataSet(sql);
|
|
return DataTableToList(ds.Tables[0]);
|
|
}
|
|
|
|
private static List<Dictionary<string, object>> QueryAll(TDatabase dberp, string tableName)
|
|
{
|
|
TSQL sql = new TSQL(dberp);
|
|
sql.Add("select " + GetTableColumns(tableName) + " from " + tableName);
|
|
DataSet ds = dberp.OpenDataSet(sql);
|
|
return DataTableToList(ds.Tables[0]);
|
|
}
|
|
|
|
private static string GetTableColumns(string tableName)
|
|
{
|
|
switch (tableName)
|
|
{
|
|
case "SRCMD":
|
|
return "MACID, MDID, MDNAME";
|
|
case "SRCMETHOD":
|
|
return "MACID, MDID, METHODNAME, MODIFIERS, AUTHREQUIRED, USEHTTPGET, METHODDESC, RETTYPE, RETDESC";
|
|
case "SRCMETHODPARAMS":
|
|
return "MACID, MDID, METHODNAME, PARAMXH, PARAMNAME, PARAMTYPE, PARAMDESC";
|
|
case "SRCTYPE":
|
|
return "TYPEFULLNAME, NAMESPACE, TYPENAME, TYPEDESC";
|
|
case "SRCPROP":
|
|
return "TYPEFULLNAME, PROPNAME, PROPTYPEFULLNAME, NAMESPACE, PROPTYPE, PROPDESC";
|
|
default:
|
|
return "*";
|
|
}
|
|
}
|
|
|
|
private static List<Dictionary<string, object>> DataTableToList(DataTable dt)
|
|
{
|
|
List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
|
|
foreach (DataRow row in dt.Rows)
|
|
{
|
|
Dictionary<string, object> item = new Dictionary<string, object>();
|
|
foreach (DataColumn col in dt.Columns)
|
|
{
|
|
object val = row[col];
|
|
item[col.ColumnName] = val == DBNull.Value ? null : val;
|
|
}
|
|
list.Add(item);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private static void InsertSRCMD(TDatabase dberp, string macId, double mdId, string mdName)
|
|
{
|
|
TSQL sql = new TSQL(dberp);
|
|
sql.Clear();
|
|
sql.Add("insert into SRCMD(MACID, MDID, MDNAME) values(:pMACID, :pMDID, :pMDNAME)");
|
|
sql.ParamByName("pMACID").Value = macId;
|
|
sql.ParamByName("pMDID").Value = mdId;
|
|
sql.ParamByName("pMDNAME").Value = mdName;
|
|
dberp.ExecSQL(sql);
|
|
}
|
|
|
|
private static void InsertSRCMETHOD(TDatabase dberp, string macId, double mdId, string methodName,
|
|
string modifiers, string authRequired, string useHttpGet, string methodDesc,
|
|
string retType, string retDesc)
|
|
{
|
|
TSQL sql = new TSQL(dberp);
|
|
sql.Clear();
|
|
sql.Add("insert into SRCMETHOD(MACID, MDID, METHODNAME, MODIFIERS, AUTHREQUIRED, USEHTTPGET, METHODDESC, RETTYPE, RETDESC) ");
|
|
sql.Add("values(:pMACID, :pMDID, :pMETHODNAME, :pMODIFIERS, :pAUTHREQUIRED, :pUSEHTTPGET, :pMETHODDESC, :pRETTYPE, :pRETDESC)");
|
|
sql.ParamByName("pMACID").Value = macId;
|
|
sql.ParamByName("pMDID").Value = mdId;
|
|
sql.ParamByName("pMETHODNAME").Value = methodName;
|
|
sql.ParamByName("pMODIFIERS").Value = modifiers;
|
|
sql.ParamByName("pAUTHREQUIRED").Value = authRequired;
|
|
sql.ParamByName("pUSEHTTPGET").Value = useHttpGet;
|
|
sql.ParamByName("pMETHODDESC").Value = methodDesc;
|
|
sql.ParamByName("pRETTYPE").Value = retType;
|
|
sql.ParamByName("pRETDESC").Value = retDesc;
|
|
dberp.ExecSQL(sql);
|
|
}
|
|
|
|
private static void InsertSRCMETHODPARAMS(TDatabase dberp, string macId, double mdId, string methodName,
|
|
double paramXh, string paramName, string paramType, string paramDesc)
|
|
{
|
|
TSQL sql = new TSQL(dberp);
|
|
sql.Clear();
|
|
sql.Add("insert into SRCMETHODPARAMS(MACID, MDID, METHODNAME, PARAMXH, PARAMNAME, PARAMTYPE, PARAMDESC) ");
|
|
sql.Add("values(:pMACID, :pMDID, :pMETHODNAME, :pPARAMXH, :pPARAMNAME, :pPARAMTYPE, :pPARAMDESC)");
|
|
sql.ParamByName("pMACID").Value = macId;
|
|
sql.ParamByName("pMDID").Value = mdId;
|
|
sql.ParamByName("pMETHODNAME").Value = methodName;
|
|
sql.ParamByName("pPARAMXH").Value = paramXh;
|
|
sql.ParamByName("pPARAMNAME").Value = paramName;
|
|
sql.ParamByName("pPARAMTYPE").Value = paramType;
|
|
sql.ParamByName("pPARAMDESC").Value = paramDesc;
|
|
dberp.ExecSQL(sql);
|
|
}
|
|
|
|
private static void InsertSRCTYPE(TDatabase dberp, string typeFullName, string nameSpace,
|
|
string typeName, string typeDesc)
|
|
{
|
|
TSQL sql = new TSQL(dberp);
|
|
sql.Clear();
|
|
sql.Add("insert into SRCTYPE(TYPEFULLNAME, NAMESPACE, TYPENAME, TYPEDESC) ");
|
|
sql.Add("values(:pTYPEFULLNAME, :pNAMESPACE, :pTYPENAME, :pTYPEDESC)");
|
|
sql.ParamByName("pTYPEFULLNAME").Value = typeFullName;
|
|
sql.ParamByName("pNAMESPACE").Value = nameSpace;
|
|
sql.ParamByName("pTYPENAME").Value = typeName;
|
|
sql.ParamByName("pTYPEDESC").Value = typeDesc;
|
|
dberp.ExecSQL(sql);
|
|
}
|
|
|
|
private static void InsertSRCPROP(TDatabase dberp, string typeFullName, string propName,
|
|
string propTypeFullName, string nameSpace, string propType, string propDesc)
|
|
{
|
|
TSQL sql = new TSQL(dberp);
|
|
sql.Clear();
|
|
sql.Add("insert into SRCPROP(TYPEFULLNAME, PROPNAME, PROPTYPEFULLNAME, NAMESPACE, PROPTYPE, PROPDESC) ");
|
|
sql.Add("values(:pTYPEFULLNAME, :pPROPNAME, :pPROPTYPEFULLNAME, :pNAMESPACE, :pPROPTYPE, :pPROPDESC)");
|
|
sql.ParamByName("pTYPEFULLNAME").Value = typeFullName;
|
|
sql.ParamByName("pPROPNAME").Value = propName;
|
|
sql.ParamByName("pPROPTYPEFULLNAME").Value = propTypeFullName;
|
|
sql.ParamByName("pNAMESPACE").Value = nameSpace;
|
|
sql.ParamByName("pPROPTYPE").Value = propType;
|
|
sql.ParamByName("pPROPDESC").Value = propDesc;
|
|
dberp.ExecSQL(sql);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 反射与类型辅助
|
|
|
|
private static Dictionary<string, ServiceMethodInfo> GetServiceMethods(Type classType)
|
|
{
|
|
if (classType == null)
|
|
return null;
|
|
|
|
List<Type> typeList = new List<Type>();
|
|
Type current = classType;
|
|
typeList.Add(current);
|
|
while (current.BaseType != null)
|
|
{
|
|
current = current.BaseType;
|
|
if (current != typeof(object))
|
|
typeList.Add(current);
|
|
}
|
|
|
|
Dictionary<string, ServiceMethodInfo> methods = new Dictionary<string, ServiceMethodInfo>(StringComparer.OrdinalIgnoreCase);
|
|
BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
|
|
BindingFlags.Static | BindingFlags.Instance;
|
|
|
|
for (int i = typeList.Count - 1; i >= 0; --i)
|
|
{
|
|
MethodInfo[] methodInfos = typeList[i].GetMethods(flags);
|
|
foreach (MethodInfo method in methodInfos)
|
|
{
|
|
object[] attribs = method.GetCustomAttributes(typeof(AjaxMethodAttribute), true);
|
|
if (attribs.Length > 0)
|
|
{
|
|
AjaxMethodAttribute ajaxAttr = (AjaxMethodAttribute)attribs[0];
|
|
ServiceMethodInfo smi = new ServiceMethodInfo(method, ajaxAttr);
|
|
smi.LoadMethodParameters();
|
|
methods[smi.MethodName] = smi;
|
|
}
|
|
}
|
|
}
|
|
return methods;
|
|
}
|
|
|
|
private static string GetMethodModifiers(MethodInfo method)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
if (method.IsPublic)
|
|
sb.Append("public ");
|
|
else if (method.IsPrivate)
|
|
sb.Append("private ");
|
|
else if (method.IsFamily)
|
|
sb.Append("protected ");
|
|
else if (method.IsAssembly)
|
|
sb.Append("internal ");
|
|
|
|
if (method.IsStatic)
|
|
sb.Append("static ");
|
|
|
|
return sb.ToString().Trim();
|
|
}
|
|
|
|
private static void ReflectType(Type type, TDatabase dberp,
|
|
Dictionary<string, string> visitedTypes, XmlDocHelper xmlDoc)
|
|
{
|
|
if (type == null)
|
|
return;
|
|
|
|
if (type.IsByRef || type.IsPointer)
|
|
{
|
|
ReflectType(type.GetElementType(), dberp, visitedTypes, xmlDoc);
|
|
return;
|
|
}
|
|
|
|
if (type.IsArray)
|
|
{
|
|
ReflectType(type.GetElementType(), dberp, visitedTypes, xmlDoc);
|
|
return;
|
|
}
|
|
|
|
Type underlying = Nullable.GetUnderlyingType(type);
|
|
if (underlying != null)
|
|
{
|
|
ReflectType(underlying, dberp, visitedTypes, xmlDoc);
|
|
return;
|
|
}
|
|
|
|
if (type.IsGenericType)
|
|
{
|
|
Type[] args = type.GetGenericArguments();
|
|
foreach (Type arg in args)
|
|
ReflectType(arg, dberp, visitedTypes, xmlDoc);
|
|
|
|
Type def = type.GetGenericTypeDefinition();
|
|
if (!IsCustomType(def))
|
|
return;
|
|
|
|
type = def;
|
|
}
|
|
|
|
if (!IsCustomType(type))
|
|
return;
|
|
|
|
string key = type.FullName;
|
|
if (string.IsNullOrEmpty(key))
|
|
return;
|
|
if (visitedTypes.ContainsKey(key))
|
|
return;
|
|
visitedTypes[key] = key;
|
|
|
|
string typeFullName = type.FullName.Replace('+', '.');
|
|
|
|
// 先清理该类型旧数据,再重新写入
|
|
DeleteTypeData(dberp, typeFullName);
|
|
|
|
InsertSRCTYPE(
|
|
dberp,
|
|
Truncate(typeFullName, 80),
|
|
Truncate(type.Namespace, 80),
|
|
Truncate(GetTypeShortName(type), 80),
|
|
Truncate(xmlDoc.GetSummary(type), 1000));
|
|
|
|
List<MemberInfo> members = new List<MemberInfo>();
|
|
members.AddRange(type.GetProperties(BindingFlags.Public | BindingFlags.Instance));
|
|
members.AddRange(type.GetFields(BindingFlags.Public | BindingFlags.Instance));
|
|
members.Sort(new MemberNameComparer());
|
|
|
|
foreach (MemberInfo mi in members)
|
|
{
|
|
Type memberType = null;
|
|
if (mi is PropertyInfo)
|
|
memberType = ((PropertyInfo)mi).PropertyType;
|
|
else if (mi is FieldInfo)
|
|
memberType = ((FieldInfo)mi).FieldType;
|
|
else
|
|
continue;
|
|
|
|
string propTypeFullName = memberType.FullName == null ? memberType.Name : memberType.FullName.Replace('+', '.');
|
|
|
|
InsertSRCPROP(
|
|
dberp,
|
|
Truncate(typeFullName, 80),
|
|
Truncate(mi.Name, 32),
|
|
Truncate(propTypeFullName, 80),
|
|
Truncate(memberType.Namespace, 80),
|
|
Truncate(GetTypeDisplayName(memberType), 80),
|
|
Truncate(xmlDoc.GetSummary(mi), 250));
|
|
|
|
ReflectType(memberType, dberp, visitedTypes, xmlDoc);
|
|
}
|
|
}
|
|
|
|
private static bool IsCustomType(Type type)
|
|
{
|
|
if (type == null)
|
|
return false;
|
|
if (type.IsGenericParameter)
|
|
return false;
|
|
if (type.IsPrimitive)
|
|
return false;
|
|
if (type == typeof(string) || type == typeof(object) || type == typeof(decimal)
|
|
|| type == typeof(DateTime) || type == typeof(TimeSpan) || type == typeof(Guid))
|
|
return false;
|
|
if (type.Namespace != null &&
|
|
(type.Namespace.StartsWith("System") || type.Namespace.StartsWith("Microsoft")))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
private static string GetTypeDisplayName(Type type)
|
|
{
|
|
if (type == null)
|
|
return "";
|
|
|
|
if (type.IsByRef)
|
|
return GetTypeDisplayName(type.GetElementType()) + "&";
|
|
if (type.IsPointer)
|
|
return GetTypeDisplayName(type.GetElementType()) + "*";
|
|
if (type.IsArray)
|
|
return GetTypeDisplayName(type.GetElementType()) + "[]";
|
|
|
|
Type underlying = Nullable.GetUnderlyingType(type);
|
|
if (underlying != null)
|
|
return GetTypeDisplayName(underlying) + "?";
|
|
|
|
if (type.IsGenericType)
|
|
{
|
|
Type def = type.GetGenericTypeDefinition();
|
|
string baseName = def.FullName;
|
|
if (string.IsNullOrEmpty(baseName))
|
|
baseName = type.Name;
|
|
baseName = baseName.Replace('+', '.');
|
|
int backtick = baseName.IndexOf('`');
|
|
string cleanName = backtick > 0 ? baseName.Substring(0, backtick) : baseName;
|
|
|
|
Type[] genericArgs = type.GetGenericArguments();
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.Append(cleanName);
|
|
sb.Append("<");
|
|
for (int i = 0; i < genericArgs.Length; i++)
|
|
{
|
|
sb.Append(GetTypeDisplayName(genericArgs[i]));
|
|
if (i < genericArgs.Length - 1)
|
|
sb.Append(", ");
|
|
}
|
|
sb.Append(">");
|
|
return sb.ToString();
|
|
}
|
|
|
|
if (type.FullName == null)
|
|
return type.Name;
|
|
return type.FullName.Replace('+', '.');
|
|
}
|
|
|
|
private static string GetTypeShortName(Type type)
|
|
{
|
|
if (type == null)
|
|
return "";
|
|
string name = type.Name;
|
|
int backtick = name.IndexOf('`');
|
|
if (backtick > 0)
|
|
name = name.Substring(0, backtick);
|
|
return name;
|
|
}
|
|
|
|
private static string Truncate(string value, int maxLength)
|
|
{
|
|
if (string.IsNullOrEmpty(value))
|
|
return string.Empty;
|
|
if (value.Length > maxLength)
|
|
return value.Substring(0, maxLength);
|
|
return value;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 嵌套辅助类
|
|
|
|
/// <summary>
|
|
/// 服务方法信息。
|
|
/// </summary>
|
|
private class ServiceMethodInfo
|
|
{
|
|
internal ServiceMethodInfo(MethodInfo methodInfo, AjaxMethodAttribute methodAttribute)
|
|
{
|
|
_methodInfo = methodInfo;
|
|
_methodName = methodInfo.Name;
|
|
_isPublic = methodInfo.IsPublic;
|
|
_isStatic = methodInfo.IsStatic;
|
|
_returnType = methodInfo.ReturnType;
|
|
_authRequried = methodAttribute.AuthRequried;
|
|
_useHttpGet = methodAttribute.UseHttpGet;
|
|
}
|
|
|
|
private MethodInfo _methodInfo;
|
|
internal MethodInfo MethodInfo
|
|
{
|
|
get { return _methodInfo; }
|
|
}
|
|
|
|
private string _methodName;
|
|
public string MethodName
|
|
{
|
|
get { return _methodName == null ? string.Empty : _methodName; }
|
|
set { _methodName = value; }
|
|
}
|
|
|
|
private bool _isPublic;
|
|
public bool IsPublic
|
|
{
|
|
get { return _isPublic; }
|
|
set { _isPublic = value; }
|
|
}
|
|
|
|
private bool _isStatic;
|
|
public bool IsStatic
|
|
{
|
|
get { return _isStatic; }
|
|
set { _isStatic = value; }
|
|
}
|
|
|
|
private Type _returnType;
|
|
public Type ReturnType
|
|
{
|
|
get { return _returnType; }
|
|
set { _returnType = value; }
|
|
}
|
|
|
|
private bool _authRequried;
|
|
public bool AuthRequried
|
|
{
|
|
get { return _authRequried; }
|
|
set { _authRequried = value; }
|
|
}
|
|
|
|
private bool _useHttpGet;
|
|
public bool UseHttpGet
|
|
{
|
|
get { return _useHttpGet; }
|
|
set { _useHttpGet = value; }
|
|
}
|
|
|
|
private List<ServiceParameterInfo> _parameterList;
|
|
public List<ServiceParameterInfo> ParameterList
|
|
{
|
|
get { return _parameterList; }
|
|
set { _parameterList = value; }
|
|
}
|
|
|
|
internal void LoadMethodParameters()
|
|
{
|
|
if (_methodInfo == null)
|
|
return;
|
|
|
|
List<ServiceParameterInfo> list = new List<ServiceParameterInfo>();
|
|
int index = 0;
|
|
foreach (ParameterInfo param in _methodInfo.GetParameters())
|
|
{
|
|
list.Add(new ServiceParameterInfo(param, index));
|
|
index++;
|
|
}
|
|
_parameterList = list;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 服务方法参数信息。
|
|
/// </summary>
|
|
private class ServiceParameterInfo
|
|
{
|
|
private ParameterInfo _param;
|
|
private int _index;
|
|
|
|
internal ServiceParameterInfo(ParameterInfo param, int index)
|
|
{
|
|
_param = param;
|
|
_index = index;
|
|
}
|
|
|
|
internal ParameterInfo ParameterInfo
|
|
{
|
|
get { return _param; }
|
|
}
|
|
|
|
internal int Index
|
|
{
|
|
get { return _index; }
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get { return _param.Name; }
|
|
}
|
|
|
|
public Type ParameterType
|
|
{
|
|
get { return _param.ParameterType; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// XML 文档注释读取辅助类。
|
|
/// </summary>
|
|
private class XmlDocHelper
|
|
{
|
|
private XPathDocument _doc;
|
|
private XPathNavigator _nav;
|
|
|
|
public XmlDocHelper(string dllPath)
|
|
{
|
|
if (string.IsNullOrEmpty(dllPath))
|
|
return;
|
|
|
|
string fullPath = Path.GetFullPath(dllPath);
|
|
string dir = Path.GetDirectoryName(fullPath);
|
|
string xmlPath = Path.Combine(dir, Path.GetFileNameWithoutExtension(fullPath) + ".xml");
|
|
if (!File.Exists(xmlPath))
|
|
return;
|
|
|
|
try
|
|
{
|
|
_doc = new XPathDocument(xmlPath);
|
|
_nav = _doc.CreateNavigator();
|
|
}
|
|
catch
|
|
{
|
|
_doc = null;
|
|
_nav = null;
|
|
}
|
|
}
|
|
|
|
public string GetSummary(Type type)
|
|
{
|
|
if (_nav == null || type == null)
|
|
return "";
|
|
string id = GetTypeDocId(type);
|
|
return GetChildText("T", id, "summary");
|
|
}
|
|
|
|
public string GetSummary(MemberInfo member)
|
|
{
|
|
if (_nav == null || member == null)
|
|
return "";
|
|
string prefix = "P";
|
|
if (member is FieldInfo)
|
|
prefix = "F";
|
|
else if (member is PropertyInfo)
|
|
prefix = "P";
|
|
else if (member is MethodInfo)
|
|
prefix = "M";
|
|
string id = GetMemberDocId(member);
|
|
return GetChildText(prefix, id, "summary");
|
|
}
|
|
|
|
public string GetMethodSummary(MethodInfo method)
|
|
{
|
|
XPathNavigator node = FindMethodNode(method);
|
|
if (node == null)
|
|
return "";
|
|
XPathNavigator sum = node.SelectSingleNode("summary");
|
|
return sum == null ? "" : sum.Value.Trim();
|
|
}
|
|
|
|
public string GetMethodReturns(MethodInfo method)
|
|
{
|
|
XPathNavigator node = FindMethodNode(method);
|
|
if (node == null)
|
|
return "";
|
|
XPathNavigator ret = node.SelectSingleNode("returns");
|
|
return ret == null ? "" : ret.Value.Trim();
|
|
}
|
|
|
|
public string GetParameterSummary(MethodInfo method, string paramName)
|
|
{
|
|
XPathNavigator node = FindMethodNode(method);
|
|
if (node == null || string.IsNullOrEmpty(paramName))
|
|
return "";
|
|
string expr = "param[@name='" + Escape(paramName) + "']";
|
|
XPathNavigator pn = node.SelectSingleNode(expr);
|
|
return pn == null ? "" : pn.Value.Trim();
|
|
}
|
|
|
|
private string GetChildText(string prefix, string id, string childName)
|
|
{
|
|
if (_nav == null)
|
|
return "";
|
|
string expr = "//member[@name='" + prefix + ":" + Escape(id) + "']";
|
|
XPathNavigator node = _nav.SelectSingleNode(expr);
|
|
if (node == null)
|
|
return "";
|
|
XPathNavigator child = node.SelectSingleNode(childName);
|
|
return child == null ? "" : child.Value.Trim();
|
|
}
|
|
|
|
private XPathNavigator FindMethodNode(MethodInfo method)
|
|
{
|
|
if (_nav == null || method == null)
|
|
return null;
|
|
|
|
string exactId = GetMethodDocId(method);
|
|
string expr = "//member[@name='M:" + Escape(exactId) + "']";
|
|
XPathNavigator node = _nav.SelectSingleNode(expr);
|
|
if (node != null)
|
|
return node;
|
|
|
|
string typeId = GetTypeDocId(method.DeclaringType);
|
|
string prefix = "M:" + Escape(typeId) + "." + method.Name;
|
|
XPathNodeIterator iter = _nav.Select("//member[starts-with(@name,'" + prefix + "')]");
|
|
int pCount = method.GetParameters().Length;
|
|
|
|
while (iter.MoveNext())
|
|
{
|
|
string name = iter.Current.GetAttribute("name", "");
|
|
int open = name.IndexOf('(');
|
|
int close = name.LastIndexOf(')');
|
|
if (open > 0 && close > open)
|
|
{
|
|
string sig = name.Substring(open + 1, close - open - 1);
|
|
int count = string.IsNullOrEmpty(sig) ? 0 : CountChar(sig, ',') + 1;
|
|
if (count == pCount)
|
|
return iter.Current.Clone();
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static string GetTypeDocId(Type type)
|
|
{
|
|
if (type == null)
|
|
return "";
|
|
string fullName = type.FullName;
|
|
if (string.IsNullOrEmpty(fullName))
|
|
return type.Name;
|
|
return fullName.Replace('+', '.');
|
|
}
|
|
|
|
private static string GetMemberDocId(MemberInfo member)
|
|
{
|
|
Type type = member.DeclaringType;
|
|
string typeId = GetTypeDocId(type);
|
|
if (member is MethodInfo)
|
|
return GetMethodDocId((MethodInfo)member);
|
|
return typeId + "." + member.Name;
|
|
}
|
|
|
|
private static string GetMethodDocId(MethodInfo method)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.Append(GetTypeDocId(method.DeclaringType));
|
|
sb.Append(".");
|
|
sb.Append(method.Name);
|
|
if (method.IsGenericMethod)
|
|
sb.Append("``").Append(method.GetGenericArguments().Length);
|
|
sb.Append("(");
|
|
ParameterInfo[] ps = method.GetParameters();
|
|
for (int i = 0; i < ps.Length; i++)
|
|
{
|
|
if (i > 0)
|
|
sb.Append(",");
|
|
sb.Append(GetParameterDocTypeName(ps[i].ParameterType));
|
|
}
|
|
sb.Append(")");
|
|
return sb.ToString();
|
|
}
|
|
|
|
private static string GetParameterDocTypeName(Type type)
|
|
{
|
|
if (type == null)
|
|
return "";
|
|
if (type.IsGenericParameter)
|
|
return type.Name;
|
|
if (type.IsByRef)
|
|
return GetParameterDocTypeName(type.GetElementType()) + "@";
|
|
if (type.IsPointer)
|
|
return GetParameterDocTypeName(type.GetElementType()) + "*";
|
|
if (type.IsArray)
|
|
return GetParameterDocTypeName(type.GetElementType()) + "[]";
|
|
|
|
Type underlying = Nullable.GetUnderlyingType(type);
|
|
if (underlying != null)
|
|
return GetParameterDocTypeName(underlying) + "?";
|
|
|
|
if (type.IsGenericType)
|
|
{
|
|
Type def = type.GetGenericTypeDefinition();
|
|
string baseName = def.FullName;
|
|
if (string.IsNullOrEmpty(baseName))
|
|
baseName = type.Name;
|
|
baseName = baseName.Replace('+', '.');
|
|
Type[] args = type.GetGenericArguments();
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.Append(baseName);
|
|
sb.Append("{");
|
|
for (int i = 0; i < args.Length; i++)
|
|
{
|
|
if (i > 0)
|
|
sb.Append(",");
|
|
sb.Append(GetParameterDocTypeName(args[i]));
|
|
}
|
|
sb.Append("}");
|
|
return sb.ToString();
|
|
}
|
|
|
|
string name = type.FullName;
|
|
if (string.IsNullOrEmpty(name))
|
|
name = type.Name;
|
|
return name.Replace('+', '.');
|
|
}
|
|
|
|
private static string Escape(string s)
|
|
{
|
|
if (s == null)
|
|
return "";
|
|
return s.Replace("'", "''");
|
|
}
|
|
|
|
private static int CountChar(string s, char c)
|
|
{
|
|
int count = 0;
|
|
for (int i = 0; i < s.Length; i++)
|
|
{
|
|
if (s[i] == c)
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 按成员名称排序的比较器。
|
|
/// </summary>
|
|
private class MemberNameComparer : IComparer<MemberInfo>
|
|
{
|
|
public int Compare(MemberInfo x, MemberInfo y)
|
|
{
|
|
return string.Compare(x.Name, y.Name, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|