Nice
3 years ago
39 changed files with 1251 additions and 0 deletions
@ -0,0 +1,37 @@ |
|||
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00 |
|||
# Visual Studio Version 17 |
|||
VisualStudioVersion = 17.1.32210.238 |
|||
MinimumVisualStudioVersion = 10.0.40219.1 |
|||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Easy.Api", "src\Easy.Api\Easy.Api.csproj", "{689367DF-1216-40A5-91CE-412EE8FE6C8F}" |
|||
EndProject |
|||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Easy.DI", "src\Easy.DI\Easy.DI.csproj", "{A269FF3D-00BC-499D-A496-46D97D51FE92}" |
|||
EndProject |
|||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Easy.Result", "src\Easy.Result\Easy.Result.csproj", "{82677F0B-E9CF-4491-8B04-9BF9B04B1534}" |
|||
EndProject |
|||
Global |
|||
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
|||
Debug|Any CPU = Debug|Any CPU |
|||
Release|Any CPU = Release|Any CPU |
|||
EndGlobalSection |
|||
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
|||
{689367DF-1216-40A5-91CE-412EE8FE6C8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|||
{689367DF-1216-40A5-91CE-412EE8FE6C8F}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|||
{689367DF-1216-40A5-91CE-412EE8FE6C8F}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|||
{689367DF-1216-40A5-91CE-412EE8FE6C8F}.Release|Any CPU.Build.0 = Release|Any CPU |
|||
{A269FF3D-00BC-499D-A496-46D97D51FE92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|||
{A269FF3D-00BC-499D-A496-46D97D51FE92}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|||
{A269FF3D-00BC-499D-A496-46D97D51FE92}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|||
{A269FF3D-00BC-499D-A496-46D97D51FE92}.Release|Any CPU.Build.0 = Release|Any CPU |
|||
{82677F0B-E9CF-4491-8B04-9BF9B04B1534}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|||
{82677F0B-E9CF-4491-8B04-9BF9B04B1534}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|||
{82677F0B-E9CF-4491-8B04-9BF9B04B1534}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|||
{82677F0B-E9CF-4491-8B04-9BF9B04B1534}.Release|Any CPU.Build.0 = Release|Any CPU |
|||
EndGlobalSection |
|||
GlobalSection(SolutionProperties) = preSolution |
|||
HideSolutionNode = FALSE |
|||
EndGlobalSection |
|||
GlobalSection(ExtensibilityGlobals) = postSolution |
|||
SolutionGuid = {7260112B-0232-4725-AB84-EF4DCCABFD77} |
|||
EndGlobalSection |
|||
EndGlobal |
@ -0,0 +1,7 @@ |
|||
using Microsoft.AspNetCore.Routing; |
|||
|
|||
namespace Easy.Api; |
|||
public abstract class ApiService |
|||
{ |
|||
|
|||
} |
@ -0,0 +1,17 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<FrameworkReference Include="Microsoft.AspNetCore.App" Version="6.0.0" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.2.3" /> |
|||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.2.3" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Easy.DI\Easy.DI.csproj" /> |
|||
</ItemGroup> |
|||
</Project> |
@ -0,0 +1,43 @@ |
|||
using Easy.Api.Realization; |
|||
using Microsoft.AspNetCore.Routing; |
|||
using Swashbuckle.AspNetCore.Annotations; |
|||
|
|||
namespace Easy.Api.Extensions; |
|||
|
|||
/// <summary>
|
|||
/// A class containing extension methods for the <see cref="RouteHandlerBuilder"/> class. This class cannot be inherited.
|
|||
/// </summary>
|
|||
public static class RouteHandlerBuilderExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Adds the <see cref="SwaggerOperationAttribute"/> to the metadata for all builders produced by builder.
|
|||
/// </summary>
|
|||
/// <param name="builder">The <see cref="RouteHandlerBuilder"/>.</param>
|
|||
/// <param name="summary">The operation summary.</param>
|
|||
/// <param name="description">The optional operation description.</param>
|
|||
/// <returns>
|
|||
/// A <see cref="RouteHandlerBuilder"/> that can be used to further customize the endpoint.
|
|||
/// </returns>
|
|||
public static RouteHandlerBuilder WithDescription( |
|||
this RouteHandlerBuilder builder, |
|||
string summary, |
|||
string description = null) |
|||
{ |
|||
return builder.WithMetadata(new SwaggerOperationAttribute(summary, description)); |
|||
} |
|||
/// <summary>
|
|||
/// 路由模板 App名称带头
|
|||
/// </summary>
|
|||
//public static ApiMapAuto AutoApi(this IEndpointRouteBuilder endpoint, string template)
|
|||
//{
|
|||
// if (string.IsNullOrEmpty(template))
|
|||
// {
|
|||
// template = "app";
|
|||
// }
|
|||
// if (!template.StartsWith("api"))
|
|||
// {
|
|||
// template = "api/" + template;
|
|||
// }
|
|||
// return new ApiMapAuto(template, endpoint);
|
|||
//}
|
|||
} |
@ -0,0 +1,42 @@ |
|||
using Easy.Api; |
|||
using Easy.Api.Realization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Controllers; |
|||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|||
|
|||
namespace Easy.Api.Extensions; |
|||
public static class ServiceCollectionServiceExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// 动态代理Api
|
|||
/// </summary>
|
|||
public static IMvcBuilder AddDynamicWebApi(this IServiceCollection services) |
|||
{ |
|||
|
|||
var build = services.AddControllers(); |
|||
|
|||
build.ConfigureApplicationPartManager(applicationPartManager => |
|||
{ |
|||
applicationPartManager.FeatureProviders.Add(new AppServiceControllerFeatureProvider()); |
|||
}); |
|||
|
|||
ControllerFeature feature = new(); |
|||
|
|||
build.PartManager.PopulateFeature(feature); |
|||
|
|||
foreach (var controller in feature.Controllers.Select(c => c.AsType()).Where(o => o != typeof(ApiService)))// 禁用父类
|
|||
{ |
|||
services.TryAddTransient(controller, controller); |
|||
} |
|||
|
|||
services.Replace(ServiceDescriptor.Transient<IControllerActivator, AppServiceActivator>()); |
|||
|
|||
services.Configure<MvcOptions>(options => |
|||
{ |
|||
options.Conventions.Add(new ApplicationConvention()); |
|||
}); |
|||
|
|||
return build; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,24 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Easy.Api; |
|||
|
|||
/// <summary>
|
|||
/// api定义?
|
|||
/// </summary>
|
|||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] |
|||
public class FirstTemplateAttribute : Attribute |
|||
{ |
|||
public string FirstTemplate { get; } |
|||
public FirstTemplateAttribute() |
|||
{ |
|||
FirstTemplate = ""; |
|||
} |
|||
public FirstTemplateAttribute(string firstTemplate) |
|||
{ |
|||
FirstTemplate = firstTemplate; |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Easy.Api; |
|||
|
|||
/// <summary>
|
|||
/// 忽略
|
|||
/// </summary>
|
|||
[AttributeUsage(AttributeTargets.Parameter)] |
|||
public class ParamIgnoreAttribute : Attribute |
|||
{ |
|||
|
|||
} |
@ -0,0 +1,140 @@ |
|||
using Microsoft.OpenApi.Models; |
|||
using Swashbuckle.AspNetCore.Annotations; |
|||
using Swashbuckle.AspNetCore.SwaggerGen; |
|||
using System.Globalization; |
|||
|
|||
namespace Easy.Api.Middlewares; |
|||
|
|||
public class AnnotationsOperationFilter : IOperationFilter |
|||
{ |
|||
public void Apply(OpenApiOperation operation, OperationFilterContext context) |
|||
{ |
|||
IEnumerable<object> controllerAttributes = Array.Empty<object>(); |
|||
IEnumerable<object> actionAttributes = Array.Empty<object>(); |
|||
IEnumerable<object> metadataAttributes = Array.Empty<object>(); |
|||
|
|||
if (context.MethodInfo is not null) |
|||
{ |
|||
controllerAttributes = context.MethodInfo.DeclaringType!.GetCustomAttributes(true); |
|||
actionAttributes = context.MethodInfo.GetCustomAttributes(true); |
|||
} |
|||
|
|||
if (context.ApiDescription.ActionDescriptor.EndpointMetadata is not null) |
|||
{ |
|||
metadataAttributes = context.ApiDescription.ActionDescriptor.EndpointMetadata; |
|||
} |
|||
|
|||
// NOTE: When controller and action attributes are applicable, action attributes should take precendence.
|
|||
// Hence why they're at the end of the list (i.e. last one wins).
|
|||
// Distinct() is applied due to an ASP.NET Core issue: https://github.com/dotnet/aspnetcore/issues/34199.
|
|||
var allAttributes = controllerAttributes |
|||
.Union(actionAttributes) |
|||
.Union(metadataAttributes) |
|||
.Distinct(); |
|||
|
|||
var actionAndEndpointAttribtues = actionAttributes |
|||
.Union(metadataAttributes) |
|||
.Distinct(); |
|||
|
|||
ApplySwaggerOperationAttribute(operation, actionAndEndpointAttribtues); |
|||
ApplySwaggerOperationFilterAttributes(operation, context, allAttributes); |
|||
ApplySwaggerResponseAttributes(operation, context, allAttributes); |
|||
} |
|||
|
|||
|
|||
|
|||
private static void ApplySwaggerOperationAttribute( |
|||
OpenApiOperation operation, |
|||
IEnumerable<object> actionAttributes) |
|||
{ |
|||
var swaggerOperationAttribute = actionAttributes |
|||
.OfType<SwaggerOperationAttribute>() |
|||
.FirstOrDefault(); |
|||
|
|||
if (swaggerOperationAttribute == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (swaggerOperationAttribute.Summary != null) |
|||
{ |
|||
operation.Summary = swaggerOperationAttribute.Summary; |
|||
} |
|||
|
|||
if (swaggerOperationAttribute.Description != null) |
|||
{ |
|||
operation.Description = swaggerOperationAttribute.Description; |
|||
} |
|||
|
|||
if (swaggerOperationAttribute.OperationId != null) |
|||
{ |
|||
operation.OperationId = swaggerOperationAttribute.OperationId; |
|||
} |
|||
|
|||
if (swaggerOperationAttribute.Tags != null) |
|||
{ |
|||
operation.Tags = swaggerOperationAttribute.Tags |
|||
.Select(tagName => new OpenApiTag { Name = tagName }) |
|||
.ToList(); |
|||
} |
|||
} |
|||
|
|||
private static void ApplySwaggerOperationFilterAttributes( |
|||
OpenApiOperation operation, |
|||
OperationFilterContext context, |
|||
IEnumerable<object> controllerAndActionAttributes) |
|||
{ |
|||
var swaggerOperationFilterAttributes = controllerAndActionAttributes |
|||
.OfType<SwaggerOperationFilterAttribute>(); |
|||
|
|||
foreach (var swaggerOperationFilterAttribute in swaggerOperationFilterAttributes) |
|||
{ |
|||
var filter = (IOperationFilter)Activator.CreateInstance(swaggerOperationFilterAttribute.FilterType)!; |
|||
filter.Apply(operation, context); |
|||
} |
|||
} |
|||
|
|||
private static void ApplySwaggerResponseAttributes( |
|||
OpenApiOperation operation, |
|||
OperationFilterContext context, |
|||
IEnumerable<object> controllerAndActionAttributes) |
|||
{ |
|||
var swaggerResponseAttributes = controllerAndActionAttributes.OfType<SwaggerResponseAttribute>(); |
|||
|
|||
foreach (var swaggerResponseAttribute in swaggerResponseAttributes) |
|||
{ |
|||
string statusCode = swaggerResponseAttribute.StatusCode.ToString(CultureInfo.InvariantCulture); |
|||
|
|||
if (operation.Responses == null) |
|||
{ |
|||
operation.Responses = new OpenApiResponses(); |
|||
} |
|||
|
|||
if (!operation.Responses.TryGetValue(statusCode, out OpenApiResponse response)) |
|||
{ |
|||
response = new OpenApiResponse(); |
|||
} |
|||
|
|||
if (swaggerResponseAttribute.Description != null) |
|||
{ |
|||
response.Description = swaggerResponseAttribute.Description; |
|||
} |
|||
|
|||
operation.Responses[statusCode] = response; |
|||
|
|||
if (swaggerResponseAttribute.ContentTypes != null) |
|||
{ |
|||
response.Content.Clear(); |
|||
|
|||
foreach (string contentType in swaggerResponseAttribute.ContentTypes) |
|||
{ |
|||
var schema = (swaggerResponseAttribute.Type != null && swaggerResponseAttribute.Type != typeof(void)) |
|||
? context.SchemaGenerator.GenerateSchema(swaggerResponseAttribute.Type, context.SchemaRepository) |
|||
: null; |
|||
|
|||
response.Content.Add(contentType, new OpenApiMediaType { Schema = schema }); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,55 @@ |
|||
namespace Easy.Api.Realization; |
|||
|
|||
public class ApiMapAuto |
|||
{ |
|||
public readonly static string[] CommonPostfixes = { "AppService", "Service" }; |
|||
public static string FiterControllerName(string controllerName) // 过滤控制器
|
|||
{ |
|||
foreach (var commonPostfixe in CommonPostfixes) |
|||
{ |
|||
if (controllerName.EndsWith(commonPostfixe)) |
|||
{ |
|||
controllerName = controllerName.Remove(controllerName.IndexOf(commonPostfixe)); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return controllerName; |
|||
} |
|||
|
|||
public readonly static List<string> ActionPostfixes = new() |
|||
{ |
|||
"GetAll", "GetList", "Get", |
|||
"Post", "Create", "Add", "Insert", |
|||
"Put", "Update", |
|||
"Delete", "Remove", |
|||
"Patch" |
|||
}; |
|||
private const string AsyncStr = "Async"; |
|||
internal static string FiterActionName(string actionName) |
|||
{ |
|||
string actionPostfixe = ActionPostfixes.FirstOrDefault(actionPostfixe => actionName.StartsWith(actionPostfixe)) ?? ""; |
|||
if (actionName.StartsWith(actionPostfixe)) |
|||
actionName = actionName.Remove(actionName.IndexOf(actionPostfixe), actionPostfixe.Length); |
|||
if (actionName.EndsWith(AsyncStr)) |
|||
actionName = actionName.Remove(actionName.IndexOf(AsyncStr)); |
|||
return actionName; |
|||
} |
|||
|
|||
public static string GetHttpMethod(string actionName) |
|||
{ |
|||
if (actionName.StartsWith("Get")) |
|||
return "GET"; |
|||
|
|||
if (actionName.StartsWith("Put") || actionName.StartsWith("Update")) |
|||
return "PUT"; |
|||
|
|||
if (actionName.StartsWith("Delete") || actionName.StartsWith("Remove")) |
|||
return "DELETE"; |
|||
|
|||
if (actionName.StartsWith("Patch")) |
|||
return "PATCH"; |
|||
|
|||
return "POST"; |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Controllers; |
|||
|
|||
namespace Easy.Api.Realization; |
|||
|
|||
internal class AppServiceActivator : IControllerActivator |
|||
{ |
|||
public object Create(ControllerContext actionContext) |
|||
{ |
|||
if (actionContext == null) |
|||
{ |
|||
throw new ArgumentNullException(nameof(actionContext)); |
|||
} |
|||
var controllerType = actionContext.ActionDescriptor.ControllerTypeInfo.AsType(); |
|||
|
|||
var controller = actionContext.HttpContext.RequestServices.GetRequiredService(controllerType); |
|||
|
|||
return controller; |
|||
} |
|||
|
|||
public virtual void Release(ControllerContext context, object controller) |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
using Microsoft.AspNetCore.Mvc.Controllers; |
|||
using System.Reflection; |
|||
|
|||
namespace Easy.Api.Realization; |
|||
|
|||
internal class AppServiceControllerFeatureProvider : ControllerFeatureProvider |
|||
{ |
|||
protected override bool IsController(TypeInfo typeInfo) |
|||
{ |
|||
var result = |
|||
typeof(ApiService).IsAssignableFrom(typeInfo) && typeof(ApiService) != typeInfo && |
|||
typeInfo.IsClass && typeInfo.IsPublic && !typeInfo.IsAbstract; |
|||
//if (result){}
|
|||
return result; |
|||
} |
|||
} |
@ -0,0 +1,149 @@ |
|||
|
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.ActionConstraints; |
|||
using Microsoft.AspNetCore.Mvc.ApplicationModels; |
|||
using Microsoft.AspNetCore.Mvc.ModelBinding; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Easy.Api.Realization; |
|||
|
|||
internal class ApplicationConvention : IApplicationModelConvention |
|||
{ |
|||
public void Apply(ApplicationModel application) |
|||
{ |
|||
application.Controllers.ToList().ForEach(controller => |
|||
{ |
|||
controller.ControllerName = ApiMapAuto.FiterControllerName(controller.ControllerName); |
|||
ConfigureSelector(controller); |
|||
ConfigureParameters(controller); |
|||
ConfigureApiExplorer(controller); |
|||
}); |
|||
} |
|||
|
|||
|
|||
|
|||
//配置记录应用: 这可用于使用 Swagger 等工具为 Web API 生成帮助页。
|
|||
private static void ConfigureApiExplorer(ControllerModel controller) |
|||
{ |
|||
if (!controller.ApiExplorer.IsVisible.HasValue) |
|||
{ |
|||
controller.ApiExplorer.IsVisible = true; |
|||
} |
|||
|
|||
foreach (var action in controller.Actions) |
|||
{ |
|||
if (!action.ApiExplorer.IsVisible.HasValue) |
|||
{ |
|||
action.ApiExplorer.IsVisible = true; |
|||
} |
|||
} |
|||
} |
|||
//配置选择器:方法路由 HttpMethod
|
|||
private static void ConfigureSelector(ControllerModel controller) |
|||
{ |
|||
foreach (var action in controller.Actions) |
|||
{ |
|||
action.Selectors[0].AttributeRouteModel = new(new RouteAttribute(RouteTemplate(action))); |
|||
action.Selectors[0].ActionConstraints.Add(new HttpMethodActionConstraint(new[] { ApiMapAuto.GetHttpMethod(action.ActionName) })); |
|||
} |
|||
} |
|||
//配置方法参数
|
|||
private static void ConfigureParameters(ControllerModel controller) |
|||
{ |
|||
foreach (var action in controller.Actions) |
|||
{ |
|||
foreach (var parameter in action.Parameters) |
|||
{ |
|||
if (parameter.BindingInfo != null) |
|||
continue; |
|||
|
|||
if (parameter.ParameterType.IsClass && |
|||
parameter.ParameterType != typeof(string) && |
|||
parameter.ParameterType != typeof(IFormFile)) |
|||
{ |
|||
|
|||
var httpMethods = action.Selectors.SelectMany(temp => temp.ActionConstraints).OfType<HttpMethodActionConstraint>().SelectMany(temp => temp.HttpMethods); |
|||
|
|||
if (new[] { "GET", "DELETE", "TRACE", "HEAD" }.Any(value => httpMethods.Contains(value))) |
|||
continue; |
|||
|
|||
parameter.BindingInfo = BindingInfo.GetBindingInfo(new[] { new FromBodyAttribute() }); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
//获得一个自定义的路由
|
|||
private static string RouteTemplate(ActionModel action) |
|||
{ |
|||
|
|||
var routeAttribute = action.Controller.Attributes.FirstOrDefault(o => o?.GetType() == typeof(FirstTemplateAttribute)); |
|||
string url = ""; |
|||
if (routeAttribute != null) |
|||
{ |
|||
url = ((FirstTemplateAttribute)routeAttribute).FirstTemplate; |
|||
} |
|||
else |
|||
{ |
|||
url += "api"; |
|||
} |
|||
|
|||
|
|||
|
|||
//控制器部分
|
|||
url += $"/{ApiMapAuto.FiterControllerName(action.Controller.ControllerType.Name)}"; |
|||
// id 部分
|
|||
var idParameterModel = action.Parameters.FirstOrDefault(p => p.ParameterName == "id"); |
|||
if (idParameterModel != null) |
|||
{ |
|||
if (action.Parameters.Any(temp => temp.ParameterName == "id")) |
|||
url += "/{id}"; |
|||
else |
|||
{ |
|||
var properties = idParameterModel.ParameterType.GetProperties(BindingFlags.Instance | BindingFlags.Public); |
|||
|
|||
foreach (var property in properties) |
|||
{ |
|||
url += "/{" + property.Name + "}"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
//方法部分
|
|||
string actionName = ApiMapAuto.FiterActionName(action.ActionMethod.Name); |
|||
if (!string.IsNullOrEmpty(actionName)) |
|||
{ |
|||
url += $"/{actionName}"; |
|||
|
|||
// id 部分
|
|||
var secondaryIds = action.Parameters.Where(p => |
|||
p.Attributes.Any(o => o.GetType() != typeof(ParamIgnoreAttribute)) && |
|||
p.ParameterName.EndsWith("Id", StringComparison.Ordinal)).ToList(); |
|||
if (secondaryIds.Count == 1) |
|||
{ |
|||
url += $"/{{{secondaryIds[0].Name}}}"; |
|||
} |
|||
|
|||
} |
|||
|
|||
return url; |
|||
} |
|||
|
|||
|
|||
//清空Selectors
|
|||
//private static void RemoveSelectors(IList<SelectorModel> selectors)
|
|||
//{
|
|||
// for (var i = selectors.Count - 1; i >= 0; i--)
|
|||
// {
|
|||
// selectors.Remove(selectors[i]);
|
|||
// }
|
|||
//}
|
|||
|
|||
} |
@ -0,0 +1,2 @@ |
|||
global using Microsoft.AspNetCore.Builder; |
|||
global using Microsoft.Extensions.DependencyInjection; |
@ -0,0 +1,13 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<!--<Nullable>enable</Nullable>--> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<FrameworkReference Include="Microsoft.AspNetCore.App" Version="6.0.0" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="6.0.0" /> |
|||
</ItemGroup> |
|||
</Project> |
@ -0,0 +1,28 @@ |
|||
using Easy.DI.Realization; |
|||
|
|||
namespace Easy.DI.Extensions; |
|||
public static class ServiceCollectionServiceExtensions |
|||
{ |
|||
|
|||
public static IServiceCollection AddDependencyAbstracts(this IServiceCollection s, params Action<IServiceCollection, Type[]>[] abstractConfigs) |
|||
{ |
|||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) |
|||
{ |
|||
var types = assembly.GetTypes().Where(o => !o.IsInterface && !o.IsAbstract && o.IsClass).ToArray(); |
|||
foreach (var config in abstractConfigs) |
|||
{ |
|||
config(s, types); |
|||
} |
|||
} |
|||
return s; |
|||
} |
|||
public static IServiceCollection AddDependency(this IServiceCollection s) |
|||
{ |
|||
s.AddDependencyAbstracts( |
|||
DependencyInterface.Singleton, |
|||
DependencyInterface.Transient, |
|||
DependencyInterface.Scoped |
|||
); |
|||
return s; |
|||
} |
|||
} |
@ -0,0 +1,20 @@ |
|||
namespace Easy.DI; |
|||
|
|||
public interface ILazyServiceProvider |
|||
{ |
|||
T LazyGetRequiredService<T>(); |
|||
|
|||
object LazyGetRequiredService(Type serviceType); |
|||
|
|||
T LazyGetService<T>(); |
|||
|
|||
object LazyGetService(Type serviceType); |
|||
|
|||
T LazyGetService<T>(T defaultValue); |
|||
|
|||
object LazyGetService(Type serviceType, object defaultValue); |
|||
|
|||
object LazyGetService(Type serviceType, Func<IServiceProvider, object> factory); |
|||
|
|||
T LazyGetService<T>(Func<IServiceProvider, object> factory); |
|||
} |
@ -0,0 +1,8 @@ |
|||
namespace Easy.DI; |
|||
|
|||
/// <summary>
|
|||
/// 只 new 一次
|
|||
/// </summary>
|
|||
public interface IScopedDependency |
|||
{ |
|||
} |
@ -0,0 +1,8 @@ |
|||
namespace Easy.DI; |
|||
|
|||
/// <summary>
|
|||
/// 全局只NEW 一次对象
|
|||
/// </summary>
|
|||
public interface ISingletonDependency |
|||
{ |
|||
} |
@ -0,0 +1,8 @@ |
|||
namespace Easy.DI; |
|||
|
|||
/// <summary>
|
|||
/// 依赖注入瞬态生命周期
|
|||
/// </summary>
|
|||
public interface ITransientDependency |
|||
{ |
|||
} |
@ -0,0 +1,52 @@ |
|||
using Easy.DI; |
|||
|
|||
namespace Easy.DI.Realization; |
|||
|
|||
internal static class DependencyInterface |
|||
{ |
|||
public static void Scoped(this IServiceCollection s, Type[] types) |
|||
{ |
|||
foreach (var type in types.Where(o => IsServiceLifetime<IScopedDependency>(o))) |
|||
{ |
|||
Type interfaceType = GetInterface(type); |
|||
|
|||
if (interfaceType != null) |
|||
s.TryAddScoped(interfaceType, type); |
|||
else |
|||
s.TryAddScoped(type, type); |
|||
} |
|||
} |
|||
public static void Singleton(this IServiceCollection s, Type[] types) |
|||
{ |
|||
foreach (var type in types.Where(o => IsServiceLifetime<ISingletonDependency>(o))) |
|||
{ |
|||
Type interfaceType = GetInterface(type); |
|||
|
|||
if (interfaceType != null) |
|||
s.TryAddSingleton(interfaceType, type); |
|||
else |
|||
s.TryAddSingleton(type, type); |
|||
|
|||
} |
|||
} |
|||
public static void Transient(this IServiceCollection s, Type[] types) |
|||
{ |
|||
foreach (var type in types.Where(o => IsServiceLifetime<ITransientDependency>(o))) |
|||
{ |
|||
Type interfaceType = GetInterface(type); |
|||
|
|||
if (interfaceType != null) |
|||
s.TryAddTransient(interfaceType, type); |
|||
else |
|||
s.TryAddTransient(type, type); |
|||
|
|||
} |
|||
} |
|||
|
|||
private static bool IsServiceLifetime<ServiceLifetime>(Type o) => typeof(ServiceLifetime).IsAssignableFrom(o); |
|||
|
|||
private static Type GetInterface(Type type) |
|||
{ |
|||
return type.GetInterfaces().FirstOrDefault(interfaceType => interfaceType.Name.EndsWith(type.Name)); |
|||
} |
|||
} |
@ -0,0 +1,73 @@ |
|||
namespace Easy.DI.Realization; |
|||
|
|||
public class LazyServiceProvider : ILazyServiceProvider, ITransientDependency |
|||
{ |
|||
protected IDictionary<Type, object> CachedServices { get; set; } |
|||
|
|||
protected IServiceProvider ServiceProvider { get; set; } |
|||
|
|||
public LazyServiceProvider(IServiceProvider serviceProvider) |
|||
{ |
|||
ServiceProvider = serviceProvider; |
|||
CachedServices = new Dictionary<Type, object>(); |
|||
} |
|||
|
|||
public virtual T LazyGetRequiredService<T>() |
|||
{ |
|||
return (T)LazyGetRequiredService(typeof(T)); |
|||
} |
|||
|
|||
public virtual object LazyGetRequiredService(Type serviceType) |
|||
{ |
|||
if (CachedServices.TryGetValue(serviceType, out object obj)) |
|||
{ |
|||
return obj; |
|||
} |
|||
|
|||
return CachedServices[serviceType] = ServiceProvider?.GetService(serviceType); |
|||
} |
|||
|
|||
public virtual T LazyGetService<T>() |
|||
{ |
|||
return (T)LazyGetService(typeof(T)); |
|||
} |
|||
|
|||
public virtual object LazyGetService(Type serviceType) |
|||
{ |
|||
if (CachedServices.TryGetValue(serviceType, out object obj)) |
|||
{ |
|||
return obj; |
|||
} |
|||
|
|||
return CachedServices[serviceType] = ServiceProvider?.GetService(serviceType); |
|||
} |
|||
|
|||
public virtual T LazyGetService<T>(T defaultValue) |
|||
{ |
|||
return (T)LazyGetService(typeof(T), defaultValue); |
|||
} |
|||
|
|||
public virtual object LazyGetService(Type serviceType, object defaultValue) |
|||
{ |
|||
return LazyGetService(serviceType) ?? defaultValue; |
|||
} |
|||
|
|||
public virtual T LazyGetService<T>(Func<IServiceProvider, object> factory) |
|||
{ |
|||
return (T)LazyGetService(typeof(T), factory); |
|||
} |
|||
|
|||
public virtual object LazyGetService(Type serviceType, Func<IServiceProvider, object> factory) |
|||
{ |
|||
|
|||
if (CachedServices.TryGetValue(serviceType, out object obj)) |
|||
{ |
|||
return obj; |
|||
} |
|||
|
|||
return CachedServices[serviceType] = factory(ServiceProvider); |
|||
} |
|||
|
|||
|
|||
} |
|||
|
@ -0,0 +1,2 @@ |
|||
global using Microsoft.Extensions.DependencyInjection; |
|||
global using Microsoft.Extensions.DependencyInjection.Extensions; |
@ -0,0 +1,27 @@ |
|||
namespace Easy.Result; |
|||
|
|||
/// <summary>
|
|||
/// ApiResult
|
|||
/// </summary>
|
|||
public class ApiResult : IModel |
|||
{ |
|||
/// <summary>
|
|||
/// 消息
|
|||
/// </summary>
|
|||
public string Message { get; set; } |
|||
/// <summary>
|
|||
/// 状态
|
|||
/// </summary>
|
|||
public string Status { get; set; } |
|||
|
|||
|
|||
public static ApiResultValue<TValue> Value<TValue>(TValue value) |
|||
{ |
|||
return new ApiResultValue<TValue>(value); |
|||
} |
|||
public static ApiResultValues<TValue> Value<TValue>(List<TValue> value) |
|||
{ |
|||
return new ApiResultValues<TValue>(value); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,13 @@ |
|||
namespace Easy.Result; |
|||
|
|||
public class ApiResultConsts |
|||
{ |
|||
/// <summary>
|
|||
/// 正确返回状态
|
|||
/// </summary>
|
|||
public const string SUCCESS = "SUCCESS"; |
|||
/// <summary>
|
|||
/// 需要用户重试 基本是报错了 或者业务问题
|
|||
/// </summary>
|
|||
public const string RETRY = "RETRY"; |
|||
} |
@ -0,0 +1,18 @@ |
|||
namespace Easy.Result; |
|||
|
|||
public class ApiResultPaged<TSource> : ApiResult |
|||
{ |
|||
public ApiResultPaged() { } |
|||
/// <summary>
|
|||
/// 页面数量
|
|||
/// </summary>
|
|||
public long PageCount { get; set; } |
|||
/// <summary>
|
|||
/// 页面大小
|
|||
/// </summary>
|
|||
public int PageSize { get; set; } |
|||
/// <summary>
|
|||
/// 返回结果
|
|||
/// </summary>
|
|||
public List<TSource> Data { get; set; } |
|||
} |
@ -0,0 +1,11 @@ |
|||
namespace Easy.Result; |
|||
|
|||
public class ApiResultValue<TValue> : ApiResult |
|||
{ |
|||
public ApiResultValue() { } |
|||
public ApiResultValue(TValue value) |
|||
{ |
|||
Result = value; |
|||
} |
|||
public TValue Result { get; set; } |
|||
} |
@ -0,0 +1,11 @@ |
|||
namespace Easy.Result; |
|||
|
|||
public class ApiResultValues<TValue> : ApiResult |
|||
{ |
|||
public ApiResultValues() { } |
|||
public ApiResultValues(List<TValue> value) |
|||
{ |
|||
Result = value; |
|||
} |
|||
public List<TValue> Result { get; set; } |
|||
} |
@ -0,0 +1,24 @@ |
|||
using AutoMapper; |
|||
using Microsoft.Extensions.DependencyModel; |
|||
using System.Reflection; |
|||
using System.Runtime.Loader; |
|||
|
|||
namespace Easy.Result.Common; |
|||
|
|||
public class AutoMapReadonly |
|||
{ |
|||
private static IEnumerable<Assembly> Assemblies = DependencyContext.Default.CompileLibraries. |
|||
Where(lib => !lib.Serviceable && lib.Type != "package" && lib.Type != "referenceassembly"). |
|||
Select(lib => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name))); |
|||
|
|||
public readonly static IConfigurationProvider ConfigurationProvider = new MapperConfiguration(cfg => |
|||
{ |
|||
foreach (var assembly in Assemblies) |
|||
{ |
|||
foreach (var profileType in assembly.GetTypes().Where(o => typeof(Profile).IsAssignableFrom(o))) |
|||
{ |
|||
cfg.AddProfile(profileType); |
|||
} |
|||
} |
|||
}); |
|||
} |
@ -0,0 +1,16 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> |
|||
<!--<Nullable>enable</Nullable>--> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<PackageReference Include="FluentValidation" Version="10.3.6" /> |
|||
<PackageReference Include="AutoMapper" Version="11.0.0" /> |
|||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="6.0.0" /> |
|||
<PackageReference Include="SqlSugarCore" Version="5.0.5.4" /> |
|||
<FrameworkReference Include="Microsoft.AspNetCore.App" Version="6.0.0" /> |
|||
</ItemGroup> |
|||
</Project> |
@ -0,0 +1,18 @@ |
|||
namespace Easy.Result.Exceptions; |
|||
|
|||
/// <summary>
|
|||
/// 服务异常
|
|||
/// </summary>
|
|||
internal class SvcException : Exception |
|||
{ |
|||
/// <summary>
|
|||
/// 服务异常
|
|||
/// </summary>
|
|||
/// <param name="message">消息</param>
|
|||
public SvcException(string message) |
|||
: base(message) |
|||
{ |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,77 @@ |
|||
using AutoMapper; |
|||
using Easy.Result.Common; |
|||
|
|||
namespace Easy.Result.Extensions; |
|||
|
|||
public static class ApiResultExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// 是成功
|
|||
/// </summary>
|
|||
static public bool IsSuccess<TSource>(this TSource source) |
|||
where TSource : ApiResult |
|||
{ |
|||
return source.Status.Equals(ApiResultConsts.SUCCESS); |
|||
} |
|||
/// <summary>
|
|||
/// 是重试
|
|||
/// </summary>
|
|||
static public bool IsRETRY<TSource>(this TSource source) |
|||
where TSource : ApiResult |
|||
{ |
|||
return source.Status.Equals(ApiResultConsts.RETRY); |
|||
} |
|||
/// <summary>
|
|||
/// 成功
|
|||
/// </summary>
|
|||
static public TSource SUCCESS<TSource>(this TSource source, string message = null) |
|||
where TSource : ApiResult |
|||
{ |
|||
return source.CustomStatusMessage("SUCCESS", message ?? "操作成功"); |
|||
} |
|||
/// <summary>
|
|||
/// 重试
|
|||
/// </summary>
|
|||
static public TSource RETRY<TSource>(this TSource source, string message = null) |
|||
where TSource : ApiResult |
|||
{ |
|||
return source.CustomStatusMessage("RETRY", message ?? "出错了,请稍后再试。"); |
|||
} |
|||
/// <summary>
|
|||
/// 自定义状态消息
|
|||
/// </summary>
|
|||
static public TSource CustomStatusMessage<TSource>(this TSource source, string status, string message) |
|||
where TSource : ApiResult |
|||
{ |
|||
source.Message = message; |
|||
source.Status = status; |
|||
return source; |
|||
} |
|||
|
|||
static public TEntity ToEntity<TEntity>(this IModel model) |
|||
where TEntity : IEntity, new() |
|||
{ |
|||
return new Mapper(AutoMapReadonly.ConfigurationProvider).Map<TEntity>(model); |
|||
} |
|||
|
|||
static public ApiResultValue<TModel> ToModel<TModel>(this IEntity entity) |
|||
where TModel : IModel, new() |
|||
{ |
|||
return ApiResult.Value(new Mapper(AutoMapReadonly.ConfigurationProvider).Map<TModel>(entity) ?? new()); |
|||
} |
|||
static public ApiResultValues<TModel> ToModels<TModel>(this IEntities entities) |
|||
{ |
|||
return ApiResult.Value(new Mapper(AutoMapReadonly.ConfigurationProvider).Map<List<TModel>>(entities.Data) ?? new()); |
|||
} |
|||
|
|||
static public ApiResultPaged<TModel> ToPagedModel<TModel>(this IPaged paged) |
|||
{ |
|||
return new ApiResultPaged<TModel>() |
|||
{ |
|||
Data = new Mapper(AutoMapReadonly.ConfigurationProvider).Map<List<TModel>>(paged.Data) ?? new(), |
|||
PageSize = paged.PageSize, |
|||
PageCount = paged.PageCount |
|||
}; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,22 @@ |
|||
using Easy.Result.FluentValidation; |
|||
using Easy.Result.Middlewares; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
|
|||
namespace Easy.Result.Extensions; |
|||
|
|||
public static class ApplicationBuilderExtensions |
|||
{ |
|||
public static IApplicationBuilder UseErrApiResult(this IApplicationBuilder builder) |
|||
{ |
|||
return builder.UseMiddleware<ErrApiResultMiddleware>(); |
|||
} |
|||
public static IMvcBuilder AddEasyFluentValidation(this IMvcBuilder builder) |
|||
{ |
|||
return builder.AddMvcOptions(options => |
|||
{ |
|||
options.Filters.Add<FluentValidationFilter>(); |
|||
}); |
|||
} |
|||
} |
|||
|
@ -0,0 +1,36 @@ |
|||
using FluentValidation; |
|||
using FluentValidation.Internal; |
|||
using Microsoft.AspNetCore.Mvc.Filters; |
|||
|
|||
namespace Easy.Result.FluentValidation; |
|||
|
|||
public class FluentValidationFilter : IAsyncActionFilter |
|||
{ |
|||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) |
|||
{ |
|||
foreach (var arg in context.ActionArguments) |
|||
{ |
|||
var requestType = arg.Value?.GetType(); |
|||
if (requestType != null) |
|||
{ |
|||
var abstractValidatorType = typeof(AbstractValidator<>).MakeGenericType(requestType); |
|||
|
|||
//var name = abstractValidatorType.Name + requestType.Name;
|
|||
var classValidatorType = requestType.Assembly.GetTypes().First(o => abstractValidatorType.IsAssignableFrom(o)); |
|||
|
|||
if (classValidatorType != null) |
|||
{ |
|||
IValidator validator = (IValidator)Activator.CreateInstance(classValidatorType); |
|||
|
|||
//new ValidationContext<T>(instance, new PropertyChain(), ValidatorOptions.Global.ValidatorSelectors.DefaultValidatorSelectorFactory())
|
|||
var validationContextType = typeof(ValidationContext<>).MakeGenericType(requestType); |
|||
IValidationContext ValidationContext = (IValidationContext)Activator.CreateInstance(validationContextType, arg.Value, new PropertyChain(), ValidatorOptions.Global.ValidatorSelectors.DefaultValidatorSelectorFactory()); |
|||
|
|||
var validationResult = await validator.ValidateAsync(ValidationContext); |
|||
|
|||
When.Is(!validationResult.IsValid, validationResult.Errors?.First()?.ErrorMessage); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,65 @@ |
|||
namespace Easy.Result; |
|||
|
|||
public interface IEntities |
|||
{ |
|||
/// <summary>
|
|||
/// 返回结果
|
|||
/// </summary>
|
|||
public object Data { get; set; } |
|||
|
|||
|
|||
public static IEntities Create<TSource>(List<TSource> Data) |
|||
{ |
|||
return new Entites() |
|||
{ |
|||
Data = Data ?? new() |
|||
}; |
|||
} |
|||
} |
|||
|
|||
public sealed class Entites : IEntities |
|||
{ |
|||
/// <summary>
|
|||
/// 返回结果
|
|||
/// </summary>
|
|||
public object Data { get; set; } |
|||
} |
|||
|
|||
public interface IPaged : IEntities |
|||
{ |
|||
/// <summary>
|
|||
/// 页面数量
|
|||
/// </summary>
|
|||
public long PageCount { get; set; } |
|||
/// <summary>
|
|||
/// 页面大小
|
|||
/// </summary>
|
|||
public int PageSize { get; set; } |
|||
|
|||
public static IPaged Create<TSource>(long PageCount, int PageSize, List<TSource> Data) |
|||
{ |
|||
return new Paged() |
|||
{ |
|||
PageCount = PageCount, |
|||
Data = Data ?? new(), |
|||
PageSize = PageSize, |
|||
}; |
|||
} |
|||
|
|||
} |
|||
|
|||
public sealed class Paged : IPaged |
|||
{ |
|||
/// <summary>
|
|||
/// 页面数量
|
|||
/// </summary>
|
|||
public long PageCount { get; set; } |
|||
/// <summary>
|
|||
/// 页面大小
|
|||
/// </summary>
|
|||
public int PageSize { get; set; } |
|||
/// <summary>
|
|||
/// 返回结果
|
|||
/// </summary>
|
|||
public object Data { get; set; } |
|||
} |
@ -0,0 +1,10 @@ |
|||
using SqlSugar; |
|||
|
|||
namespace Easy.Result; |
|||
|
|||
public interface IEntity |
|||
{ |
|||
[SugarColumn(IsPrimaryKey = true)] |
|||
public long Id { get; set; } |
|||
|
|||
} |
@ -0,0 +1,9 @@ |
|||
using AutoMapper; |
|||
using Easy.Result.Common; |
|||
namespace Easy.Result; |
|||
|
|||
public interface IModel |
|||
{ |
|||
public TEntity ToEntity<TEntity>() where TEntity : IEntity, new() => new Mapper(AutoMapReadonly.ConfigurationProvider).Map<TEntity>(this); |
|||
|
|||
} |
@ -0,0 +1,51 @@ |
|||
using Easy.Result.Exceptions; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.Extensions.Logging; |
|||
|
|||
namespace Easy.Result.Middlewares; |
|||
|
|||
public class ErrApiResultMiddleware |
|||
{ |
|||
private readonly RequestDelegate _next; |
|||
|
|||
public ErrApiResultMiddleware(RequestDelegate next) |
|||
{ |
|||
_next = next; |
|||
} |
|||
public async Task InvokeAsync(HttpContext context, ILoggerFactory loggerFactory) |
|||
{ |
|||
if (context.Request.Path.Value.StartsWith("/api")) |
|||
{ |
|||
var logger = loggerFactory.CreateLogger(nameof(ErrApiResultMiddleware)); |
|||
try |
|||
{ |
|||
await _next(context); |
|||
} |
|||
catch (SvcException ex) |
|||
{ |
|||
await context.Response.WriteAsJsonAsync(new ApiResult() |
|||
{ |
|||
Message = ex.Message, |
|||
Status = "RETRY", |
|||
}); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
string message = $"ErrMessage = {ex.Message}"; |
|||
#pragma warning disable CA2254 // 模板应为静态表达式
|
|||
logger.LogError(new EventId(ex.HResult), ex, message); |
|||
#pragma warning restore CA2254 // 模板应为静态表达式
|
|||
await context.Response.WriteAsJsonAsync(new ApiResult() |
|||
{ |
|||
Message = "出错了,请稍后再试。", |
|||
Status = "RETRY", |
|||
}); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
await _next(context); |
|||
} |
|||
|
|||
} |
|||
} |
@ -0,0 +1,38 @@ |
|||
namespace Easy.Result; |
|||
|
|||
public record PagingRequest : IModel |
|||
{ |
|||
private int _pageIndex; |
|||
private int _pageSize; |
|||
|
|||
/// <summary>
|
|||
/// 当前第几页
|
|||
/// </summary>
|
|||
public int PageIndex |
|||
{ |
|||
get => _pageIndex; |
|||
set |
|||
{ |
|||
if (value <= 0) value = 1; |
|||
_pageIndex = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 页面数量
|
|||
/// </summary>
|
|||
public int PageSize |
|||
{ |
|||
get => _pageSize; |
|||
set |
|||
{ |
|||
if (value <= 9) value = 10; |
|||
_pageSize = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 默认是降序
|
|||
/// </summary>
|
|||
public bool OrderByDescending { get; set; } = true; |
|||
} |
@ -0,0 +1,20 @@ |
|||
using Easy.Result.Exceptions; |
|||
|
|||
namespace Easy.Result; |
|||
|
|||
/// <summary>
|
|||
/// when 语句
|
|||
/// </summary>
|
|||
public class When |
|||
{ |
|||
/// <summary>
|
|||
/// 是
|
|||
/// </summary>
|
|||
/// <param name="isOk">是否</param>
|
|||
/// <param name="message">消息</param>
|
|||
/// <exception cref="SvcException">服务异常会被中间件拦截</exception>
|
|||
public static void Is(bool isOk, string message) |
|||
{ |
|||
if (isOk) throw new SvcException(message); |
|||
} |
|||
} |
Loading…
Reference in new issue