From 7a524ac871ae3bd70104b4fcaf3ee9a11c9a71b3 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Thu, 13 Apr 2023 23:46:44 +0800 Subject: [PATCH 1/5] feat: Support public properties in MinimalAPIs --- .../Helpers/ServiceBaseHelper.cs | 6 ++- .../ServiceBase.cs | 42 ++++++++++++---- .../ServiceGlobalRouteOptions.cs | 1 + .../ServiceRouteOptions.cs | 6 +++ .../ServiceBaseTest.cs | 49 +++++++++++++++---- .../Services/OrderService.cs | 36 ++++++++++++++ 6 files changed, 118 insertions(+), 22 deletions(-) create mode 100644 src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs diff --git a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Helpers/ServiceBaseHelper.cs b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Helpers/ServiceBaseHelper.cs index badf2077d..82113cc8d 100644 --- a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Helpers/ServiceBaseHelper.cs +++ b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Helpers/ServiceBaseHelper.cs @@ -9,7 +9,9 @@ public static Delegate CreateDelegate(MethodInfo methodInfo, object targetInstan { var type = Expression.GetDelegateType(methodInfo.GetParameters().Select(parameterInfo => parameterInfo.ParameterType) .Concat(new List - { methodInfo.ReturnType }).ToArray()); + { + methodInfo.ReturnType + }).ToArray()); return Delegate.CreateDelegate(type, targetInstance, methodInfo); } @@ -24,7 +26,7 @@ public static string ParseMethodPrefix(IEnumerable prefixes, string meth var prefix = prefixes.FirstOrDefault(prefix => newMethodName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)); if (prefix is not null) - return prefix; + return methodName.Substring(0, prefix.Length); return string.Empty; } diff --git a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceBase.cs b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceBase.cs index 4fba71a63..b584c0cf2 100644 --- a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceBase.cs +++ b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceBase.cs @@ -28,6 +28,8 @@ public abstract class ServiceBase : IService public IServiceCollection Services => MasaApp.GetServices(); + private bool? _enableProperty; + #pragma warning disable S4136 protected ServiceBase() { } @@ -50,14 +52,7 @@ protected virtual IServiceProvider GetServiceProvider() internal void AutoMapRoute(ServiceGlobalRouteOptions globalOptions, PluralizationService pluralizationService) { - var type = GetType(); - - var methodInfos = type - .GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance) - .Where(methodInfo => methodInfo.CustomAttributes.All(attr => attr.AttributeType != typeof(IgnoreRouteAttribute))) - .Concat(type.GetMethods(BindingFlags.Public | BindingFlags.Instance) - .Where(methodInfo => methodInfo.CustomAttributes.Any(attr => attr.AttributeType == typeof(RoutePatternAttribute)))) - .Distinct(); + var methodInfos = GetMethodsByAutoMapRoute(GetType(), globalOptions); foreach (var method in methodInfos) { @@ -92,6 +87,25 @@ internal void AutoMapRoute(ServiceGlobalRouteOptions globalOptions, Pluralizatio } } + protected virtual List GetMethodsByAutoMapRoute(Type type, ServiceGlobalRouteOptions globalOptions) + { + BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; + var methodInfos = type + .GetMethods(BindingFlags.DeclaredOnly | bindingFlags) + .Where(methodInfo => methodInfo.CustomAttributes.All(attr => attr.AttributeType != typeof(IgnoreRouteAttribute))) + .Concat(type.GetMethods(bindingFlags) + .Where(methodInfo => methodInfo.CustomAttributes.Any(attr => attr.AttributeType == typeof(RoutePatternAttribute)))) + .Distinct(); + _enableProperty = RouteOptions.EnableProperty ?? globalOptions.EnableProperty ?? false; + if (!_enableProperty.Value) + { + return methodInfos.Where(methodInfo => !methodInfo.IsSpecialName).ToList(); + } + + return methodInfos.Where(methodInfo + => !methodInfo.IsSpecialName || (methodInfo.IsSpecialName && methodInfo.Name.StartsWith("get_"))).ToList(); + } + protected virtual string GetBaseUri(ServiceRouteOptions globalOptions, PluralizationService pluralizationService) { if (!string.IsNullOrWhiteSpace(BaseUri)) @@ -112,7 +126,10 @@ protected virtual string GetBaseUri(ServiceRouteOptions globalOptions, Pluraliza RouteHandlerBuilder MapMethods(ServiceRouteOptions globalOptions, string pattern, string? httpMethod, Delegate handler) { if (!string.IsNullOrWhiteSpace(httpMethod)) - return App.MapMethods(pattern, new[] { httpMethod }, handler); + return App.MapMethods(pattern, new[] + { + httpMethod + }, handler); var httpMethods = GetDefaultHttpMethods(globalOptions); if (httpMethods.Length > 0) @@ -173,7 +190,12 @@ string TrimMethodPrefix(string name) protected virtual (string? HttpMethod, string Prefix) ParseMethod(ServiceRouteOptions globalOptions, string methodName) { - var prefix = ServiceBaseHelper.ParseMethodPrefix(RouteOptions.GetPrefixes ?? globalOptions.GetPrefixes!, methodName); + var getPrefixes = RouteOptions.GetPrefixes ?? globalOptions.GetPrefixes!; + if (_enableProperty!.Value) + { + getPrefixes.Insert(0, "get_"); + } + var prefix = ServiceBaseHelper.ParseMethodPrefix(getPrefixes, methodName); if (!string.IsNullOrEmpty(prefix)) return ("GET", prefix); diff --git a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceGlobalRouteOptions.cs b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceGlobalRouteOptions.cs index ad8ff2d95..b416a821b 100644 --- a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceGlobalRouteOptions.cs +++ b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceGlobalRouteOptions.cs @@ -25,5 +25,6 @@ public ServiceGlobalRouteOptions() DisableTrimMethodPrefix = false; Assemblies = MasaApp.GetAssemblies(); Pluralization = PluralizationService.CreateService(CultureInfo.CreateSpecificCulture("en")); + EnableProperty = false; } } diff --git a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceRouteOptions.cs b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceRouteOptions.cs index c0372eda5..4c09e5b8f 100644 --- a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceRouteOptions.cs +++ b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceRouteOptions.cs @@ -42,4 +42,10 @@ public class ServiceRouteOptions /// When the collection is empty, the default Post, Get, Put, Delete all support access /// public string[] MapHttpMethodsForUnmatched { get; set; } = Array.Empty(); + + /// + /// Enable access to public properties + /// default: false + /// + public bool? EnableProperty { get; set; } } diff --git a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/ServiceBaseTest.cs b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/ServiceBaseTest.cs index 5c8260427..d6b211a1c 100644 --- a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/ServiceBaseTest.cs +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/ServiceBaseTest.cs @@ -6,6 +6,9 @@ namespace Masa.Contrib.Service.MinimalAPIs.Tests; [TestClass] public class ServiceBaseTest { + private static FieldInfo _enablePropertyFieldInfo + => typeof(ServiceBase).GetField("_enableProperty", BindingFlags.Instance | BindingFlags.NonPublic)!; + [TestMethod] public void TestGetBaseUri() { @@ -40,9 +43,7 @@ public void TestCombineUris() { var uris = new[] { - "api", - "v1", - "order" + "api", "v1", "order" }; Assert.AreEqual("api/v1/order", ServiceBaseHelper.CombineUris(uris)); } @@ -154,18 +155,26 @@ public void TestConstructor() } [DataTestMethod] - [DataRow("AddUser", "POST", "Add")] - [DataRow("PostUser", "POST", "Post")] - [DataRow("DeleteUser", "DELETE", "Delete")] - [DataRow("PutUser", "PUT", "Put")] - [DataRow("GetUser", "GET", "Get")] - [DataRow("AuditState", null, "")] + [DataRow("AddUser", "POST", "Add", false)] + [DataRow("PostUser", "POST", "Post", false)] + [DataRow("DeleteUser", "DELETE", "Delete", false)] + [DataRow("PutUser", "PUT", "Put", false)] + [DataRow("GetUser", "GET", "Get", false)] + [DataRow("get_Name", "GET", "get", false)] + [DataRow("get_Name", "GET", "get_", true)] + [DataRow("set_Name", null, "", false)] + [DataRow("set_Name", null, "", true)] + [DataRow("AuditState", null, "", false)] public void TestParseMethod( string methodName, string? actualHttpMethod, - string actualPrefix) + string actualPrefix, + bool enableProperty) { var service = new UserService(); + + _enablePropertyFieldInfo.SetValue(service, enableProperty); + var globalOptions = new ServiceGlobalRouteOptions(); var result = service.TestParseMethod(globalOptions, methodName); Assert.AreEqual(actualHttpMethod, result.HttpMethod); @@ -202,6 +211,26 @@ public void TestGetServiceName(bool enablePluralizeServiceName, string actualSer Assert.AreEqual("Catalogs", service.TestGetServiceName(pluralizationService)); } + [DataTestMethod] + [DataRow(true, true, 2)] + [DataRow(true, false, 1)] + [DataRow(true, null, 2)] + [DataRow(null, true, 2)] + [DataRow(null, false, 1)] + [DataRow(null, null, 1)] + [DataRow(false, true, 2)] + [DataRow(false, false, 1)] + [DataRow(false, null, 1)] + public void TestGetMethodsByAutoMapRoute(bool? globalEnableProperty, bool? enableProperty, int expectedNumber) + { + var orderService = new OrderService(enableProperty); + var methodInfos = orderService.TestGetMethodsByAutoMapRoute(new ServiceGlobalRouteOptions() + { + EnableProperty = globalEnableProperty + }); + Assert.AreEqual(expectedNumber, methodInfos.Count); + } + #region private methods private static CustomServiceBase GetCustomService() diff --git a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs new file mode 100644 index 000000000..56b546701 --- /dev/null +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs @@ -0,0 +1,36 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.Service.MinimalAPIs.Tests.Services; + +public class OrderService : ServiceBase +{ + public OrderService(bool? enableProperty) + { + RouteOptions.EnableProperty = enableProperty; + } + + public string ConnectionString => GetConnectionString; + + public static string GetConnectionString => "connection string"; + + private int Age { get; set; } + + private static string GetName() => "name"; + + public static void SetName() + { + + } + + public override string ToString() + { + return base.ToString(); + } + + [IgnoreRoute] + public List TestGetMethodsByAutoMapRoute(ServiceGlobalRouteOptions globalOptions) + { + return base.GetMethodsByAutoMapRoute(typeof(OrderService), globalOptions); + } +} From 27b31403afb1b9b496260468fe91fce7313056e1 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Thu, 13 Apr 2023 23:48:38 +0800 Subject: [PATCH 2/5] feat: Support public properties in MinimalAPIs --- .../Services/OrderService.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs index 56b546701..82d5d869c 100644 --- a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs @@ -5,17 +5,21 @@ namespace Masa.Contrib.Service.MinimalAPIs.Tests.Services; public class OrderService : ServiceBase { - public OrderService(bool? enableProperty) - { - RouteOptions.EnableProperty = enableProperty; - } - public string ConnectionString => GetConnectionString; public static string GetConnectionString => "connection string"; + public int Id { private get; set; } + private int Age { get; set; } + public int CreateTime; + + public OrderService(bool? enableProperty) + { + RouteOptions.EnableProperty = enableProperty; + } + private static string GetName() => "name"; public static void SetName() From 8cd98b7079133829ee89aa160d0da1f1f520eb7e Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Fri, 14 Apr 2023 00:29:24 +0800 Subject: [PATCH 3/5] fix: Fix unit test errors --- .../Service/Masa.Contrib.Service.MinimalAPIs/ServiceBase.cs | 2 +- .../Services/OrderService.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceBase.cs b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceBase.cs index b584c0cf2..c7c3216db 100644 --- a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceBase.cs +++ b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/ServiceBase.cs @@ -89,7 +89,7 @@ internal void AutoMapRoute(ServiceGlobalRouteOptions globalOptions, Pluralizatio protected virtual List GetMethodsByAutoMapRoute(Type type, ServiceGlobalRouteOptions globalOptions) { - BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; + var bindingFlags = BindingFlags.Public | BindingFlags.Instance; var methodInfos = type .GetMethods(BindingFlags.DeclaredOnly | bindingFlags) .Where(methodInfo => methodInfo.CustomAttributes.All(attr => attr.AttributeType != typeof(IgnoreRouteAttribute))) diff --git a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs index 82d5d869c..2ecb732c4 100644 --- a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs @@ -15,6 +15,11 @@ public class OrderService : ServiceBase public int CreateTime; + public OrderService() : base() + { + + } + public OrderService(bool? enableProperty) { RouteOptions.EnableProperty = enableProperty; From 5d46482ab736d640d99e94969161ba9236f4c672 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Fri, 14 Apr 2023 00:29:42 +0800 Subject: [PATCH 4/5] chore: Optimize unit test duration --- .../IdGeneratorTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Contrib/Data/IdGenerator/Snowflake/Tests/Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis.Tests/IdGeneratorTest.cs b/src/Contrib/Data/IdGenerator/Snowflake/Tests/Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis.Tests/IdGeneratorTest.cs index b4eeb0b53..35482d038 100644 --- a/src/Contrib/Data/IdGenerator/Snowflake/Tests/Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis.Tests/IdGeneratorTest.cs +++ b/src/Contrib/Data/IdGenerator/Snowflake/Tests/Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis.Tests/IdGeneratorTest.cs @@ -233,7 +233,7 @@ public async Task TestGetWorkerIdAsync() [TestMethod] public async Task TestGetDistibutedLockFaieldAsync() { - var workerIdBits = 10; + var workerIdBits = 2; var maxWorkerId = ~(-1L << workerIdBits); var tasks = new ConcurrentBag(); ThreadPool.GetMinThreads(out int workerThreads, out var minIoc); From 43952ab08eae6d32d39b04f1fcf747b5ae1a03e6 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Fri, 14 Apr 2023 00:39:33 +0800 Subject: [PATCH 5/5] chore: Fix code smell --- .../IdGeneratorTest.cs | 2 +- .../Services/OrderService.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Contrib/Data/IdGenerator/Snowflake/Tests/Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis.Tests/IdGeneratorTest.cs b/src/Contrib/Data/IdGenerator/Snowflake/Tests/Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis.Tests/IdGeneratorTest.cs index 35482d038..63be025b1 100644 --- a/src/Contrib/Data/IdGenerator/Snowflake/Tests/Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis.Tests/IdGeneratorTest.cs +++ b/src/Contrib/Data/IdGenerator/Snowflake/Tests/Masa.Contrib.Data.IdGenerator.Snowflake.Distributed.Redis.Tests/IdGeneratorTest.cs @@ -242,7 +242,7 @@ public async Task TestGetDistibutedLockFaieldAsync() int laterTime = 0; try { - Parallel.For(0, maxWorkerId * 2, _ => + Parallel.For(0, maxWorkerId * 10, _ => { tasks.Add(GetWorkerIdAsync(null, workerIdBits)); }); diff --git a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs index 2ecb732c4..086ee946a 100644 --- a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs @@ -3,6 +3,7 @@ namespace Masa.Contrib.Service.MinimalAPIs.Tests.Services; +#pragma warning disable CA1822 public class OrderService : ServiceBase { public string ConnectionString => GetConnectionString; @@ -34,7 +35,7 @@ public static void SetName() public override string ToString() { - return base.ToString(); + return nameof(OrderService); } [IgnoreRoute] @@ -43,3 +44,4 @@ public List TestGetMethodsByAutoMapRoute(ServiceGlobalRouteOptions g return base.GetMethodsByAutoMapRoute(typeof(OrderService), globalOptions); } } +#pragma warning restore CA1822