diff --git a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Extensions/ServiceCollectionExtensions.cs b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Extensions/ServiceCollectionExtensions.cs index cd170eaf7..c79ece373 100644 --- a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Extensions/ServiceCollectionExtensions.cs +++ b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Extensions/ServiceCollectionExtensions.cs @@ -87,6 +87,8 @@ public static IServiceCollection AddMasaMinimalAPIs( var serviceProvider = services.BuildServiceProvider(); var serviceMapOptions = serviceProvider.GetRequiredService>().Value; var serviceTypes = TypeHelper.GetServiceTypes(serviceMapOptions.Assemblies.ToArray()); + + GlobalMinimalApiOptions.InitializeService(); foreach (var serviceType in serviceTypes) { GlobalMinimalApiOptions.AddService(serviceType); diff --git a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Extensions/WebApplicationExtensions.cs b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Extensions/WebApplicationExtensions.cs index 4f1e97709..c4f04fce2 100644 --- a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Extensions/WebApplicationExtensions.cs +++ b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Extensions/WebApplicationExtensions.cs @@ -17,7 +17,7 @@ public static void MapMasaMinimalAPIs(this WebApplication webApplication) { var serviceInstance = (ServiceBase)webApplication.Services.GetRequiredService(serviceType); if (serviceInstance.RouteOptions.DisableAutoMapRoute ?? serviceMapOptions.DisableAutoMapRoute ?? false) - return; + continue; serviceInstance.AutoMapRoute(serviceMapOptions, serviceMapOptions.Pluralization); } diff --git a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Internal/GlobalMinimalApiOptions.cs b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Internal/GlobalMinimalApiOptions.cs index ca9844440..0d0064492 100644 --- a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Internal/GlobalMinimalApiOptions.cs +++ b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/Internal/GlobalMinimalApiOptions.cs @@ -1,6 +1,8 @@ // Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. +[assembly: InternalsVisibleTo("Masa.Contrib.Service.MinimalAPIs.Tests")] + // ReSharper disable once CheckNamespace namespace Masa.Contrib.Service.MinimalAPIs; @@ -13,6 +15,11 @@ internal static class GlobalMinimalApiOptions #pragma warning restore S2223 public static List ServiceTypes { get; private set; } = new(); + public static void InitializeService() + { + ServiceTypes = new List(); + } + public static void AddService(Type serviceType) { if (ServiceTypes.Contains(serviceType)) diff --git a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/_Imports.cs b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/_Imports.cs index 9c5591190..eeefb3634 100644 --- a/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/_Imports.cs +++ b/src/Contrib/Service/Masa.Contrib.Service.MinimalAPIs/_Imports.cs @@ -17,4 +17,5 @@ global using System.Linq; global using System.Linq.Expressions; global using System.Reflection; +global using System.Runtime.CompilerServices; global using System.Threading; diff --git a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/MinimalAPITest.cs b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/MinimalAPITest.cs index c9414374b..0f5dd5487 100644 --- a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/MinimalAPITest.cs +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/MinimalAPITest.cs @@ -26,42 +26,107 @@ public void TestAddMultiServices() [TestMethod] public void AddService() { + MasaApp.SetServiceCollection(_builder.Services); var app = _builder.AddServices(); Assert.IsTrue(_builder.Services.Any(service => service.ServiceType == typeof(CustomService) && service.Lifetime == ServiceLifetime.Scoped)); - var servicePrvider = _builder.Services.BuildServiceProvider(); - var customService = servicePrvider.GetService(); + var serviceProvider = _builder.Services.BuildServiceProvider(); + var customService = serviceProvider.GetService(); Assert.IsNotNull(customService); - Assert.ReferenceEquals(customService.App, app); + Assert.AreEqual(customService.App, app); - Assert.ReferenceEquals(customService.Services, _builder.Services); + Assert.AreEqual(customService.Services, _builder.Services); Assert.ThrowsException(() => customService.GetRequiredService()); Assert.IsTrue(customService.GetTest2() == 1); - var newCustomService = servicePrvider.CreateScope().ServiceProvider.GetService(); + var newCustomService = serviceProvider.CreateScope().ServiceProvider.GetService(); Assert.IsNotNull(newCustomService); Assert.IsTrue(newCustomService.GetTest2() == 1); } [TestMethod] - public void TestMapMasaMinimalAPIs() + public void TestAddMasaMinimalApIs() { _builder.Services.AddMasaMinimalAPIs(); - Assert.IsTrue(_builder.Services.Any()); - Assert.IsTrue(_builder.Services.Any()); - Assert.IsTrue(_builder.Services.Any()); - Assert.IsTrue(_builder.Services.Any()); - - var app = _builder.Build(); + Assert.AreEqual(6, GlobalMinimalApiOptions.ServiceTypes.Count); + } + [TestMethod] + public void TestMapMasaMinimalApIs() + { + GlobalMinimalApiOptions.InitializeService(); + GlobalMinimalApiOptions.AddService(typeof(PersonService)); + GlobalMinimalApiOptions.AddService(typeof(GoodsService)); + + var builder = WebApplication.CreateBuilder(); + builder.Services.Configure(options => options.DisableAutoMapRoute = false); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(_ => new GoodsService(builder.Services, "")); + var app = builder.Build(); app.MapMasaMinimalAPIs(); - var service = (ServiceBase)app.Services.GetRequiredService(typeof(CatalogService)); - Assert.AreEqual(app, service.App); + var routeBuilder = (IEndpointRouteBuilder)app; + var endpoints = routeBuilder.DataSources.SelectMany(x => x.Endpoints).ToList(); + var group = GetServiceActionGroup(endpoints); + Assert.AreEqual(2, group.Count); + Assert.AreEqual(2, group[nameof(GoodsService)].Count); + Assert.AreEqual(1, group[nameof(PersonService)].Count); } + + #region Private Methods + + private static Dictionary> GetServiceActionGroup(List endpoints) + { + Dictionary> serviceRoutes = new(StringComparer.OrdinalIgnoreCase); + foreach (var endpoint in endpoints) + { + string serviceName = GetServiceName(endpoint); + if (!serviceRoutes.ContainsKey(serviceName)) + { + serviceRoutes[serviceName] = new List(); + } + + if (TryParseServiceActionName(endpoint, out string? actionName)) + { + serviceRoutes[serviceName].Add(actionName); + } + } + + return serviceRoutes; + } + + private static bool TryParseServiceActionName(Endpoint endpoint, [NotNullWhen(true)] out string? actionName) + { + if (endpoint is not RouteEndpoint routeEndpoint) + { + actionName = null; + return false; + } + + actionName = routeEndpoint.DisplayName ?? string.Empty; + return true; + } + + private static string GetServiceName(Endpoint endpoint) + { + var metadata = endpoint.Metadata.GetMetadata(); + Assert.IsNotNull(metadata); + return (object?)metadata.DeclaringType == null || IsCompilerGeneratedType(metadata.DeclaringType) + ? "" + : metadata.DeclaringType.Name; + } + + static bool IsCompilerGeneratedType(Type? type = null) + { + if (type == null) + return false; + return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute)) || IsCompilerGeneratedType(type.DeclaringType); + } + + #endregion } 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 d6b211a1c..7552e4d17 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 @@ -246,5 +246,4 @@ private static CustomServiceBase GetCatalogService() => new CatalogService(); #endregion - } diff --git a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/CustomServiceBase.cs b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/CustomServiceBase.cs index 15829aded..2fdad7f92 100644 --- a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/CustomServiceBase.cs +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/CustomServiceBase.cs @@ -20,8 +20,8 @@ public CustomServiceBase(IServiceCollection services, string baseUri) : base(ser } #pragma warning restore CS0618 - public string TestGetBaseUri(ServiceRouteOptions globalOptions) => base.GetBaseUri(globalOptions, - PluralizationService.CreateService(System.Globalization.CultureInfo.CreateSpecificCulture("en"))); + public string TestGetBaseUri(ServiceRouteOptions globalOptions) + => base.GetBaseUri(globalOptions, PluralizationService.CreateService(System.Globalization.CultureInfo.CreateSpecificCulture("en"))); public string TestGetMethodName(MethodInfo methodInfo, string prefix, ServiceRouteOptions globalOptions) => base.GetMethodName(methodInfo, prefix, globalOptions); diff --git a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/GoodsService.cs b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/GoodsService.cs index 572e83292..6d2d287e3 100644 --- a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/GoodsService.cs +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/GoodsService.cs @@ -13,5 +13,18 @@ public GoodsService() public GoodsService(IServiceCollection services, string baseUri) : base(services, baseUri) { + RouteOptions.DisableAutoMapRoute = true; + App.MapGet("add", AddAsync); + App.MapGet("update", UpdateAsync); + } + + private Task AddAsync() + { + return Task.FromResult(Results.Accepted()); + } + + private Task UpdateAsync() + { + return Task.FromResult(Results.Accepted()); } } 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 086ee946a..9459ccad0 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 @@ -10,12 +10,6 @@ public class OrderService : ServiceBase public static string GetConnectionString => "connection string"; - public int Id { private get; set; } - - private int Age { get; set; } - - public int CreateTime; - public OrderService() : base() { diff --git a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/PersonService.cs b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/PersonService.cs new file mode 100644 index 000000000..50473ea51 --- /dev/null +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/Services/PersonService.cs @@ -0,0 +1,18 @@ +// 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 PersonService : ServiceBase +{ + public PersonService() + { + RouteOptions.DisableAutoMapRoute = true; + App.MapGet("list", GetListAsync); + } + + private Task GetListAsync() + { + return Task.CompletedTask; + } +} diff --git a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/_Imports.cs b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/_Imports.cs index 9b9e7f7cc..0b401e464 100644 --- a/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/_Imports.cs +++ b/src/Contrib/Service/Tests/Masa.Contrib.Service.MinimalAPIs.Tests/_Imports.cs @@ -1,9 +1,14 @@ // Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. +global using Masa.BuildingBlocks.Data; global using Masa.Contrib.Service.MinimalAPIs.Tests.Services; global using Microsoft.AspNetCore.Builder; +global using Microsoft.AspNetCore.Http; +global using Microsoft.AspNetCore.Routing; global using Microsoft.AspNetCore.Mvc; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using System.Diagnostics.CodeAnalysis; global using System.Reflection; +global using System.Runtime.CompilerServices;