5 Commits

  1. 24
      Apewer/ForbiddenException.cs
  2. 47
      Apewer/Json.cs
  3. 46
      Apewer/NotFoundException.cs
  4. 7
      Apewer/RedundanceException.cs
  5. 5
      Apewer/UnauthorizedException.cs
  6. 16
      Apewer/UnparallelAttribute.cs
  7. 14
      Apewer/Web/ApiAction.cs
  8. 7
      Apewer/Web/ApiApplication.cs
  9. 7
      Apewer/Web/ApiFunction.cs
  10. 81
      Apewer/Web/ApiProcessor.cs
  11. 8
      Apewer/Web/ApiUtility.cs
  12. 16
      Apewer/Web/IApiException.cs

24
Apewer/ForbiddenException.cs

@ -0,0 +1,24 @@
using Apewer.Web;
using System;
namespace Apewer
{
/// <summary>表示被禁止访问的错误。</summary>
public sealed class ForbiddenException : Exception, IApiException
{
const string DefaultMessage = "禁止访问。";
/// <summary>表示禁止访问的状态。</summary>
public string Status { get => "Forbidden"; }
/// <summary></summary>
public ForbiddenException(string message = DefaultMessage) : base(message.IsEmpty() ? DefaultMessage : message) { }
/// <summary></summary>
public override string ToString() => $"<ForbiddenException> {Message}";
}
}

47
Apewer/Json.cs

