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..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 @@ -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); @@ -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/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..c7c3216db 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) + { + var 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..086ee946a --- /dev/null +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/OrderService.cs @@ -0,0 +1,47 @@ +// 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; + +#pragma warning disable CA1822 +public class OrderService : ServiceBase +{ + 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() : base() + { + + } + + public OrderService(bool? enableProperty) + { + RouteOptions.EnableProperty = enableProperty; + } + + private static string GetName() => "name"; + + public static void SetName() + { + + } + + public override string ToString() + { + return nameof(OrderService); + } + + [IgnoreRoute] + public List TestGetMethodsByAutoMapRoute(ServiceGlobalRouteOptions globalOptions) + { + return base.GetMethodsByAutoMapRoute(typeof(OrderService), globalOptions); + } +} +#pragma warning restore CA1822