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"); } } }