@ -85,6 +85,7 @@ namespace Apewer
if (value == null) return new JValue(null, JTokenType.Null);
if (value is Json json) return json?._jtoken ?? new JValue(null, JTokenType.Null);
if (value is DateTime dt) return new JValue(SerializeDateTime(dt));
if (value is byte[] bytes) return new JValue(SerializeBytes(bytes));
if (value is string) return new JValue(value);
if (value is bool) return new JValue(value);
@ -1290,6 +1291,7 @@ namespace Apewer
if (value == null) { json.AddItem(); }
else if (value is DateTime dt) { json.AddItem(SerializeDateTime(dt)); }
else if (value is byte[] bytes) { json.AddItem(SerializeBytes(bytes)); }
else if (value is bool) { json.AddItem((bool)value); }
else if (value is byte) { json.AddItem((byte)value); }
else if (value is sbyte) { json.AddItem((sbyte)value); }
@ -1401,6 +1403,7 @@ namespace Apewer
if (value == null) { json.SetProperty(field); }
else if (value is DateTime dt) { json.SetProperty(field, SerializeDateTime(dt)); }
else if (value is byte[] bytes) { json.SetProperty(field, SerializeBytes(bytes)); }
else if (value is bool) { json.SetProperty(field, (bool)value); }
else if (value is byte) { json.SetProperty(field, (byte)value); }
else if (value is sbyte) { json.SetProperty(field, (sbyte)value); }
@ -1959,6 +1962,7 @@ namespace Apewer
else if (pt.Equals(typeof(float))) setter.Invoke(entity, new object[] { Float(value) });
else if (pt.Equals(typeof(double))) setter.Invoke(entity, new object[] { Double(value) });
else if (pt.Equals(typeof(decimal))) setter.Invoke(entity, new object[] { Decimal(value) });
else if (pt.Equals(typeof(byte[]))) setter.Invoke(entity, new object[] { DeserializeBytes(value) });
else
{
var serializable = (force || _forceall);
@ -2539,6 +2543,47 @@ namespace Apewer
#endregion
#region Byte[]
static Func<byte[], string> _bytes_serializer = null;
static Func<object, byte[]> _bytes_deserializer = null;
/// <summary>自定义 Byte[] 序列化程序。</summary>
public static Func<byte[], string> BytesSerializer { get => _bytes_serializer; set => _bytes_serializer = value; }
/// <summary>自定义 Byte[] 反序列化程序。</summary>
public static Func<object, byte[]> BytesDeserializer { get => _bytes_deserializer; set => _bytes_deserializer = value; }
/// <summary>序列化 Byte[] 实例。</summary>
public static string SerializeBytes(byte[] bytes)
{
var serializer = _bytes_serializer;
if (serializer != null) return serializer.Invoke(bytes);
if (bytes == null) return null;
return Convert.ToBase64String(bytes);
}
/// <summary>反序列化 Byte[] 实例。</summary>
public static byte[] DeserializeBytes(object value)
{
var deserializer = _bytes_deserializer;
if (deserializer != null) return deserializer.Invoke(value);
try
{
if (value is byte[] bytes) return bytes;
if (value is string base64) return Convert.FromBase64String(base64);
return null;
}
catch
{
return null;
}
}
#endregion
#region DateTime
static Func<DateTime, string> _datetime_serializer = null;
@ -2559,7 +2604,7 @@ namespace Apewer
return ClockUtility.Lucid(dateTime);
}
/// <summary>序列化 DateTime 实例。</summary>
/// <summary>序列化 DateTime 实例。</summary>
public static DateTime DeserializeDateTime(object value)
{
var deserializer = _datetime_deserializer;

46
Apewer/NotFoundException.cs

@ -0,0 +1,46 @@
using Apewer.Web;
using System;
namespace Apewer
{
/// <summary>表示目标资源不存在的错误。</summary>
public class NotFoundException : Exception, IApiException
{
static string _default = FixMessage(null);
static string FixMessage(string message)
{
const string Preset = "Resource not found.";
if (message != null)
{
message = message.Trim();
if (!string.IsNullOrEmpty(message)) return message;
}
return Preset;
}
/// <summary>获取或设置默认消息。</summary>
public static string DefaultMessage { get => _default; set => _default = FixMessage(value); }
/// <summary>状态。</summary>
/// <value>Unauthorized</value>
public virtual string Status { get => "Not Found"; }
/// <summary>表示目标资源不存在的错误。</summary>
/// <remarks>默认消息:Operation is not authorized.</remarks>
public NotFoundException() : base(DefaultMessage) { }
/// <summary>表示目标资源不存在的错误。</summary>
/// <remarks>默认消息:Operation is not authorized.</remarks>
public NotFoundException(string message) : base(FixMessage(message)) { }
/// <summary>表示目标资源不存在的错误。</summary>
/// <remarks>默认消息:Operation is not authorized.</remarks>
public NotFoundException(string message, Exception innerException) : base(FixMessage(message), innerException) { }
}
}

7
Apewer/RedundanceException.cs

@ -1,9 +1,4 @@
using Apewer.Internals;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;
using System;
namespace Apewer
{

5
Apewer/UnauthorizedException.cs

@ -1,11 +1,12 @@
using System;
using Apewer.Web;
using System;
namespace Apewer
{
/// <summary>表示未授权的错误。</summary>
/// <remarks>默认消息:Operation is not authorized.</remarks>
public class UnauthorizedException : Exception
public class UnauthorizedException : Exception, IApiException
{
static string _default = FixMessage(null);

16
Apewer/UnparallelAttribute.cs

@ -0,0 +1,16 @@
using System;
namespace Apewer
{
/// <summary>表示方法不可并行。</summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class UnparallelAttribute : Attribute
{
/// <summary></summary>
public static implicit operator bool(UnparallelAttribute unparallel) => unparallel != null;
}
}

14
Apewer/Web/ApiAction.cs

@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace Apewer.Web
{
@ -19,6 +18,7 @@ namespace Apewer.Web
string _path = null;
HttpMethod[] _methods = null;
ApiParameter[] _parameters = null;
UnparallelAttribute _unparallel = null;
#endregion
@ -55,6 +55,9 @@ namespace Apewer.Web
}
}
/// <summary>不可并行。</summary>
public UnparallelAttribute Unparallel { get => _unparallel; }
/// <summary>生成 JSON 实例。</summary>
public Json ToJson() => ToJson(null);
@ -109,9 +112,10 @@ namespace Apewer.Web
/// <param name="path">URL 路径。</param>
/// <param name="methods">HTTP 方法。</param>
/// <param name="parameters">参数。</param>
/// <param name="unparallel">不可并行。</param>
/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
ApiAction(Type type, MethodInfo method, string path, HttpMethod[] methods, ApiParameter[] parameters)
ApiAction(Type type, MethodInfo method, string path, HttpMethod[] methods, ApiParameter[] parameters, UnparallelAttribute unparallel)
{
if (type == null) throw new ArgumentNullException(nameof(type));
if (method == null) throw new ArgumentNullException(nameof(method));
@ -128,6 +132,7 @@ namespace Apewer.Web
_path = path;
_methods = methods;
_parameters = parameters;
_unparallel = unparallel;
}
/// <summary>解析控制器类型,获取 API 活动。</summary>
@ -213,7 +218,10 @@ namespace Apewer.Web
parameters.Add(parameter);
}
var action = new ApiAction(type, method, path, httpMethods.ToArray(), parameters.ToArray());
// 不可并行
var unparallel = RuntimeUtility.GetAttribute<UnparallelAttribute>(method);
var action = new ApiAction(type, method, path, httpMethods.ToArray(), parameters.ToArray(), unparallel);
actions.Add(action);
}

7
Apewer/Web/ApiApplication.cs

@ -22,6 +22,7 @@ namespace Apewer.Web
// invoke & enumerate
bool _independent = false;
bool _hidden = false;
bool _unparallel = false;
// functions
Dictionary<string, ApiFunction> _dict = new Dictionary<string, ApiFunction>();
@ -52,6 +53,9 @@ namespace Apewer.Web
/// <summary></summary>
public bool Hidden { get => _hidden; }
/// <summary></summary>
public bool Unparallel { get => _unparallel; }
/// <summary></summary>
public ApiFunction[] Functions { get => _list.ToArray(); }
@ -98,6 +102,9 @@ namespace Apewer.Web
// independent
if (type.Contains<IndependentAttribute>(false)) _independent = true;
// unparallel
if (type.Contains<UnparallelAttribute>(false)) _unparallel = true;
// Module
var assemblyName = type.Assembly.GetName();
_module = TextUtility.Join("-", assemblyName.Name, assemblyName.Version.ToString());

7
Apewer/Web/ApiFunction.cs

@ -22,6 +22,7 @@ namespace Apewer.Web
string _description = null;
bool _hidden = false;
bool _unparallel = false;
#endregion
@ -51,6 +52,9 @@ namespace Apewer.Web
/// <summary></summary>
public bool Hidden { get => _hidden; }
/// <summary></summary>
public bool Unparallel { get => _unparallel; }
#endregion
/// <summary></summary>
@ -118,6 +122,9 @@ namespace Apewer.Web
// hidden
if (method.Contains<HiddenAttribute>(false)) _hidden = true;
// unparallel
if (method.Contains<UnparallelAttribute>(false)) _unparallel = true;
// 参数。
_parameters = parameters;
}

