using Microsoft.AspNetCore.Http;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
namespace ReZero.SuperAPI
{
public class DynamicApiManager : IDynamicApi
{
///
/// Determines if the given URL is a valid API endpoint.
///
/// The URL to check.
/// True if the URL is a valid API endpoint, false otherwise.
public bool IsApi(string url)
{
var db = App.Db;
var isAnyUrl = CacheManager.Instance.GetList()
.Any(it =>
it!.Url!.ToLower() == url.ToLower()||
(it.OriginalUrl!=null&&url.ToLower().StartsWith(it.OriginalUrl.ToLower()))
);
return isAnyUrl;
}
///
/// Writes the response for the given HTTP context.
///
/// The HTTP context.
public async Task WriteAsync(HttpContext context)
{
var helper = new DynamicApiHelper();
var requestMethodString = context.Request.Method;
HttpRequestMethod requestMethod;
if (helper.IsHttpMethod(requestMethodString, out requestMethod))
{
await WriteAsyncSuccess(context, helper, requestMethod);
}
else
{
await WriteError(context);
}
}
///
/// Writes the response for a successful API request.
///
/// The HTTP context.
/// The dynamic API helper.
/// The HTTP request method.
private static async Task WriteAsyncSuccess(HttpContext context, DynamicApiHelper helper, HttpRequestMethod requestMethod)
{
var handler = helper.GetHandler(requestMethod, context);
var db = App.Db;
var path = context.Request.Path.ToString()?.ToLower();
var interInfo = CacheManager
.Instance.GetList()
.Where(it =>
it.Url!.ToLower() == path
||
(it.OriginalUrl != null && path!.ToLower().StartsWith(it.OriginalUrl.ToLower()))
)?.First();
interInfo = db.Utilities.TranslateCopy(interInfo);
var dynamicInterfaceContext = new InterfaceContext() { InterfaceType = InterfaceType.DynamicApi, HttpContext = context, InterfaceInfo = interInfo };
if (interInfo == null)
{
var message = TextHandler.GetCommonText($"未找到内置接口 {path} ,请在表ZeroInterfaceList中查询", $"No built-in interface {path} is found. Query in the table ZeroInterfaceList");
context.Response.StatusCode = 500;
await context.Response.WriteAsync(message);
}
else
{
try
{
DataService dataService = new DataService();
interInfo!.DataModel!.ApiId = interInfo.Id;
interInfo!.DataModel!.ResultType = interInfo.DataModel?.ResultType;
interInfo!.DataModel!.Sql = interInfo.DataModel?.Sql;
interInfo!.DataModel!.DataBaseId = interInfo.DataModel?.DataBaseId ?? 0;
dataService.BindHttpParameters.Bind(interInfo.DataModel, context, path, !string.IsNullOrEmpty(interInfo.OriginalUrl), interInfo);
dynamicInterfaceContext.DataModel = interInfo.DataModel;
var service = DependencyInjection.DependencyResolver.Provider;
dynamicInterfaceContext.ServiceProvider = service;
interInfo.DataModel!.ServiceProvider = service;
await SuperAPIModule._apiOptions!.InterfaceOptions!.SuperApiAop!.OnExecutingAsync(dynamicInterfaceContext);
await InstanceManager.AuthorizationAsync(context, dynamicInterfaceContext);
var data = await dataService.ExecuteAction(interInfo.DataModel!);
data = GetUserInfo(path, interInfo, data);
SetDataToAop(dynamicInterfaceContext, data);
await SuperAPIModule._apiOptions!.InterfaceOptions!.SuperApiAop!.OnExecutedAsync(dynamicInterfaceContext);
var resultModel = interInfo.CustomResultModel ?? new ResultModel();
resultModel.OutPutData = interInfo.DataModel?.OutPutData;
data = new ResultService().GetResult(data!, resultModel);
if (IsNoSystemPublicApi(interInfo, context))
data = SuperAPIModule._apiOptions?.InterfaceOptions?.MergeDataToStandardDtoFunc?.Invoke(data) ?? data;
var json = JsonHelper.SerializeObject(data, SuperAPIModule._apiOptions!.InterfaceOptions?.JsonSerializerSettings);
context.Response.ContentType = PubConst.DataSource_ApplicationJson;
await context.Response.WriteAsync(json);
}
catch (Exception ex)
{
ReZero.DependencyInjection.DependencyResolver.GetLogger().LogInformation(ex.Message);
object data = new ErrorResponse { message = ex.Message };
if (IsNoSystemPublicApi(interInfo, context))
data = SuperAPIModule._apiOptions?.InterfaceOptions?.MergeDataToStandardDtoFunc?.Invoke(data) ?? data;
context.Response.ContentType = PubConst.DataSource_ApplicationJson;
await context.Response.WriteAsync(JsonHelper.SerializeObject(data, SuperAPIModule._apiOptions!.InterfaceOptions?.JsonSerializerSettings));
dynamicInterfaceContext.Exception = ex;
await SuperAPIModule._apiOptions!.InterfaceOptions!.SuperApiAop!.OnErrorAsync(dynamicInterfaceContext);
}
}
}
private static bool IsNoSystemPublicApi(ZeroInterfaceList interInfo, HttpContext context)
{
var query = context.Request.Query;
var supportCustomDto = query.ContainsKey("supportCustomDto") && query["supportCustomDto"].ToString().ToLower() == "true";
return ((interInfo.Url?.ToLower()?.StartsWith("/public/") != true) && interInfo.Id != InterfaceListInitializerProvider.GetTokenId) || supportCustomDto;
}
private static void SetDataToAop(InterfaceContext dynamicInterfaceContext, object? data)
{
if (dynamicInterfaceContext.DataModel != null)
dynamicInterfaceContext.DataModel.Data = data;
}
private static object? GetUserInfo(string? path, ZeroInterfaceList interInfo, object? data)
{
if (path == PubConst.Jwt_GetJwtInfo)
{
data = interInfo?.DataModel?.ClaimList;
if (interInfo?.DataModel?.ClaimList?.Any()!=true)
{
throw new Exception(TextHandler.GetCommonText("你没有启用JWT授权或者没有配置Claim", "You did not enable JWT authorization or did not configure Claim"));
}
}
return data;
}
///
/// Writes the response for an invalid API request.
///
/// The HTTP context.
private static async Task WriteError(HttpContext context)
{
context.Response.StatusCode = 400; // Bad Request
await context.Response.WriteAsync("Invalid request method");
}
}
}