|
|
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 {
/// <summary>API 调用器。</summary>
public sealed class ApiInvoker {
private static ApiInvoker _default = new ApiInvoker();
/// <summary>默认的调用器。</summary>
public static ApiInvoker Default { get { return _default; } }
#region instance
private Dictionary<string, ApiApplication> _entries = null;
/// <summary>获取 API 入口的数量。</summary>
public int Entries { get { return _entries.Count; } }
private void AddEntries(Dictionary<string, ApiApplication> 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());
/// <summary>清除所有入口。</summary>
public void ClearEntries() { _entries = null; }
/// <summary>添加指定程序集的入口。</summary>
public void AddEntries(IEnumerable<Assembly> assemblies) => AddEntries(GetEntries(assemblies));
/// <summary>添加指定程序集的入口。</summary>
public void AddEntries(Assembly assembly) => AddEntries(GetEntries(assembly));
private string Invoke(object context, Func<ApiProcessor> 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(); }
/// <summary>执行。</summary>
public string Invoke(HttpListenerContext context) => Invoke(context, () => new ApiProcessorListener(context));
/// <summary>从 Listener 发起 API 调用。</summary>
public static string Listener(HttpListenerContext context) => _default.Invoke(context);
#if NETFX
/// <summary>执行。</summary>
public string Invoke(System.Web.HttpContext context) => Invoke(context, () => new ApiProcessorIIS(context));
/// <summary>从 IIS 发起 API 调用。</summary>
public static string IIS(HttpContext context) => _default.Invoke(context);
#endif
#if NETCORE
/// <summary>执行。</summary>
public string Invoke(Microsoft.AspNetCore.Http.HttpContext context) => Invoke(context, () => new ApiProcessorCore(context));
/// <summary>从 ASP.NET Core 发起 API 调用。</summary>
public static string AspNetCore(HttpContext context) => _default.Invoke(context);
#endif
#endregion
#region entries
static Dictionary<string, ApiApplication> Sort(Dictionary<string, ApiApplication> entries) { var names = new List<string>(); names.AddRange(entries.Keys); names.Sort();
var sorted = new Dictionary<string, ApiApplication>(); foreach (var name in names) sorted.Add(name, entries[name]); return sorted; }
static Dictionary<string, ApiApplication> GetEntries(Assembly assembly) { if (assembly == null) return new Dictionary<string, ApiApplication>();
var types = RuntimeUtility.GetTypes(assembly); return GetEntries(types); }
static Dictionary<string, ApiApplication> GetEntries(IEnumerable<Assembly> assemblies) { var deduplicates = new List<Assembly>(); foreach (var assembly in assemblies) { if (assembly == null) continue; if (deduplicates.Contains(assembly)) continue; deduplicates.Add(assembly); }
var all = new Dictionary<string, ApiApplication>(); 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<string, ApiApplication> GetEntries(IEnumerable<Type> types) { if (types == null) return null; var entries = new Dictionary<string, ApiApplication>(); 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<ApiFunction>(true); foreach (var method in methods) { var function = GetFunction(application, method); if (function == null) continue; fes[function.Name] = function; }
var fns = new List<string>(); 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<HiddenAttribute>(false)) { entry.Visible = false; } } } else { entry.Name = ""; entry.Caption = ""; entry.Visible = false; }
// Independent
if (type.ContainsAttribute<IndependentAttribute>(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
}
}
|