363 lines
14 KiB
C#
363 lines
14 KiB
C#
using Falcon.SugarApi.DatabaseDefinitions;
|
||
using Falcon.SugarApi.ModelValidation;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.Extensions.Caching.Distributed;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
using Microsoft.Extensions.Logging;
|
||
using System;
|
||
using System.Text.Encodings.Web;
|
||
using System.Text.Json;
|
||
using System.Text.Unicode;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace Falcon.SugarApi.ApiDefinistions
|
||
{
|
||
/// <summary>
|
||
/// api控制器基类
|
||
/// </summary>
|
||
[Area("api")]
|
||
[ApiController]
|
||
[Route("[Area]/[Controller]/[Action]")]
|
||
public abstract class ApiControllerBase:ControllerBase
|
||
{
|
||
/// <summary>
|
||
/// 系统缓存
|
||
/// </summary>
|
||
public IDistributedCache? Cache { get; set; }
|
||
/// <summary>
|
||
/// 日志记录服务
|
||
/// </summary>
|
||
public ILogger Logger { get; set; }
|
||
/// <summary>
|
||
/// 服务集合
|
||
/// </summary>
|
||
public IServiceProvider Services { get; set; }
|
||
/// <summary>
|
||
/// Sugar数据库
|
||
/// </summary>
|
||
public SugarDbContext? SugarDb { get; set; }
|
||
|
||
/// <summary>
|
||
/// 应用程序跟目录
|
||
/// </summary>
|
||
public string AppPath { get => AppDomain.CurrentDomain.BaseDirectory; }
|
||
|
||
/// <summary>
|
||
/// 获取请求的方法前缀
|
||
/// </summary>
|
||
protected virtual string Prefix {
|
||
get {
|
||
var con = this.RouteData.Values["controller"];
|
||
var ac = this.RouteData.Values["action"];
|
||
return $":{con}:{ac}";
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 构造控制器基类
|
||
/// </summary>
|
||
/// <param name="service"></param>
|
||
protected ApiControllerBase(IServiceProvider service) {
|
||
this.Services = service;
|
||
this.Logger = service.GetService(typeof(ILogger<>).MakeGenericType(GetType())) as ILogger ?? throw new NullReferenceException("ILogger");
|
||
this.SugarDb = service.GetService<SugarDbContext>();
|
||
this.Cache = service.GetService<IDistributedCache>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取一个新的系统Id
|
||
/// </summary>
|
||
protected virtual string NewId() => Guid.NewGuid().ToString();
|
||
|
||
#region 记录日志
|
||
|
||
/// <summary>
|
||
/// 保存文本日志
|
||
/// </summary>
|
||
/// <param name="msg">日志文本</param>
|
||
protected virtual void SaveLogger(string msg) => this.Logger.LogInformation(msg);
|
||
|
||
/// <summary>
|
||
/// 记录保存请求和响应日志
|
||
/// </summary>
|
||
/// <typeparam name="TRequest">请求信息类型</typeparam>
|
||
/// <typeparam name="TResponse">响应信息类型</typeparam>
|
||
/// <param name="data">请求数据</param>
|
||
/// <param name="result">响应数据</param>
|
||
/// <param name="exception">异常</param>
|
||
protected virtual void SaveLogger<TRequest, TResponse>(TRequest data,TResponse result,Exception? exception = null) {
|
||
var requestStr = this.JsonSerialize(data);
|
||
var responseStr = this.JsonSerialize(result);
|
||
var exStr = exception == null ? "" : exception.ToString();
|
||
var logmsg = $"{this.Prefix}\n请求消息:{requestStr}\n响应消息:{responseStr}\n异常:{exStr}\n";
|
||
this.Logger.LogInformation(logmsg);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 序列化
|
||
/// <summary>
|
||
/// 从对象序列化字符串
|
||
/// </summary>
|
||
/// <typeparam name="T">对象类型</typeparam>
|
||
/// <param name="obj">要序列化的对象</param>
|
||
/// <returns>字符串</returns>
|
||
protected string JsonSerialize<T>(T obj) {
|
||
return JsonSerializer.Serialize<T>(obj,new JsonSerializerOptions {
|
||
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
|
||
});
|
||
}
|
||
/// <summary>
|
||
/// 从字符串反序列化对象
|
||
/// </summary>
|
||
/// <typeparam name="T">对象的类型</typeparam>
|
||
/// <param name="json">json字符串</param>
|
||
/// <returns>对象实例</returns>
|
||
protected T? JsonDeserialize<T>(string json) where T : class {
|
||
return JsonSerializer.Deserialize<T>(json);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 模型验证
|
||
/// <summary>
|
||
/// 验证模型。如果失败抛出异常
|
||
/// </summary>
|
||
/// <param name="model">模型</param>
|
||
protected virtual void ModelValidation(object? model) {
|
||
model.ThrowNullExceptionWhenNull();
|
||
if(!model.TryModelValidation(out var errors)) {
|
||
ThrowApiException("传入的数据验证错误",null,e => {
|
||
e.Data.Add("ModelValidation",errors);
|
||
});
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 抛出异常
|
||
|
||
/// <summary>
|
||
/// 抛出api异常
|
||
/// </summary>
|
||
/// <param name="msg">异常消息</param>
|
||
/// <param name="innException">内部异常</param>
|
||
/// <exception cref="ApiException">api异常</exception>
|
||
protected virtual void ThrowApiException(string msg,Exception innException)
|
||
=> throw new ApiException(msg,innException);
|
||
/// <summary>
|
||
/// 抛出api异常
|
||
/// </summary>
|
||
/// <param name="msg">异常消息</param>
|
||
/// <exception cref="ApiException">api异常</exception>
|
||
protected virtual void ThrowApiException(string msg)
|
||
=> throw new ApiException(msg);
|
||
/// <summary>
|
||
/// 抛出api异常
|
||
/// </summary>
|
||
/// <param name="innException">内部异常</param>
|
||
/// <exception cref="ApiException">api异常</exception>
|
||
protected virtual void ThrowApiException(Exception innException)
|
||
=> throw new ApiException(innException.Message,innException);
|
||
|
||
/// <summary>
|
||
/// 抛出api异常
|
||
/// </summary>
|
||
/// <param name="msg">异常消息</param>
|
||
/// <param name="innException">内部异常</param>
|
||
/// <param name="exAction">异常处理方法</param>
|
||
protected virtual void ThrowApiException(string msg,Exception innException,Action<ApiException> exAction) {
|
||
var ex = new ApiException(msg,innException);
|
||
exAction?.Invoke(ex);
|
||
throw ex;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 返回api调用结果
|
||
|
||
/// <summary>
|
||
/// 同步返回成功的结果
|
||
/// </summary>
|
||
/// <typeparam name="T">data携带的数据类型</typeparam>
|
||
/// <param name="resultBuilder">返回结果创建者</param>
|
||
/// <returns>同步api结果</returns>
|
||
protected virtual ApiResult<T> SuccessResult<T>(Action<ApiResult<T>>? resultBuilder) {
|
||
var result = new ApiResult<T> {
|
||
Code = 0,Msg = ""
|
||
};
|
||
resultBuilder?.Invoke(result);
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步返回成功的结果
|
||
/// </summary>
|
||
/// <typeparam name="T">数据类型</typeparam>
|
||
/// <param name="resultBuilder">成功结果创建器</param>
|
||
/// <returns>异步api结果</returns>
|
||
protected virtual async Task<ApiResult<T>> SuccessResultAsync<T>(Action<ApiResult<T>>? resultBuilder)
|
||
=> await Task.FromResult(SuccessResult(resultBuilder));
|
||
|
||
/// <summary>
|
||
/// 同步返回成功的结果
|
||
/// </summary>
|
||
/// <typeparam name="T">data携带的数据类型</typeparam>
|
||
/// <param name="result">携带数据</param>
|
||
/// <returns>同步api结果</returns>
|
||
protected virtual ApiResult<T> SuccessResult<T>(T result)
|
||
=> SuccessResult<T>(b => b.Data = result);
|
||
|
||
/// <summary>
|
||
/// 异步返回成功的结果
|
||
/// </summary>
|
||
/// <typeparam name="T">data携带的数据类型</typeparam>
|
||
/// <param name="result">携带数据</param>
|
||
/// <returns>异步api结果</returns>
|
||
protected virtual async Task<ApiResult<T>> SuccessResultAsync<T>(T result)
|
||
=> await Task.FromResult(SuccessResult(result));
|
||
|
||
/// <summary>
|
||
/// 同步返回失败的结果
|
||
/// </summary>
|
||
/// <typeparam name="T">data携带的数据类型</typeparam>
|
||
/// <param name="failResultBuilder">失败信息创建器</param>
|
||
/// <returns>异步api结果</returns>
|
||
protected virtual ApiResult<T> FailResult<T>(Action<ApiResult<T>>? failResultBuilder) {
|
||
var result = new ApiResult<T> { Code = 1 };
|
||
failResultBuilder?.Invoke(result);
|
||
return result;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 同步返回失败的结果
|
||
/// </summary>
|
||
/// <typeparam name="T">data携带的数据类型</typeparam>
|
||
/// <param name="failMessage">失败信息</param>
|
||
/// <returns>异步api结果</returns>
|
||
protected virtual ApiResult<T> FailResult<T>(string failMessage)
|
||
=> FailResult<T>(b => b.Msg = failMessage);
|
||
|
||
/// <summary>
|
||
/// 异步返回失败的结果
|
||
/// </summary>
|
||
/// <typeparam name="T">data携带的数据类型</typeparam>
|
||
/// <param name="failMessage">失败信息</param>
|
||
/// <returns>异步api结果</returns>
|
||
protected virtual async Task<ApiResult<T>> FailResultAsync<T>(string failMessage)
|
||
=> await Task.FromResult(FailResult<T>(failMessage));
|
||
|
||
#endregion
|
||
|
||
#region 数据缓存
|
||
/// <summary>
|
||
/// 获取缓存字符串
|
||
/// </summary>
|
||
/// <param name="key">存储的键</param>
|
||
/// <returns>缓存的字符串</returns>
|
||
protected string GetCache(string key) {
|
||
if(this.Cache == null) {
|
||
return string.Empty;
|
||
}
|
||
if(key.IsNullOrEmpty()) {
|
||
return string.Empty; ;
|
||
}
|
||
return this.Cache.GetString(key);
|
||
}
|
||
/// <summary>
|
||
/// 设置缓存
|
||
/// </summary>
|
||
/// <param name="key">存储的键</param>
|
||
/// <param name="val">要存储的值</param>
|
||
/// <param name="span">存储过期时间</param>
|
||
protected void SetCache(string key,string val,TimeSpan? span = null) {
|
||
if(this.Cache == null) {
|
||
return;
|
||
}
|
||
if(key.IsNullOrEmpty() || val.IsNullOrEmpty()) {
|
||
return;
|
||
}
|
||
if(span == null) {
|
||
span = TimeSpan.FromMinutes(1);
|
||
}
|
||
this.Cache.SetString(key,val,new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = span });
|
||
}
|
||
/// <summary>
|
||
/// 获取缓存的对象
|
||
/// </summary>
|
||
/// <typeparam name="T">缓存对象的类型</typeparam>
|
||
/// <param name="key">缓存的键</param>
|
||
/// <returns>缓存的对象</returns>
|
||
protected T? GetCache<T>(string key) {
|
||
if(this.Cache == null) {
|
||
return default(T);
|
||
}
|
||
var value = this.Cache.GetString(key);
|
||
if(value == null)
|
||
return default(T);
|
||
else
|
||
return JsonSerializer.Deserialize<T>(value);
|
||
}
|
||
/// <summary>
|
||
/// 设置对象缓存
|
||
/// </summary>
|
||
/// <typeparam name="T">缓存对象的类型</typeparam>
|
||
/// <param name="key">缓存的键</param>
|
||
/// <param name="val">缓存的对象</param>
|
||
/// <param name="span">存储过期时间</param>
|
||
protected void SetCache<T>(string key,T val,TimeSpan? span = null) {
|
||
if(this.Cache == null) {
|
||
return;
|
||
}
|
||
if(key.IsNullOrEmpty() || val == null) {
|
||
return;
|
||
}
|
||
var str = JsonSerializer.Serialize(val);
|
||
this.SetCache(key,str,span);
|
||
//this.Cache.SetString(key,str,new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = span });
|
||
}
|
||
/// <summary>
|
||
/// 尝试获取key指定的缓冲数据,如果不存在通过cacheDataBuilder方法获取缓冲数据,获取缓冲数据后存入分布式缓存,并返回数据
|
||
/// </summary>
|
||
/// <param name="key">缓存的键</param>
|
||
/// <param name="cacheDataBuilder"></param>
|
||
/// <param name="span">存储过期时间</param>
|
||
/// <returns>缓冲数据</returns>
|
||
protected string? GetCache(string key,Func<string>? cacheDataBuilder = null,TimeSpan? span = null) {
|
||
string? str = this.GetCache(key);
|
||
if(str.IsNotNullOrEmpty()) {
|
||
return str;
|
||
}
|
||
if(cacheDataBuilder != null) {
|
||
str = cacheDataBuilder?.Invoke();
|
||
}
|
||
if(str.IsNotNullOrEmpty()) {
|
||
this.SetCache(key,str,span);
|
||
}
|
||
return str;
|
||
}
|
||
/// <summary>
|
||
/// 尝试获取key指定的缓冲数据,如果不存在通过cacheDataBuilder方法获取缓冲数据,获取缓冲数据后存入分布式缓存,并返回数据
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="key"></param>
|
||
/// <param name="cacheDataBuilder"></param>
|
||
/// <param name="span"></param>
|
||
/// <returns></returns>
|
||
protected T? GetCache<T>(string key,Func<T>? cacheDataBuilder = null,TimeSpan? span = null) {
|
||
T? result = this.GetCache<T>(key);
|
||
if(result != null) {
|
||
return result;
|
||
}
|
||
if(cacheDataBuilder != null) {
|
||
result = cacheDataBuilder.Invoke();
|
||
}
|
||
if(result != null) {
|
||
this.SetCache(key,result,span);
|
||
}
|
||
return result;
|
||
}
|
||
#endregion
|
||
}
|
||
}
|