using Apewer.Network; using System; using System.Collections.Generic; using System.Net; using System.Reflection; #if NETFX using System.Web; #endif #if NETCORE using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; #endif namespace Apewer.Web { /// API 调用器。 public sealed class ApiInvoker { private static ApiInvoker _default = new ApiInvoker(); /// 默认的调用器。 public static ApiInvoker Default { get { return _default; } } #region instance private Dictionary _entries = null; /// 获取 API 入口的数量。 public int Entries { get { return _entries.Count; } } private void AddEntries(Dictionary entries) { if (entries == null || entries.Count < 0) return; var olds = _entries; if (olds != null) { foreach (var old in olds) { if (entries.ContainsKey(old.Key)) continue; entries.Add(old.Key, old.Value); } } var sorted = Sort(entries); _entries = sorted; } private void AddCurrent() => AddEntries(AppDomain.CurrentDomain.GetAssemblies()); /// 清除所有入口。 public void ClearEntries() { _entries = null; } /// 添加指定程序集的入口。 public void AddEntries(IEnumerable assemblies) => AddEntries(GetEntries(assemblies)); /// 添加指定程序集的入口。 public void AddEntries(Assembly assembly) => AddEntries(GetEntries(assembly)); private string Invoke(object context, Func func) { if (context == null) return "Context 无效。"; if (_entries == null) AddEntries(AppDomain.CurrentDomain.GetAssemblies()); var entries = _entries; // if (entries == null) return "Entries 无效。"; var processor = func(); processor.Invoker = this; processor.Entries = entries; return processor.Run(); } /// 执行。 public string Invoke(HttpListenerContext context) => Invoke(context, () => new ApiProcessorListener(context)); /// 从 Listener 发起 API 调用。 public static string Listener(HttpListenerContext context) => _default.Invoke(context); #if NETFX /// 执行。 public string Invoke(System.Web.HttpContext context) => Invoke(context, () => new ApiProcessorIIS(context)); /// 从 IIS 发起 API 调用。 public static string IIS(HttpContext context) => _default.Invoke(context); #endif #if NETCORE /// 执行。 public string Invoke(Microsoft.AspNetCore.Http.HttpContext context) => Invoke(context, () => new ApiProcessorCore(context)); /// 从 ASP.NET Core 发起 API 调用。 public static string AspNetCore(HttpContext context) => _default.Invoke(context); #endif #endregion #region entries static Dictionary Sort(Dictionary entries) { var names = new List(); names.AddRange(entries.Keys); names.Sort(); var sorted = new Dictionary(); foreach (var name in names) sorted.Add(name, entries[name]); return sorted; } static Dictionary GetEntries(Assembly assembly) { if (assembly == null) return new Dictionary(); var types = RuntimeUtility.GetTypes(assembly); return GetEntries(types); } static Dictionary GetEntries(IEnumerable assemblies) { var deduplicates = new List(); foreach (var assembly in assemblies) { if (assembly == null) continue; if (deduplicates.Contains(assembly)) continue; deduplicates.Add(assembly); } var all = new Dictionary(); foreach (var assembly in deduplicates) { var types = RuntimeUtility.GetTypes(assembly); var entries = GetEntries(types); foreach (var entry in entries) { if (all.ContainsKey(entry.Key)) continue; all.Add(entry.Key, entry.Value); } } return all; } static Dictionary GetEntries(IEnumerable types) { if (types == null) return null; var entries = new Dictionary(); foreach (var type in types) { var entry = GetEntry(type); if (entry == null) continue; if (entries.ContainsKey(entry.Name)) continue; entries.Add(entry.Name, entry); } return entries; } static ApiApplication GetEntry(Type type) { var application = GetApplication(type); if (application == null) return null; var methods = type.GetMethods(); var fes = new ObjectSet(true); foreach (var method in methods) { var function = GetFunction(application, method); if (function == null) continue; fes[function.Name] = function; } var fns = new List(); fns.AddRange(RuntimeUtility.GetOrigin(fes).Keys); fns.Sort(); foreach (var i in fns) application.Functions.Add(i, fes[i]); return application; } internal static ApiApplication GetApplication(Type type, bool checkAttribute = true) { if (type == null) return null; // Check Type Properties if (!type.IsClass) return null; if (type.IsAbstract) return null; if (type.IsGenericType) return null; // Check Type ApiAttributes var attributes = null as object[]; if (checkAttribute) { attributes = type.GetCustomAttributes(typeof(ApiAttribute), false); if (attributes.Length < 1) return null; } // Check Base if (!RuntimeUtility.IsInherits(type, typeof(ApiController))) return null; // Entry var entry = new ApiApplication(); entry.Type = type; entry.Assembly = type.Assembly; if (checkAttribute) { // Name var api = (ApiAttribute)attributes[0]; var name = api.Name; if (string.IsNullOrEmpty(name)) name = type.Name; name = name.ToLower(); entry.Name = name; // Caption entry.Caption = api.Caption; if (entry.Caption.Length < 1) { var captions = type.GetCustomAttributes(typeof(CaptionAttribute), true); if (captions.Length > 0) { var caption = (CaptionAttribute)captions[0]; entry.Caption = caption.Title; entry.Description = caption.Description; } } // Visible entry.Visible = api.Visible; if (entry.Visible) { if (type.ContainsAttribute(false)) { entry.Visible = false; } } } else { entry.Name = ""; entry.Caption = ""; entry.Visible = false; } // Independent if (type.ContainsAttribute(false)) { entry.Independent = true; } // Module entry.Module = TextUtility.Join("-", entry.Assembly.GetName().Name, entry.Assembly.GetName().Version.ToString()); return entry; } static ApiFunction GetFunction(ApiApplication application, MethodInfo method) { if (method == null) return null; // 滤除构造函数。 if (method.IsConstructor) return null; // 滤除继承的方法。 if (method.DeclaringType.Equals(typeof(object))) return null; if (method.DeclaringType.Equals(typeof(ApiController))) return null; // 滤除带参数的方法。 var parameters = method.GetParameters(); if (parameters.Length > 0) return null; // Entry var entry = new ApiFunction(); entry.Type = application.Type; entry.Assembly = application.Type.Assembly; entry.Method = method; entry.Name = method.Name.ToLower(); // Caption var captions = method.GetCustomAttributes(typeof(CaptionAttribute), true); if (captions.Length > 0) { var caption = (CaptionAttribute)captions[0]; entry.Caption = caption.Title; entry.Description = caption.Description; } // Visible entry.Visible = true; if (application.Visible) { var hidden = method.GetCustomAttributes(typeof(HiddenAttribute), false); if (hidden.Length > 0) entry.Visible = false; } else { entry.Visible = false; } // Returnable if (method.ReturnType.Equals(typeof(string))) { entry.Returnable = true; } return entry; } #endregion } }