81
Apewer/Web/ApiProcessor.cs

@ -1,4 +1,5 @@
using Apewer.Network;
using Apewer.Internals;
using Apewer.Network;
using System;
using System.Collections.Generic;
using System.Net;
@ -305,7 +306,17 @@ namespace Apewer.Web
if (action != null)
{
_context.ApiAction = action;
InvokeAction(action);
if (action.Unparallel)
{
UnparallelLocker.InLock(GetUnparallelKey(action.MethodInfo), () =>
{
InvokeAction(action);
});
}
else
{
InvokeAction(action);
}
return;
}
}
@ -393,12 +404,25 @@ namespace Apewer.Web
}
else
{
// 创建默认控制器。
var controller = null as ApiController;
try
{
controller = CreateController(@default, _context);
InvokeFunction(controller, application, null, options, request, response);
var unparallel = @default.Contains<UnparallelAttribute>(false);
if (unparallel)
{
UnparallelLocker.InLock(GetUnparallelKey(@default), () =>
{
controller = CreateController(@default, _context);
InvokeFunction(controller, application, null, options, request, response);
});
}
else
{
controller = CreateController(@default, _context);
InvokeFunction(controller, application, null, options, request, response);
}
}
catch (Exception ex)
{
@ -417,8 +441,27 @@ namespace Apewer.Web
var controller = null as ApiController;
try
{
controller = CreateController(application.Type, _context);
InvokeFunction(controller, application, function, options, request, response);
if (application.Unparallel)
{
UnparallelLocker.InLock(GetUnparallelKey(application.Type), () =>
{
controller = CreateController(application.Type, _context);
InvokeFunction(controller, application, function, options, request, response);
});
}
else if (function != null && function.Unparallel)
{
UnparallelLocker.InLock(GetUnparallelKey(function.Method), () =>
{
controller = CreateController(application.Type, _context);
InvokeFunction(controller, application, function, options, request, response);
});
}
else
{
controller = CreateController(application.Type, _context);
InvokeFunction(controller, application, function, options, request, response);
}
}
catch (Exception ex)
{
@ -438,8 +481,14 @@ namespace Apewer.Web
{
// 控制器初始化。
var initializer = ApiUtility.GetInitialier(controller);
var match = initializer == null ? true : initializer.Invoke(controller);
if (!match) return;
if (initializer != null)
{
var @continue = true;
@continue = initializer.Invoke(controller);
if (!@continue) return;
}
// 此应用独立处理,不受反射控制。
if (application.Independent) return;
if (function != null)
@ -803,6 +852,22 @@ namespace Apewer.Web
#endregion
#region 不可并行
static TextLocker UnparallelLocker = new TextLocker();
static string GetUnparallelKey(MethodInfo method)
{
return $"{method.DeclaringType.Assembly.ToString()} | {method.DeclaringType.FullName} | {method.ToString()}";
}
static string GetUnparallelKey(Type type)
{
return $"{type.Assembly.ToString()} | {type.FullName}";
}
#endregion
}
}

8
Apewer/Web/ApiUtility.cs

@ -736,6 +736,14 @@ namespace Apewer.Web
{
try
{
if (exception is IApiException apiException)
{
if (!string.IsNullOrEmpty(apiException.Status))
{
response.Status = apiException.Status.ToLower();
}
}
if (setData)
{
var json = ToJson(exception);

16
Apewer/Web/IApiException.cs

@ -0,0 +1,16 @@
namespace Apewer.Web
{
/// <summary>执行 API 时发生的异常。</summary>
public interface IApiException
{
/// <summary>异常状态。</summary>
string Status { get; }
/// <summary>错误消息。</summary>
string Message { get; }
}
}
Loading…
Cancel
Save