ZhiYeJianKang_PeiXun/Song.ViewData/ExecuteMethod.cs
2025-02-20 15:41:53 +08:00

322 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Newtonsoft.Json;
using Song.ViewData.Attri;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Song.ViewData
{
/// <summary>
/// 执行具体的方法
/// </summary>
public class ExecuteMethod
{
#region
private static readonly ExecuteMethod _instance = new ExecuteMethod();
private ExecuteMethod() { }
/// <summary>
/// 返回实例
/// </summary>
/// <returns></returns>
public static ExecuteMethod GetInstance()
{
return _instance;
}
#endregion
#region
//存储对象的键值对key为对象的类名称全名value为对象自身
private Dictionary<string, object> _objects = new Dictionary<string, object>();
/// <summary>
/// 创建对象,如果存在,则直接返回;如果不存在,创建后返回
/// </summary>
/// <param name="letter"></param>
/// <returns></returns>
public static object CreateInstance(Letter letter)
{
string assemblyName = "Song.ViewData";
string classFullName = String.Format("{0}.Methods.{1}", assemblyName, letter.ClassName);
object obj = null;
//由缓存中查找,是否存在
ExecuteMethod curr = ExecuteMethod.GetInstance();
foreach (KeyValuePair<string, object> kv in curr._objects)
{
if (classFullName.Trim().Equals(kv.Key, StringComparison.CurrentCultureIgnoreCase))
{
obj = kv.Value;
break;
}
}
if (obj != null) return obj;
//如果之前未创建,则重新创建
Type type = null;
Assembly assembly = Assembly.Load(assemblyName);
Type[] types = assembly.GetExportedTypes()
.Where(t => t.GetInterfaces().Contains(typeof(IViewAPI)))
.ToArray();
foreach (Type info in types)
{
if (info.FullName.Equals(classFullName, StringComparison.CurrentCultureIgnoreCase))
{
type = info;
break;
}
}
if (type == null) throw new Exception(
string.Format("调用的对象'{0}'不存在, 可能是'{1}'拼写错误",
classFullName, letter.ClassName));
obj = System.Activator.CreateInstance(type); //创建对象
ExecuteMethod.GetInstance()._objects.Add(type.FullName, obj); //记录到缓存
return obj;
}
#endregion
/// <summary>
/// 执行,按实际结果返回
/// </summary>
/// <param name="letter">客户端递交的参数信息</param>
/// <returns></returns>
public static object Exec(Letter letter)
{
//1.创建对象,即$api.get("account/single")中的account
object execObj = ExecuteMethod.CreateInstance(letter);
//2.获取要执行的方法,即$api.get("account/single")中的single
MethodInfo method = getMethod(execObj.GetType(), letter);
//3#.验证方法的特性,一是验证Http动词二是验证是否登录后操作三是验证权限
//----验证Http谓词访问限制
HttpAttribute.Verify(letter.HTTP_METHOD, method);
//LoginAttribute.Verify(method);
//----范围控制,本机或局域网,或同域
bool isRange = RangeAttribute.Verify(letter, method);
//----验证是否需要登录
LoginAttribute loginattr = LoginAttribute.Verify(method);
//4.构建执行该方法所需要的参数
object[] parameters = getInvokeParam(method, letter);
//5.执行方法,返回结果
object objResult = null; //结果
//只有get方式时才使用缓存
CacheAttribute cache = null;
if (letter.HTTP_METHOD.Equals("put", StringComparison.CurrentCultureIgnoreCase))
CacheAttribute.Remove(method, letter);
if (letter.HTTP_METHOD.Equals("get", StringComparison.CurrentCultureIgnoreCase))
cache = CacheAttribute.GetAttr<CacheAttribute>(method);
if (cache != null)
{
objResult = CacheAttribute.GetResult(method, letter);
if (objResult == null)
{
objResult = method.Invoke(execObj, parameters);
CacheAttribute.Insert(cache.Expires, method, letter, objResult);
}
}
else
{
objResult = method.Invoke(execObj, parameters);
}
//将执行结果写入日志
LoginAttribute.LogWrite(loginattr, objResult);
return objResult;
}
/// <summary>
/// 执行返回结构封装到DataResult对象中
/// </summary>
/// <param name="letter">客户端递交的参数信息</param>
/// <returns></returns>
public static DataResult ExecToResult(Letter letter)
{
DateTime time = DateTime.Now;
try
{
if (!"weishakeji".Equals(letter.HTTP_Mark))
throw VExcept.System("请求标识不正确", 100);
//执行方法
object res = Exec(letter);
//计算耗时
double span = ((TimeSpan)(DateTime.Now - time)).TotalMilliseconds;
//
//如果是分页数据
if (res is ListResult)
{
ListResult list = (ListResult)res;
list.ExecSpan = span;
return list;
}
return new Song.ViewData.DataResult(res, span); //普通数据
}
catch (Exception ex)
{
//如果是自定义异常
if (ex.InnerException is VExcept)
{
VExcept except = (VExcept)ex.InnerException;
return new Song.ViewData.DataResult(except, time);
}
return new Song.ViewData.DataResult(ex, time);
}
}
/// <summary>
/// 要执行的方法,根据方法名、参数数量
/// </summary>
/// <param name="type">要调用的对象的类型</param>
/// <param name="p"></param>
/// <returns></returns>
private static MethodInfo getMethod(Type type, Letter p)
{
//1、先判断方法是否存在
List<MethodInfo> methods = new List<MethodInfo>();
foreach (MethodInfo mi in type.GetMethods())
{
if (p.MethodName.Equals(mi.Name, StringComparison.CurrentCultureIgnoreCase))
methods.Add(mi);
}
if (methods.Count < 1)
throw new Exception(string.Format("调用方法'{0}.{1}'不存在", p.ClassName, p.MethodName));
//2、判断方法的参数名称是否与传递来的参数名称匹配参数数量必须匹配
//只有一个参数且类型是Letter
MethodInfo mbLetter = null;
for (int i = 0; i < methods.Count; i++)
{
ParameterInfo[] pis = methods[i].GetParameters();
if (pis.Length == 1 && p.GetType().FullName.Equals(pis[0].ParameterType.FullName))
{
mbLetter = methods[i];
methods.Remove(methods[i]);
break;
}
}
MethodInfo method = null;
foreach (MethodInfo mi in methods)
{
//2-1、判断参数个数是否相同
int paraCount = 0;
foreach (ParameterInfo pi in mi.GetParameters())
{
if (!pi.IsOut) paraCount++;
}
//方法的参数个数,和传参的参数个数,必须相等
if (paraCount == p.Params.Count)
{
method = mi;
break;
}
}
//2-2、判断参数名称与传递来的参数名称是否一致
if (method != null)
{
bool ismatch = true; //是否匹配
foreach (ParameterInfo pi in method.GetParameters())
{
//如果参数是Parameter类型则跳过匹配
if (p.GetType().FullName.Equals(pi.ParameterType.FullName)) continue;
//只要有一个参数不匹配,即中断
if (!p.ExistParameter(pi.Name))
{
ismatch = false;
break;
}
}
if (!ismatch) method = null;
}
if (method == null) method = mbLetter;
if (method == null) throw new Exception(
string.Format("所调用方法'{0}.{1}'的参数名称与实际传参不匹配;实际传参:{2}",
type.FullName, p.MethodName,
p.ToString() == string.Empty ? "null" : p.ToString()));
return method;
}
/// <summary>
/// 返回方法执行所需要的参数
/// </summary>
/// <param name="method">要执行的方法</param>
/// <param name="letter">传递来的参数</param>
/// <returns></returns>
private static object[] getInvokeParam(MethodInfo method, Letter letter)
{
ParameterInfo[] paramInfos = method.GetParameters();
object[] objs = new object[paramInfos.Length];
for (int i = 0; i < objs.Length; i++)
{
ParameterInfo pi = paramInfos[i];
//如果参数是Letter类型则直接赋值
if (letter.GetType().FullName.Equals(pi.ParameterType.FullName))
{
objs[i] = letter;
continue;
}
//接口方法的参数所对应的客户端传来的值
string val = letter[pi.Name].String;
//如果参数为输出型的则不赋值ViewData接口不允许此类参数
if (pi.IsOut || string.IsNullOrWhiteSpace(val))
{
objs[i] = null;
continue;
}
//如果参数是数据实体
if (pi.ParameterType.BaseType != null && pi.ParameterType.BaseType.FullName == "WeiSha.Data.Entity")
{
//创建实体
object entity = pi.ParameterType.Assembly.CreateInstance(pi.ParameterType.FullName);
Dictionary<string, string> dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(val);
PropertyInfo[] props = pi.ParameterType.GetProperties();
for (int j = 0; j < props.Length; j++)
{
PropertyInfo opi = props[j]; //实体属性
foreach (KeyValuePair<string, string> kv in dic)
{
if (kv.Key.Equals(opi.Name, StringComparison.CurrentCultureIgnoreCase))
{
//实体属性的值
object tm = string.IsNullOrEmpty(kv.Value) ? null : WeiSha.Common.DataConvert.ChangeType(kv.Value, opi.PropertyType);
opi.SetValue(entity, tm, null);
continue;
}
}
}
objs[i] = entity;
continue;
}
//将客户端传来的参数,转换为方法对应的参数类型
if (!pi.ParameterType.Name.Equals("string", StringComparison.CurrentCultureIgnoreCase))
{
if (string.IsNullOrWhiteSpace(val)) throw new Exception("参数 " + pi.Name + " 的值为空");
}
try
{
switch (pi.ParameterType.Name)
{
case "DateTime":
if (val == null || string.IsNullOrWhiteSpace(val.ToString()))
{
objs[i] = DateTime.Now;
break;
}
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
long lTime = long.Parse(val + "0000");
TimeSpan toNow = new TimeSpan(lTime);
objs[i] = dt.Add(toNow);
break;
default:
objs[i] = Convert.ChangeType(val, pi.ParameterType);
break;
}
}
catch
{
throw new Exception("参数 " + pi.Name + " 的值,数据格式不正确");
}
}
return objs;
}
}
}