You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
5.8 KiB
179 lines
5.8 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
|
|
namespace Apewer.Web
|
|
{
|
|
|
|
/// <summary></summary>
|
|
public sealed class ApiApplication : IToJson
|
|
{
|
|
|
|
#region fields
|
|
|
|
Type _type = null;
|
|
string _module = null;
|
|
|
|
// ApiAttribute
|
|
string _name = null;
|
|
string _caption = null;
|
|
string _description = null;
|
|
|
|
// invoke & enumerate
|
|
bool _independent = false;
|
|
bool _hidden = false;
|
|
|
|
// functions
|
|
Dictionary<string, ApiFunction> _dict = new Dictionary<string, ApiFunction>();
|
|
List<ApiFunction> _list = new List<ApiFunction>();
|
|
|
|
#endregion
|
|
|
|
#region properties
|
|
|
|
/// <summary></summary>
|
|
public Type Type { get => _type; }
|
|
|
|
/// <summary></summary>
|
|
public string Module { get => _module; }
|
|
|
|
/// <summary></summary>
|
|
public string Name { get => _name; }
|
|
|
|
/// <summary></summary>
|
|
public string Caption { get => _caption; }
|
|
|
|
/// <summary></summary>
|
|
public string Description { get => _description; }
|
|
|
|
/// <summary></summary>
|
|
public bool Independent { get => _independent; }
|
|
|
|
/// <summary></summary>
|
|
public bool Hidden { get => _hidden; }
|
|
|
|
/// <summary></summary>
|
|
public ApiFunction[] Functions { get => _list.ToArray(); }
|
|
|
|
#endregion
|
|
|
|
/// <summary></summary>
|
|
public ApiApplication(Type type, ApiAttribute api)
|
|
{
|
|
// type
|
|
_type = type;
|
|
|
|
// api
|
|
if (api == null)
|
|
{
|
|
_name = type?.Name;
|
|
}
|
|
else
|
|
{
|
|
_name = string.IsNullOrEmpty(api.Name) ? type?.Name : api.Name;
|
|
_caption = api.Caption;
|
|
_description = api.Description;
|
|
}
|
|
|
|
if (type != null)
|
|
{
|
|
// caption
|
|
if (string.IsNullOrEmpty(_caption))
|
|
{
|
|
var captions = type.GetCustomAttributes(typeof(CaptionAttribute), true);
|
|
if (captions.Length > 0)
|
|
{
|
|
var caption = (CaptionAttribute)captions[0];
|
|
_caption = caption.Title;
|
|
if (string.IsNullOrEmpty(_description))
|
|
{
|
|
_description = caption.Description;
|
|
}
|
|
}
|
|
}
|
|
|
|
// hidden
|
|
if (type.Contains<HiddenAttribute>(false)) _hidden = true;
|
|
|
|
// independent
|
|
if (type.Contains<IndependentAttribute>(false)) _independent = true;
|
|
|
|
// Module
|
|
var assemblyName = type.Assembly.GetName();
|
|
_module = TextUtility.Join("-", assemblyName.Name, assemblyName.Version.ToString());
|
|
|
|
// functions
|
|
var funcs = new Dictionary<string, ApiFunction>();
|
|
var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
|
|
foreach (var method in methods)
|
|
{
|
|
var func = ApiFunction.Parse(this, method);
|
|
if (func == null) continue;
|
|
|
|
var funcKey = func.Name.Lower();
|
|
if (funcs.ContainsKey(funcKey)) continue;
|
|
funcs.Add(funcKey, func);
|
|
}
|
|
_dict = funcs;
|
|
|
|
_list.AddRange(funcs.Values);
|
|
_list.Sort(new Comparison<ApiFunction>((a, b) => a.Name.CompareTo(b.Name)));
|
|
}
|
|
}
|
|
|
|
internal ApiFunction GetFunction(string name)
|
|
{
|
|
if (string.IsNullOrEmpty(name)) return null;
|
|
if (_dict.TryGetValue(name.ToLower(), out var func)) return func;
|
|
return null;
|
|
}
|
|
|
|
/// <summary></summary>
|
|
public Json ToJson() => ToJson(new ApiOptions());
|
|
|
|
internal Json ToJson(ApiOptions options)
|
|
{
|
|
if (Hidden) return null;
|
|
|
|
var json = Json.NewObject();
|
|
json.SetProperty("name", _name);
|
|
if (!string.IsNullOrEmpty(_caption)) json.SetProperty("caption", _caption);
|
|
if (!string.IsNullOrEmpty(_description)) json.SetProperty("description", _description);
|
|
if (options != null)
|
|
{
|
|
if (options.WithTypeName) json.SetProperty("type", _type.FullName);
|
|
if (options.WithModuleName) json.SetProperty("mudule", _module);
|
|
if (options.AllowEnumerate) json.SetProperty("functions", Json.From(_list));
|
|
}
|
|
return json;
|
|
}
|
|
|
|
/// <summary>解析类型,获取 <see cref="ApiApplication"/> 实例。</summary>
|
|
/// <param name="type">要解析的类型。</param>
|
|
/// <param name="requireAttribute">要求此类型拥有 Api 特性。</param>
|
|
/// <returns>解析成功返回实例,解析失败返回 NULL 值。</returns>
|
|
public static ApiApplication Parse(Type type, bool requireAttribute)
|
|
{
|
|
if (type == null) return null;
|
|
|
|
// 检查类型的属性。
|
|
if (!type.IsClass) return null;
|
|
if (type.IsAbstract) return null;
|
|
if (type.IsGenericType) return null;
|
|
if (type.GetGenericArguments().NotEmpty()) return null;
|
|
if (!RuntimeUtility.CanNew(type)) return null;
|
|
|
|
// 判断基类。
|
|
if (!typeof(ApiController).IsAssignableFrom(type)) return null;
|
|
|
|
// 检查类型的特性。
|
|
var apis = type.GetCustomAttributes(typeof(ApiAttribute), false);
|
|
var api = apis.Length > 0 ? (ApiAttribute)apis[0] : null;
|
|
if (requireAttribute && api == null) return null;
|
|
|
|
return new ApiApplication(type, api);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|