Browse Source

增加 IApiMiddleware 以支持中间件。

master
王厅 5 days ago
parent
commit
454710747a
  1. 12
      Apewer/Web/ApiContext.cs
  2. 34
      Apewer/Web/ApiInvoker.cs
  3. 104
      Apewer/Web/ApiProcessor.cs
  4. 13
      Apewer/Web/IApiMiddleware.cs

12
Apewer/Web/ApiContext.cs

@ -57,6 +57,18 @@ namespace Apewer.Web
#endregion #endregion
#region 中间件
Action<ApiContext> _middleware_callback = null;
/// <summary>设置中间件回调。</summary>
internal void SetMiddlewareCallback(Action<ApiContext> callback) => _middleware_callback = callback;
/// <summary>继续执行。</summary>
public void Next() => _middleware_callback?.Invoke(this);
#endregion
internal ApiContext(ApiInvoker invoker, ApiProvider provider, ApiEntries entries) internal ApiContext(ApiInvoker invoker, ApiProvider provider, ApiEntries entries)
{ {
if (invoker == null) throw new ArgumentNullException(nameof(invoker)); if (invoker == null) throw new ArgumentNullException(nameof(invoker));

34
Apewer/Web/ApiInvoker.cs

@ -11,7 +11,7 @@ namespace Apewer.Web
public sealed class ApiInvoker public sealed class ApiInvoker
{ {
#region #region default
private static ApiInvoker _default = new ApiInvoker(); private static ApiInvoker _default = new ApiInvoker();
@ -20,8 +20,7 @@ namespace Apewer.Web
#endregion #endregion
object _locker = new object(); #region 配置
bool _initialized = false;
/// <summary>获取或设置要使用的 API 入口。</summary> /// <summary>获取或设置要使用的 API 入口。</summary>
public ApiEntries Entries { get; set; } public ApiEntries Entries { get; set; }
@ -38,6 +37,29 @@ namespace Apewer.Web
/// <summary>输出前的检查。</summary> /// <summary>输出前的检查。</summary>
public ApiPreOutput PreOutput { get; set; } public ApiPreOutput PreOutput { get; set; }
#endregion
#region 中间件
private List<Type> _middlewares = new List<Type>();
/// <summary>中间件。</summary>
public Type[] Middlewares { get => _middlewares.ToArray(); }
/// <summary>添加中间件。</summary>
public void AddMiddleware<T>() where T : class, IApiMiddleware, new()
{
var type = typeof(T);
_middlewares.Add(type);
}
#endregion
#region 初始化
object _locker = new object();
bool _initialized = false;
/// <summary>执行初始化程序,每个 ApiInvoker 实例仅执行一次初始化。</summary> /// <summary>执行初始化程序,每个 ApiInvoker 实例仅执行一次初始化。</summary>
public void Initialize(Action action) public void Initialize(Action action)
{ {
@ -50,6 +72,10 @@ namespace Apewer.Web
} }
} }
#endregion
#region 调用
/// <summary>发起调用。</summary> /// <summary>发起调用。</summary>
/// <exception cref="ArgumentNullException" /> /// <exception cref="ArgumentNullException" />
public void Invoke(ApiProvider provider) public void Invoke(ApiProvider provider)
@ -74,6 +100,8 @@ namespace Apewer.Web
processor.Run(); processor.Run();
} }
#endregion
} }
} }

104
Apewer/Web/ApiProcessor.cs

@ -1,6 +1,8 @@
using Apewer.Network; using Apewer.Network;
using Apewer.Source; using Apewer.Source;
using System; using System;
using System.Collections.Generic;
using System.Data;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using static Apewer.Web.ApiUtility; using static Apewer.Web.ApiUtility;
@ -50,6 +52,7 @@ namespace Apewer.Web
} }
catch (Exception ex) catch (Exception ex)
{ {
ApiUtility.Exception(_context.Response, ex, _context.Options.WithException);
var message = ex.Message(); var message = ex.Message();
Logger.Internals.Error(typeof(ApiInvoker), message); Logger.Internals.Error(typeof(ApiInvoker), message);
} }
@ -141,32 +144,8 @@ namespace Apewer.Web
} }
} }
// 路由 // 中间件
if (_context.Options.UseRoute) InvokeMiddwares();
{
var path = _context?.Request?.Url?.AbsolutePath;
path = path.TrimEnd('/');
var action = _context.Entries.GetAction(path);
if (action != null)
{
_context.ApiAction = action;
Invoke(action);
return;
}
}
// 反射
if (_context.Options.UseReflection)
{
var appName = _context.Request.Application;
var application = _context.Entries.GetApplication(appName);
Invoke(application);
return;
}
// 未匹配到
_context.Response.Duration = Duration(_context.Beginning);
_context.Response.Model = new ApiStatusModel(404);
} }
#endregion #endregion
@ -277,6 +256,79 @@ namespace Apewer.Web
#endregion #endregion
#region middleware
Queue<Type> _mw_queue = null;
void MiddlewareNext(ApiContext context)
{
if (_mw_queue.Count < 1)
{
Route();
return;
}
// 创建下一个中间件的实例
var type = _mw_queue.Dequeue();
var instance = Activator.CreateInstance(type);
var middleware = instance as IApiMiddleware;
if (middleware == null) throw new Exception($"类型【{type.FullName}】不是有效的中间件。");
// 调用
middleware.Invoke(context);
}
// 调用中间件。
void InvokeMiddwares()
{
var types = _context.Invoker.Middlewares;
if (types.Length < 1)
{
Route();
return;
}
// 设置队列和回调。
_mw_queue = new Queue<Type>(types);
_context.SetMiddlewareCallback(MiddlewareNext);
// 执行。
MiddlewareNext(_context);
}
// 执行路由。
void Route()
{
// 路由
if (_context.Options.UseRoute)
{
var path = _context?.Request?.Url?.AbsolutePath;
path = path.TrimEnd('/');
var action = _context.Entries.GetAction(path);
if (action != null)
{
_context.ApiAction = action;
Invoke(action);
return;
}
}
// 反射
if (_context.Options.UseReflection)
{
var appName = _context.Request.Application;
var application = _context.Entries.GetApplication(appName);
Invoke(application);
return;
}
// 未匹配到
_context.Response.Duration = Duration(_context.Beginning);
_context.Response.Model = new ApiStatusModel(404);
}
#endregion
#region route #region route
// 执行 Action。 // 执行 Action。

13
Apewer/Web/IApiMiddleware.cs

@ -0,0 +1,13 @@
namespace Apewer.Web
{
/// <summary>中间件。</summary>
public interface IApiMiddleware
{
/// <summary>调用中间件。</summary>
void Invoke(ApiContext context);
}
}
Loading…
Cancel
Save