diff --git a/Masa.Framework.sln b/Masa.Framework.sln index 0c0780ae1..67e7052c8 100644 --- a/Masa.Framework.sln +++ b/Masa.Framework.sln @@ -525,6 +525,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Framework.IntegrationT EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.IdGenerator.NormalGuid.Tests", "src\Contrib\Data\IdGenerator\NormalGuid\Masa.Contrib.Data.IdGenerator.NormalGuid.Tests\Masa.Contrib.Data.IdGenerator.NormalGuid.Tests.csproj", "{C488CAC3-6F06-4D29-B449-93CEF482C4D7}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Serialization", "Serialization", "{F2595DAE-AEB7-4739-8578-B6635FC7C6FB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.Serialization.Json", "src\Contrib\Data\Serialization\Masa.Contrib.Data.Serialization.Json\Masa.Contrib.Data.Serialization.Json.csproj", "{E14E5712-EEC4-4249-84A5-5AC930E51E28}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.Serialization.Yaml", "src\Contrib\Data\Serialization\Masa.Contrib.Data.Serialization.Yaml\Masa.Contrib.Data.Serialization.Yaml.csproj", "{7E8785A6-1B4D-4A35-9DA1-F6B99FF8C740}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{6E93CADC-B6C7-4063-BEA7-56068D682C31}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.Serialization.Json.Tests", "src\Contrib\Data\Serialization\Tests\Masa.Contrib.Data.Serialization.Json.Tests\Masa.Contrib.Data.Serialization.Json.Tests.csproj", "{C55B75D2-43E0-4D3D-B705-110C4255528A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Contrib.Data.Serialization.Yaml.Tests", "src\Contrib\Data\Serialization\Tests\Masa.Contrib.Data.Serialization.Yaml.Tests\Masa.Contrib.Data.Serialization.Yaml.Tests.csproj", "{A86DA6FB-58E0-4FEE-B663-C336F9B3A3A5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1853,6 +1865,38 @@ Global {C488CAC3-6F06-4D29-B449-93CEF482C4D7}.Release|Any CPU.Build.0 = Release|Any CPU {C488CAC3-6F06-4D29-B449-93CEF482C4D7}.Release|x64.ActiveCfg = Release|Any CPU {C488CAC3-6F06-4D29-B449-93CEF482C4D7}.Release|x64.Build.0 = Release|Any CPU + {E14E5712-EEC4-4249-84A5-5AC930E51E28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E14E5712-EEC4-4249-84A5-5AC930E51E28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E14E5712-EEC4-4249-84A5-5AC930E51E28}.Debug|x64.ActiveCfg = Debug|Any CPU + {E14E5712-EEC4-4249-84A5-5AC930E51E28}.Debug|x64.Build.0 = Debug|Any CPU + {E14E5712-EEC4-4249-84A5-5AC930E51E28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E14E5712-EEC4-4249-84A5-5AC930E51E28}.Release|Any CPU.Build.0 = Release|Any CPU + {E14E5712-EEC4-4249-84A5-5AC930E51E28}.Release|x64.ActiveCfg = Release|Any CPU + {E14E5712-EEC4-4249-84A5-5AC930E51E28}.Release|x64.Build.0 = Release|Any CPU + {7E8785A6-1B4D-4A35-9DA1-F6B99FF8C740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E8785A6-1B4D-4A35-9DA1-F6B99FF8C740}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E8785A6-1B4D-4A35-9DA1-F6B99FF8C740}.Debug|x64.ActiveCfg = Debug|Any CPU + {7E8785A6-1B4D-4A35-9DA1-F6B99FF8C740}.Debug|x64.Build.0 = Debug|Any CPU + {7E8785A6-1B4D-4A35-9DA1-F6B99FF8C740}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E8785A6-1B4D-4A35-9DA1-F6B99FF8C740}.Release|Any CPU.Build.0 = Release|Any CPU + {7E8785A6-1B4D-4A35-9DA1-F6B99FF8C740}.Release|x64.ActiveCfg = Release|Any CPU + {7E8785A6-1B4D-4A35-9DA1-F6B99FF8C740}.Release|x64.Build.0 = Release|Any CPU + {C55B75D2-43E0-4D3D-B705-110C4255528A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C55B75D2-43E0-4D3D-B705-110C4255528A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C55B75D2-43E0-4D3D-B705-110C4255528A}.Debug|x64.ActiveCfg = Debug|Any CPU + {C55B75D2-43E0-4D3D-B705-110C4255528A}.Debug|x64.Build.0 = Debug|Any CPU + {C55B75D2-43E0-4D3D-B705-110C4255528A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C55B75D2-43E0-4D3D-B705-110C4255528A}.Release|Any CPU.Build.0 = Release|Any CPU + {C55B75D2-43E0-4D3D-B705-110C4255528A}.Release|x64.ActiveCfg = Release|Any CPU + {C55B75D2-43E0-4D3D-B705-110C4255528A}.Release|x64.Build.0 = Release|Any CPU + {A86DA6FB-58E0-4FEE-B663-C336F9B3A3A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A86DA6FB-58E0-4FEE-B663-C336F9B3A3A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A86DA6FB-58E0-4FEE-B663-C336F9B3A3A5}.Debug|x64.ActiveCfg = Debug|Any CPU + {A86DA6FB-58E0-4FEE-B663-C336F9B3A3A5}.Debug|x64.Build.0 = Debug|Any CPU + {A86DA6FB-58E0-4FEE-B663-C336F9B3A3A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A86DA6FB-58E0-4FEE-B663-C336F9B3A3A5}.Release|Any CPU.Build.0 = Release|Any CPU + {A86DA6FB-58E0-4FEE-B663-C336F9B3A3A5}.Release|x64.ActiveCfg = Release|Any CPU + {A86DA6FB-58E0-4FEE-B663-C336F9B3A3A5}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2111,6 +2155,12 @@ Global {9EA05A47-B28A-4CD1-8058-00A2098ED0C2} = {55DCA34D-48CE-4D32-8515-B6583FA548AE} {A9EED08B-6C1E-4409-9874-AA7D34102519} = {E747043D-81E2-4A89-8B5B-1258ED45F941} {C488CAC3-6F06-4D29-B449-93CEF482C4D7} = {4515CCA0-E8FC-4FCF-93E1-B812F5949371} + {F2595DAE-AEB7-4739-8578-B6635FC7C6FB} = {BE980C6D-3277-44C4-8203-959239F81F67} + {E14E5712-EEC4-4249-84A5-5AC930E51E28} = {F2595DAE-AEB7-4739-8578-B6635FC7C6FB} + {7E8785A6-1B4D-4A35-9DA1-F6B99FF8C740} = {F2595DAE-AEB7-4739-8578-B6635FC7C6FB} + {6E93CADC-B6C7-4063-BEA7-56068D682C31} = {F2595DAE-AEB7-4739-8578-B6635FC7C6FB} + {C55B75D2-43E0-4D3D-B705-110C4255528A} = {6E93CADC-B6C7-4063-BEA7-56068D682C31} + {A86DA6FB-58E0-4FEE-B663-C336F9B3A3A5} = {6E93CADC-B6C7-4063-BEA7-56068D682C31} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {40383055-CC50-4600-AD9A-53C14F620D03} diff --git a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/DefaultTypeConvertProvider.cs b/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/DefaultTypeConvertProvider.cs deleted file mode 100644 index 0ec0aca6d..000000000 --- a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/DefaultTypeConvertProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) MASA Stack All rights reserved. -// Licensed under the MIT License. See LICENSE.txt in the project root for license information. - -namespace Masa.BuildingBlocks.Authentication.Identity; - -public class DefaultTypeConvertProvider : ITypeConvertProvider -{ - public T ConvertTo(string value) - { - if (typeof(T) == typeof(Guid)) - return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(value)!; - - return (T)Convert.ChangeType(value, typeof(T)); - } -} diff --git a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/Enum/IdentityType.cs b/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/Enum/IdentityType.cs deleted file mode 100644 index 4b3bf50c0..000000000 --- a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/Enum/IdentityType.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) MASA Stack All rights reserved. -// Licensed under the MIT License. See LICENSE.txt in the project root for license information. - -namespace Masa.BuildingBlocks.Authentication.Identity; - -[Flags] -public enum IdentityType -{ - /// - /// Only use user information - /// - Basic = 0x01, - - /// - /// Multi-tenant - /// - MultiTenant = 0x02, - - /// - /// Multi-Environment - /// - MultiEnvironment = 0x04, -} diff --git a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/IUserContext.cs b/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/IUserContext.cs index 165bc435c..d79bd51f0 100644 --- a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/IUserContext.cs +++ b/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/IUserContext.cs @@ -13,6 +13,8 @@ public interface IUserContext TUserId? GetUserId(); + IdentityUser? GetUser(); + TIdentityUser? GetUser() where TIdentityUser : IIdentityUser; IEnumerable GetUserRoles(); diff --git a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/Masa.BuildingBlocks.Authentication.Identity.csproj b/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/Masa.BuildingBlocks.Authentication.Identity.csproj index 132c02c59..b3d41f5ba 100644 --- a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/Masa.BuildingBlocks.Authentication.Identity.csproj +++ b/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/Masa.BuildingBlocks.Authentication.Identity.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/UserContext.cs b/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/UserContext.cs index 55301d0cf..dcf6bb088 100644 --- a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/UserContext.cs +++ b/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/UserContext.cs @@ -5,7 +5,7 @@ namespace Masa.BuildingBlocks.Authentication.Identity; public abstract class UserContext : IUserSetter, IUserContext { - private readonly AsyncLocal _currentUser = new(); + private readonly AsyncLocal?> _currentUser = new(); public bool IsAuthenticated => GetUserSimple() != null; @@ -15,11 +15,13 @@ public abstract class UserContext : IUserSetter, IUserContext protected ITypeConvertProvider TypeConvertProvider { get; } - public UserContext(ITypeConvertProvider typeConvertProvider) => TypeConvertProvider = typeConvertProvider; - - protected abstract object? GetUser(); + protected UserContext(ITypeConvertProvider typeConvertProvider) + { + TypeConvertProvider = typeConvertProvider; + _currentUser.Value = new Dictionary(); + } - protected abstract IdentityUser? GetUserBasicInfo(); + protected abstract object? GetUser(Type userType); public TUserId? GetUserId() { @@ -30,9 +32,16 @@ public abstract class UserContext : IUserSetter, IUserContext return TypeConvertProvider.ConvertTo(userId); } + public IdentityUser? GetUser() => GetUser(); + public TIdentityUser? GetUser() where TIdentityUser : IIdentityUser { - var user = _currentUser.Value ?? GetUser(); + var userModelType = typeof(TIdentityUser); + if (!_currentUser.Value!.TryGetValue(userModelType, out var user) || user == null) + { + user ??= GetUser(userModelType); + _currentUser.Value.TryAdd(userModelType, user); + } return user == null ? default : (TIdentityUser)user; } @@ -40,13 +49,16 @@ public abstract class UserContext : IUserSetter, IUserContext public IDisposable Change(TIdentityUser identityUser) where TIdentityUser : IIdentityUser { - var user = GetUser(); - _currentUser.Value = identityUser; - return new DisposeAction(() => _currentUser.Value = user); + var userModelType = typeof(TIdentityUser); + var user = GetUser(userModelType); + _currentUser.Value![userModelType] = identityUser; + return new DisposeAction(() => _currentUser.Value[userModelType] = user); } public IEnumerable GetUserRoles() { - return GetUserSimple()?.Roles.Select(r => TypeConvertProvider.ConvertTo(r)) ?? new List(); + return GetUserSimple()?.Roles + .Select(r => TypeConvertProvider.ConvertTo(r) ?? + throw new ArgumentException($"RoleId cannot be converted to [{typeof(TRoleId).Name}]")) ?? new List(); } } diff --git a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/_Imports.cs b/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/_Imports.cs index d37b21c00..fabbc0a50 100644 --- a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/_Imports.cs +++ b/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/_Imports.cs @@ -2,4 +2,4 @@ // Licensed under the MIT License. See LICENSE.txt in the project root for license information. global using Masa.BuildingBlocks.Authentication.Identity.Internal; -global using System.ComponentModel; +global using Masa.BuildingBlocks.Data; diff --git a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/ITypeConvertProvider.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Enum/DataType.cs similarity index 54% rename from src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/ITypeConvertProvider.cs rename to src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Enum/DataType.cs index 947573c9d..daed9cdcb 100644 --- a/src/BuildingBlocks/Authentication/Masa.BuildingBlocks.Authentication.Identity/ITypeConvertProvider.cs +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Enum/DataType.cs @@ -1,9 +1,11 @@ // Copyright (c) MASA Stack All rights reserved. // Licensed under the MIT License. See LICENSE.txt in the project root for license information. -namespace Masa.BuildingBlocks.Authentication.Identity; +namespace Masa.BuildingBlocks.Data; -public interface ITypeConvertProvider +public enum DataType { - T ConvertTo(string value); + Json = 1, + Xml = 2, + Yml = 3 } diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Extensions/ServiceCollectionExtensions.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/IdGenerator/Extensions/ServiceCollectionExtensions.cs similarity index 88% rename from src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Extensions/ServiceCollectionExtensions.cs rename to src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/IdGenerator/Extensions/ServiceCollectionExtensions.cs index c318c81f4..65b4b383a 100644 --- a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Extensions/ServiceCollectionExtensions.cs +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/IdGenerator/Extensions/ServiceCollectionExtensions.cs @@ -3,7 +3,7 @@ namespace Microsoft.Extensions.DependencyInjection; -public static class ServiceCollectionExtensions +public static partial class ServiceCollectionExtensions { public static IServiceCollection AddIdGeneratorCore(this IServiceCollection services) { diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/DefaultDeserializerFactory.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/DefaultDeserializerFactory.cs new file mode 100644 index 000000000..d08f3d01b --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/DefaultDeserializerFactory.cs @@ -0,0 +1,39 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public class DefaultDeserializerFactory : IDeserializerFactory +{ + private readonly IServiceProvider _serviceProvider; + private readonly IOptions _deserializerFactoryOptions; + private readonly DeserializerRelationOptions? _defaultDeserializerOptions; + + public DefaultDeserializerFactory(IServiceProvider serviceProvider, IOptions deserializerFactoryOptions) + { + _serviceProvider = serviceProvider; + _deserializerFactoryOptions = deserializerFactoryOptions; + _defaultDeserializerOptions = deserializerFactoryOptions.Value.Options.FirstOrDefault(options + => options.Name == Options.DefaultName) ?? + deserializerFactoryOptions.Value.Options.FirstOrDefault(); + } + + public IDeserializer Create() + { + if (_defaultDeserializerOptions == null) + throw new NotImplementedException("Default deserializer not found, you need to add it, like services.AddJson()"); + + return _defaultDeserializerOptions.Func.Invoke(_serviceProvider); + } + + public IDeserializer Create(string name) + { + var deserializerOptions = + _deserializerFactoryOptions.Value.Options.FirstOrDefault(options + => options.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + if (deserializerOptions == null) + throw new NotImplementedException($"No deserializer found for 【{name}】"); + + return deserializerOptions.Func.Invoke(_serviceProvider); + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/DefaultSerializerFactory.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/DefaultSerializerFactory.cs new file mode 100644 index 000000000..51475e911 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/DefaultSerializerFactory.cs @@ -0,0 +1,39 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public class DefaultSerializerFactory : ISerializerFactory +{ + private readonly IServiceProvider _serviceProvider; + private readonly IOptions _serializerFactoryOptions; + private readonly SerializerRelationOptions? _defaultSerializerOptions; + + public DefaultSerializerFactory(IServiceProvider serviceProvider, IOptions serializerFactoryOptions) + { + _serviceProvider = serviceProvider; + _serializerFactoryOptions = serializerFactoryOptions; + _defaultSerializerOptions = serializerFactoryOptions.Value.Options.FirstOrDefault(options + => options.Name == Options.DefaultName) ?? + serializerFactoryOptions.Value.Options.FirstOrDefault(); + } + + public ISerializer Create() + { + if (_defaultSerializerOptions == null) + throw new NotImplementedException("Default serializer not found, you need to add it, like services.AddJson()"); + + return _defaultSerializerOptions.Func.Invoke(_serviceProvider); + } + + public ISerializer Create(string name) + { + var serializerOptions = + _serializerFactoryOptions.Value.Options.FirstOrDefault(options + => options.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + if (serializerOptions == null) + throw new NotImplementedException($"No serializer found for 【{name}】"); + + return serializerOptions.Func.Invoke(_serviceProvider); + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Extensions/ServiceCollectionExtensions.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..49f83c007 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,16 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Microsoft.Extensions.DependencyInjection; + +public static partial class ServiceCollectionExtensions +{ + public static IServiceCollection AddSerializationCore(this IServiceCollection services) + { + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(serviceProvider => serviceProvider.GetRequiredService().Create()); + services.TryAddSingleton(serviceProvider => serviceProvider.GetRequiredService().Create()); + return services; + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/IDeserializer.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/IDeserializer.cs new file mode 100644 index 000000000..e5b00f495 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/IDeserializer.cs @@ -0,0 +1,11 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public interface IDeserializer +{ + TValue? Deserialize(string value); + + object? Deserialize(string value, Type valueType); +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/IDeserializerFactory.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/IDeserializerFactory.cs new file mode 100644 index 000000000..d65398ea5 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/IDeserializerFactory.cs @@ -0,0 +1,11 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public interface IDeserializerFactory +{ + IDeserializer Create(); + + IDeserializer Create(string name); +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/ISerializer.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/ISerializer.cs new file mode 100644 index 000000000..714df845f --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/ISerializer.cs @@ -0,0 +1,9 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public interface ISerializer +{ + string Serialize(TValue value); +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/ISerializerFactory.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/ISerializerFactory.cs new file mode 100644 index 000000000..41049b907 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/ISerializerFactory.cs @@ -0,0 +1,11 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public interface ISerializerFactory +{ + public ISerializer Create(); + + ISerializer Create(string name); +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Json/IJsonDeserializer.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Json/IJsonDeserializer.cs new file mode 100644 index 000000000..337ea764f --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Json/IJsonDeserializer.cs @@ -0,0 +1,9 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public interface IJsonDeserializer : IDeserializer +{ + +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Json/IJsonSerializer.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Json/IJsonSerializer.cs new file mode 100644 index 000000000..46ccd8299 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Json/IJsonSerializer.cs @@ -0,0 +1,8 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public interface IJsonSerializer : ISerializer +{ +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Yaml/IYamlDeserializer.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Yaml/IYamlDeserializer.cs new file mode 100644 index 000000000..7a53306ab --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Yaml/IYamlDeserializer.cs @@ -0,0 +1,9 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public interface IYamlDeserializer : IDeserializer +{ + +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Yaml/IYamlSerializer.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Yaml/IYamlSerializer.cs new file mode 100644 index 000000000..3c1621357 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Interfaces/Yaml/IYamlSerializer.cs @@ -0,0 +1,8 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public interface IYamlSerializer : ISerializer +{ +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/DeserializerFactoryOptions.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/DeserializerFactoryOptions.cs new file mode 100644 index 000000000..4e6bc8cd8 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/DeserializerFactoryOptions.cs @@ -0,0 +1,24 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public class DeserializerFactoryOptions : MasaFactoryOptions +{ + public DeserializerFactoryOptions MappingDeserializer(string name, Func func) + { + var builder = Options.FirstOrDefault(b => b.Name == name.ToLower()); + if (builder != null) builder.Func = func; + else Options.Add(new DeserializerRelationOptions(name.ToLower(), func)); + return this; + } + + public Func? GetDeserializer() + => GetDeserializer(Microsoft.Extensions.Options.Options.DefaultName); + + public Func? GetDeserializer(string name) + { + var deserializer = Options.FirstOrDefault(b => b.Name == name.ToLower()); + return deserializer?.Func; + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/DeserializerRelationOptions.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/DeserializerRelationOptions.cs new file mode 100644 index 000000000..bf4326743 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/DeserializerRelationOptions.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public class DeserializerRelationOptions : MasaRelationOptions +{ + public DeserializerRelationOptions(string name, Func func) + : base(name) + { + Func = func; + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/SerializerFactoryOptions.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/SerializerFactoryOptions.cs new file mode 100644 index 000000000..232d80745 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/SerializerFactoryOptions.cs @@ -0,0 +1,24 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public class SerializerFactoryOptions : MasaFactoryOptions +{ + public SerializerFactoryOptions MappingSerializer(string name, Func func) + { + var builder = Options.FirstOrDefault(b => b.Name == name.ToLower()); + if (builder != null) builder.Func = func; + else Options.Add(new SerializerRelationOptions(name.ToLower(), func)); + return this; + } + + public Func? GetSerializer() + => GetSerializer(Microsoft.Extensions.Options.Options.DefaultName); + + public Func? GetSerializer(string name) + { + var serializer = Options.FirstOrDefault(b => b.Name == name.ToLower()); + return serializer?.Func; + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/SerializerRelationOptions.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/SerializerRelationOptions.cs new file mode 100644 index 000000000..c7d148c72 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/Serialization/Options/SerializerRelationOptions.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public class SerializerRelationOptions : MasaRelationOptions +{ + public SerializerRelationOptions(string name, Func func) + : base(name) + { + Func = func; + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/DefaultTypeConvertFactory.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/DefaultTypeConvertFactory.cs new file mode 100644 index 000000000..400af5a1d --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/DefaultTypeConvertFactory.cs @@ -0,0 +1,39 @@ +// 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.Data; + +public class DefaultTypeConvertFactory : ITypeConvertFactory +{ + private readonly IServiceProvider _serviceProvider; + private readonly IOptions _typeConvertFactoryOptions; + private readonly TypeConvertRelationOptions? _defaultOptions; + + public DefaultTypeConvertFactory(IOptions typeConvertFactoryOptions, IServiceProvider serviceProvider) + { + _typeConvertFactoryOptions = typeConvertFactoryOptions; + _defaultOptions = _typeConvertFactoryOptions.Value.Options.FirstOrDefault(options + => options.Name == Options.DefaultName) ?? + _typeConvertFactoryOptions.Value.Options.FirstOrDefault(); + _serviceProvider = serviceProvider; + } + + public ITypeConvertProvider Create() + { + if (_defaultOptions == null) + throw new NotImplementedException("Default typeConvert not found, you need to add it"); + + return _defaultOptions.Func.Invoke(_serviceProvider); + } + + public ITypeConvertProvider Create(string name) + { + var typeConvertOptions = + _typeConvertFactoryOptions.Value.Options.FirstOrDefault(options + => options.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + if (typeConvertOptions == null) + throw new NotImplementedException($"No TypeConvert found for 【{name}】"); + + return typeConvertOptions.Func.Invoke(_serviceProvider); + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/DefaultTypeConvertProvider.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/DefaultTypeConvertProvider.cs new file mode 100644 index 000000000..eab8cc9bc --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/DefaultTypeConvertProvider.cs @@ -0,0 +1,50 @@ +// 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.Data; + +public class DefaultTypeConvertProvider : ITypeConvertProvider +{ + private readonly List _types = new() + { + typeof(Guid), + typeof(Guid?), + typeof(DateTime), + typeof(DateTime?) + }; + + private readonly List _notNeedSerializeTypes = new() + { + typeof(String), + typeof(Guid), + typeof(DateTime), + typeof(Decimal), + typeof(Guid?), + typeof(DateTime?), + typeof(Decimal?) + }; + + private readonly IDeserializer? _deserializer; + + public DefaultTypeConvertProvider(IDeserializer? deserializer = null) => _deserializer = deserializer; + + public T? ConvertTo(string value, IDeserializer? deserializer = null) + { + var result = ConvertTo(value, typeof(T), deserializer); + return result is T res ? res : default; + } + + public object? ConvertTo(string value, Type type, IDeserializer? deserializer = null) + { + if (_types.Contains(type)) + return TypeDescriptor.GetConverter(type).ConvertFromInvariantString(value)!; + + if (!IsSupportDeserialize(type)) + return Convert.ChangeType(value, type); + + return (deserializer ?? _deserializer)!.Deserialize(value, type); + } + + private bool IsSupportDeserialize(Type type) + => !type.IsPrimitive && !_notNeedSerializeTypes.Contains(type); +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Extensions/ServiceCollectionExtensions.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..f7f433a94 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,37 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Microsoft.Extensions.DependencyInjection; + +public static partial class ServiceCollectionExtensions +{ + public static IServiceCollection AddTypeConvert(this IServiceCollection services) + { + services + .AddTypeConvertCore() + .Configure(option => + { + option.TryMapping(serviceProvider => new DefaultTypeConvertProvider(serviceProvider.GetRequiredService().Create())); + }); + return services; + } + + public static IServiceCollection AddTypeConvert(this IServiceCollection services, string name) + { + services + .AddTypeConvertCore() + .Configure(option => + { + option.TryMapping(name, + serviceProvider => new DefaultTypeConvertProvider(serviceProvider.GetRequiredService().Create(name))); + }); + return services; + } + + private static IServiceCollection AddTypeConvertCore(this IServiceCollection services) + { + services.TryAddSingleton(); + services.TryAddSingleton(serviceProvider => serviceProvider.GetRequiredService().Create()); + return services; + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Interfaces/ITypeConvertFactory.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Interfaces/ITypeConvertFactory.cs new file mode 100644 index 000000000..04b0264fd --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Interfaces/ITypeConvertFactory.cs @@ -0,0 +1,11 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public interface ITypeConvertFactory +{ + ITypeConvertProvider Create(); + + ITypeConvertProvider Create(string name); +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Interfaces/ITypeConvertProvider.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Interfaces/ITypeConvertProvider.cs new file mode 100644 index 000000000..e7958b0d6 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Interfaces/ITypeConvertProvider.cs @@ -0,0 +1,11 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public interface ITypeConvertProvider +{ + T? ConvertTo(string value, IDeserializer? deserializer = null); + + object? ConvertTo(string value, Type type, IDeserializer? deserializer = null); +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Options/TypeConvertFactoryOptions.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Options/TypeConvertFactoryOptions.cs new file mode 100644 index 000000000..802093e45 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Options/TypeConvertFactoryOptions.cs @@ -0,0 +1,44 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data.TypeConverts; + +public class TypeConvertFactoryOptions : MasaFactoryOptions +{ + public TypeConvertFactoryOptions TryMapping(Func func) + => TryMapping(Microsoft.Extensions.Options.Options.DefaultName, func); + + public TypeConvertFactoryOptions TryMapping(string name, Func func) + { + if (Options.Any(opt => opt.Name == name.ToLower())) + return this; + + Options.Add(new TypeConvertRelationOptions(name.ToLower(), func)); + return this; + } + + public TypeConvertFactoryOptions Mapping(Func func) + => Mapping(Microsoft.Extensions.Options.Options.DefaultName, func); + + public TypeConvertFactoryOptions Mapping(string name, Func func) + { + var builder = Options.FirstOrDefault(opt => opt.Name == name.ToLower()); + if (builder != null) + { + builder.Func = func; + } + else + { + Options.Add(new TypeConvertRelationOptions(name.ToLower(), func)); + } + return this; + } + + public Func? GetTypeConvert() + => GetTypeConvert(Microsoft.Extensions.Options.Options.DefaultName); + + public Func? GetTypeConvert(string name) + { + return Options.FirstOrDefault(opt => opt.Name == name.ToLower())?.Func; + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Options/TypeConvertRelationOptions.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Options/TypeConvertRelationOptions.cs new file mode 100644 index 000000000..bd866b327 --- /dev/null +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/TypeConverts/Options/TypeConvertRelationOptions.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data.TypeConverts; + +public class TypeConvertRelationOptions : MasaRelationOptions +{ + public TypeConvertRelationOptions(string name, Func func) + : base(name) + { + Func = func; + } +} diff --git a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/_Imports.cs b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/_Imports.cs index 6b238536a..921c58357 100644 --- a/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/_Imports.cs +++ b/src/BuildingBlocks/Data/Masa.BuildingBlocks.Data/_Imports.cs @@ -3,6 +3,10 @@ global using Masa.BuildingBlocks.Data; global using Masa.BuildingBlocks.Data.Contracts; +global using Masa.BuildingBlocks.Data.TypeConverts; +global using Masa.Contrib.Data; global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.DependencyInjection.Extensions; global using Microsoft.Extensions.Options; +global using System.ComponentModel; global using System.Reflection; diff --git a/src/BuildingBlocks/Service/Masa.BuildingBlocks.Service.Caller/Options/CallerRelationOptions.cs b/src/BuildingBlocks/Service/Masa.BuildingBlocks.Service.Caller/Options/CallerRelationOptions.cs index 0e899a4a7..c9d83107f 100644 --- a/src/BuildingBlocks/Service/Masa.BuildingBlocks.Service.Caller/Options/CallerRelationOptions.cs +++ b/src/BuildingBlocks/Service/Masa.BuildingBlocks.Service.Caller/Options/CallerRelationOptions.cs @@ -5,9 +5,9 @@ namespace Masa.BuildingBlocks.Service.Caller.Options; public class CallerRelationOptions : MasaRelationOptions { - public CallerRelationOptions(string name, Func func) : base(name) + public CallerRelationOptions(string name, Func func) + : base(name) { - Name = name; Func = func; } } diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/BaseUserContext.cs b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/BaseUserContext.cs new file mode 100644 index 000000000..730316543 --- /dev/null +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/BaseUserContext.cs @@ -0,0 +1,29 @@ +// 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.Authentication.Identity; + +public class BaseUserContext : IUserContext +{ + private readonly IUserContext _userContext; + protected ITypeConvertProvider TypeConvertProvider { get; } + + public bool IsAuthenticated => _userContext.IsAuthenticated; + public string? UserId => _userContext.UserId; + public string? UserName => _userContext.UserName; + + public BaseUserContext(IServiceProvider serviceProvider) + { + _userContext = serviceProvider.GetRequiredService(); + TypeConvertProvider = serviceProvider.GetRequiredService(); + } + + public TUserId? GetUserId() => _userContext.GetUserId(); + + public IdentityUser? GetUser() => GetUser(); + + public TIdentityUser? GetUser() where TIdentityUser : IIdentityUser + => _userContext.GetUser(); + + public IEnumerable GetUserRoles() => _userContext.GetUserRoles(); +} diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultIsolatedUserContext.cs b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultIsolatedUserContext.cs index 167888959..98260831e 100644 --- a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultIsolatedUserContext.cs +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultIsolatedUserContext.cs @@ -1,24 +1,16 @@ -// Copyright (c) MASA Stack All rights reserved. +// 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.Authentication.Identity; -internal class DefaultIsolatedUserContext : DefaultUserContext, IIsolatedUserContext +public class DefaultIsolatedUserContext : BaseUserContext, IIsolatedUserContext { public string? TenantId => GetUser()?.TenantId; public string? Environment => GetUser()?.Environment; - private readonly IOptionsMonitor _optionsMonitor; - - public DefaultIsolatedUserContext( - ITypeConvertProvider typeConvertProvider, - ICurrentPrincipalAccessor currentPrincipalAccessor, - IOptionsMonitor optionsMonitor, - ILoggerFactory? loggerFactory = null) - : base(typeConvertProvider, currentPrincipalAccessor, optionsMonitor, loggerFactory) + public DefaultIsolatedUserContext(IServiceProvider serviceProvider) : base(serviceProvider) { - _optionsMonitor = optionsMonitor; } public TTenantId? GetTenantId() @@ -29,22 +21,4 @@ public DefaultIsolatedUserContext( return TypeConvertProvider.ConvertTo(tenantId); } - - protected override IsolatedIdentityUser? GetUser() - { - var identityUser = GetUserBasicInfo(); - if (identityUser == null) - { - return null; - } - - return new IsolatedIdentityUser - { - Id = identityUser.Id, - UserName = identityUser.UserName, - Roles = identityUser.Roles, - TenantId = ClaimsPrincipal?.FindClaimValue(_optionsMonitor.CurrentValue.TenantId), - Environment = ClaimsPrincipal?.FindClaimValue(_optionsMonitor.CurrentValue.Environment), - }; - } } diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultMultiEnvironmentUserContext.cs b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultMultiEnvironmentUserContext.cs index 1a1030c07..ad2606f5e 100644 --- a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultMultiEnvironmentUserContext.cs +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultMultiEnvironmentUserContext.cs @@ -1,38 +1,13 @@ -// Copyright (c) MASA Stack All rights reserved. +// 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.Authentication.Identity; -internal class DefaultMultiEnvironmentUserContext : DefaultUserContext, IMultiEnvironmentUserContext +public class DefaultMultiEnvironmentUserContext: BaseUserContext, IMultiEnvironmentUserContext { public string? Environment => GetUser()?.Environment; - private readonly IOptionsMonitor _optionsMonitor; - - public DefaultMultiEnvironmentUserContext( - ITypeConvertProvider typeConvertProvider, - ICurrentPrincipalAccessor currentPrincipalAccessor, - IOptionsMonitor optionsMonitor, - ILoggerFactory? loggerFactory = null) - : base(typeConvertProvider, currentPrincipalAccessor, optionsMonitor, loggerFactory) + public DefaultMultiEnvironmentUserContext(IServiceProvider serviceProvider) : base(serviceProvider) { - _optionsMonitor = optionsMonitor; - } - - protected override MultiEnvironmentIdentityUser? GetUser() - { - var identityUser = GetUserBasicInfo(); - if (identityUser == null) - { - return null; - } - - return new MultiEnvironmentIdentityUser - { - Id = identityUser.Id, - UserName = identityUser.UserName, - Roles = identityUser.Roles, - Environment = ClaimsPrincipal?.FindClaimValue(_optionsMonitor.CurrentValue.Environment), - }; } } diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultMultiTenantUserContext.cs b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultMultiTenantUserContext.cs index 9e78782e2..a10050fb7 100644 --- a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultMultiTenantUserContext.cs +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultMultiTenantUserContext.cs @@ -1,25 +1,15 @@ -// Copyright (c) MASA Stack All rights reserved. +// 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.Authentication.Identity; -internal class DefaultMultiTenantUserContext : DefaultUserContext, IMultiTenantUserContext +public class DefaultMultiTenantUserContext : BaseUserContext, IMultiTenantUserContext { public string? TenantId => GetUser()?.TenantId; - private readonly IOptionsMonitor _optionsMonitor; + public DefaultMultiTenantUserContext(IServiceProvider serviceProvider) : base(serviceProvider) { } - public DefaultMultiTenantUserContext( - ITypeConvertProvider typeConvertProvider, - ICurrentPrincipalAccessor currentPrincipalAccessor, - IOptionsMonitor optionsMonitor, - ILoggerFactory? loggerFactory = null) - : base(typeConvertProvider, currentPrincipalAccessor, optionsMonitor, loggerFactory) - { - _optionsMonitor = optionsMonitor; - } - - public virtual TTenantId? GetTenantId() + public TTenantId? GetTenantId() { var tenantId = TenantId; if (tenantId == null) @@ -27,21 +17,4 @@ public DefaultMultiTenantUserContext( return TypeConvertProvider.ConvertTo(tenantId); } - - protected override MultiTenantIdentityUser? GetUser() - { - var identityUser = GetUserBasicInfo(); - if (identityUser == null) - { - return null; - } - - return new MultiTenantIdentityUser - { - Id = identityUser.Id, - UserName = identityUser.UserName, - Roles = identityUser.Roles, - TenantId = ClaimsPrincipal?.FindClaimValue(_optionsMonitor.CurrentValue.TenantId), - }; - } } diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultUserContext.cs b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultUserContext.cs index ead7d42b9..fa615f89f 100644 --- a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultUserContext.cs +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/DefaultUserContext.cs @@ -6,51 +6,52 @@ namespace Masa.Contrib.Authentication.Identity; internal class DefaultUserContext : UserContext { private readonly IOptionsMonitor _optionsMonitor; - private readonly ILogger? _logger; + private static readonly MemoryCache ModelRelationCache = new(); - protected ClaimsPrincipal? ClaimsPrincipal { get; set; } + private ClaimsPrincipal? ClaimsPrincipal { get; set; } public DefaultUserContext( ITypeConvertProvider typeConvertProvider, ICurrentPrincipalAccessor currentPrincipalAccessor, - IOptionsMonitor optionsMonitor, ILoggerFactory? loggerFactory = null) + IOptionsMonitor optionsMonitor) : base(typeConvertProvider) { _optionsMonitor = optionsMonitor; + _optionsMonitor.CurrentValue.Initialize(); ClaimsPrincipal = currentPrincipalAccessor.GetCurrentPrincipal(); - _logger = loggerFactory?.CreateLogger(); } - protected override IdentityUser? GetUser() + protected override object? GetUser(Type userType) { - return GetUserBasicInfo(); - } - - protected override IdentityUser? GetUserBasicInfo() - { - - var userId = ClaimsPrincipal?.FindClaimValue(_optionsMonitor.CurrentValue.UserId); + var userClaimType = _optionsMonitor.CurrentValue.GetClaimType(nameof(_optionsMonitor.CurrentValue.UserId))!; + var userId = ClaimsPrincipal?.FindClaimValue(userClaimType); if (userId == null) return null; - var roleStr = ClaimsPrincipal?.FindClaimValue(_optionsMonitor.CurrentValue.Role); - var roles = Array.Empty(); - if (!string.IsNullOrWhiteSpace(roleStr)) + var modelRelation = ModelRelationCache.GetOrAdd(userType, (type) => { - try - { - roles = JsonSerializer.Deserialize(roleStr) ?? roles; - } - catch (Exception e) + var constructor = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public) + .FirstOrDefault(c => c.GetParameters().Length == 0) ?? + throw new InvalidOperationException($"[{type.Name}] has a parameterless constructor"); + return new CustomizeModelRelation( + InstanceBuilder.CreateInstanceDelegate(constructor), + InstanceBuilder.GetPropertyAndMethodInfoRelations(type)); + }); + var userModel = modelRelation.Func.Invoke(Array.Empty()); + foreach (var property in userType.GetProperties()) + { + var claimType = _optionsMonitor.CurrentValue.GetClaimType(property.Name); + if (claimType == null) + continue; + + var claimValue = ClaimsPrincipal?.FindClaimValue(claimType); + if (claimValue != null) { - _logger?.LogError("role data deserialization failed", e); + modelRelation.Setters[property] + .Invoke(userModel, new[] { TypeConvertProvider.ConvertTo(claimValue, property.PropertyType) }); } } - return new IdentityUser - { - Id = userId, - UserName = ClaimsPrincipal?.FindClaimValue(_optionsMonitor.CurrentValue.UserName), - Roles = roles - }; + + return userModel; } } diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/IdentityClaimOptions.cs b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/IdentityClaimOptions.cs index c47610133..f9712bec0 100644 --- a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/IdentityClaimOptions.cs +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/IdentityClaimOptions.cs @@ -5,22 +5,139 @@ namespace Masa.Contrib.Authentication.Identity; public class IdentityClaimOptions { - public string UserId { get; set; } + private readonly Dictionary _mapping = new(); + private MemoryCache Mappings { get; } = new(); - public string UserName { get; set; } + private string? _userId; - public string Role { get; set; } + public string? UserId + { + get => _userId ??= GetClaimType(nameof(UserId)); + set + { + if (value != null) + { + _userId = value; + Mapping(nameof(UserId), value); + } + } + } + + private string? _userName; + + public string? UserName + { + get => _userName ??= GetClaimType(nameof(UserName)); + set + { + if (value != null) + { + _userName = value; + Mapping(nameof(UserName), value); + } + } + } + + private string? _role; + + public string? Role + { + get => _role ??= GetClaimType(nameof(Role)); + set + { + if (value != null) + { + _role = value; + Mapping(nameof(Role), value); + } + } + } + + private string? _tenantId; + + public string? TenantId + { + get => _tenantId ??= GetClaimType(nameof(TenantId)); + set + { + if (value != null) + { + _tenantId = value; + Mapping(nameof(TenantId), value); + } + } + } - public string TenantId { get; set; } + private string? _environment; - public string Environment { get; set; } + public string? Environment + { + get => _environment ??= GetClaimType(nameof(Environment)); + set + { + if (value != null) + { + _environment = value; + Mapping(nameof(Environment), value); + } + } + } + + internal bool IsInitialize { get; set; } public IdentityClaimOptions() { - UserId = ClaimType.DEFAULT_USER_ID; - UserName = ClaimType.DEFAULT_USER_NAME; - Role = ClaimType.DEFAULT_USER_ROLE; - TenantId = ClaimType.DEFAULT_TENANT_ID; - Environment = ClaimType.DEFAULT_ENVIRONMENT; + _mapping.Add(nameof(IIdentityUser.Id), nameof(UserId)); + _mapping.Add(nameof(IIdentityUser.Roles), nameof(Role)); + } + + public IdentityClaimOptions Mapping(string name, string claimType) + { + ArgumentNullException.ThrowIfNull(name, nameof(name)); + + Mappings.AddOrUpdate(name.ToLower(), (k) => claimType); + return this; + } + + public void Initialize() + { + if (!IsInitialize) + { + Mappings.TryAdd(nameof(UserId).ToLower(), (k) => + { + _userId = ClaimType.DEFAULT_USER_ID; + return _userId; + }); + Mappings.TryAdd(nameof(UserName).ToLower(), (k) => + { + _userName = ClaimType.DEFAULT_USER_NAME; + return _userName; + }); + Mappings.TryAdd(nameof(Role).ToLower(), (k) => + { + _role = ClaimType.DEFAULT_USER_ROLE; + return _role; + }); + Mappings.TryAdd(nameof(TenantId).ToLower(), (k) => + { + _tenantId = ClaimType.DEFAULT_TENANT_ID; + return _tenantId; + }); + Mappings.TryAdd(nameof(Environment).ToLower(), (k) => + { + _environment = ClaimType.DEFAULT_ENVIRONMENT; + return _environment; + }); + IsInitialize = true; + } + } + + public string? GetClaimType(string name) + { + if (_mapping.ContainsKey(name)) + name = _mapping[name]; + + Mappings.TryGet(name.ToLower(), out string? value); + return value; } } diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/Internal/CustomizeModelRelation.cs b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/Internal/CustomizeModelRelation.cs new file mode 100644 index 000000000..1ae2564de --- /dev/null +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/Internal/CustomizeModelRelation.cs @@ -0,0 +1,20 @@ +// 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.Authentication.Identity.Internal; + +internal class CustomizeModelRelation +{ + /// + /// For creating custom user models + /// + public Func Func { get; set; } + + public Dictionary Setters { get; set; } + + public CustomizeModelRelation(Func func, Dictionary setter) + { + Func = func; + Setters = setter; + } +} diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/Internal/InstanceBuilder.cs b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/Internal/InstanceBuilder.cs new file mode 100644 index 000000000..c1e37a394 --- /dev/null +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/Internal/InstanceBuilder.cs @@ -0,0 +1,32 @@ +// 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.Authentication.Identity.Internal; + +internal static class InstanceBuilder +{ + private static readonly Expression[] UnaryExpressions = Array.Empty(); + + public static Func CreateInstanceDelegate(ConstructorInfo constructorInfo) + { + var parameterParameterExpression = Expression.Parameter(typeof(object[]), "parameters"); + + return Expression.Lambda> + ( + Expression.New(constructorInfo, UnaryExpressions), + parameterParameterExpression + ).Compile(); + } + + public static Dictionary GetPropertyAndMethodInfoRelations(Type type) + { + var properties = type.GetProperties(); + var propertyDict = new Dictionary(properties.Length); + foreach (var property in properties) + { + var setMethod = property.GetSetMethod(property.PropertyType.IsNotPublic); + if (setMethod != null) propertyDict.Add(property, setMethod); + } + return propertyDict; + } +} diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/Masa.Contrib.Authentication.Identity.csproj b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/Masa.Contrib.Authentication.Identity.csproj index b5c7ceab2..122d5930a 100644 --- a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/Masa.Contrib.Authentication.Identity.csproj +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/Masa.Contrib.Authentication.Identity.csproj @@ -12,7 +12,10 @@ + + + diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/README.zh-CN.md b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/README.zh-CN.md index b55737b77..e1bc786c2 100644 --- a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/README.zh-CN.md +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/README.zh-CN.md @@ -46,4 +46,4 @@ using (userSetter.Change(user)) { //获取到的用户信息为Tom } -``` \ No newline at end of file +``` diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/ServiceCollectionExtensions.cs b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/ServiceCollectionExtensions.cs index 28e782e81..b4971bbe2 100644 --- a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/ServiceCollectionExtensions.cs +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/ServiceCollectionExtensions.cs @@ -6,15 +6,20 @@ namespace Microsoft.Extensions.DependencyInjection; public static class ServiceCollectionExtensions { public static IServiceCollection AddMasaIdentityModel( - this IServiceCollection services, - IdentityType identityType = IdentityType.Basic) - => services.AddMasaIdentityModel(identityType, _ => + this IServiceCollection services) + => services.AddMasaIdentityModel(_ => { + }); public static IServiceCollection AddMasaIdentityModel( this IServiceCollection services, - IdentityType identityType, + Action configureOptions) + => services.AddMasaIdentityModel(DataType.Json.ToString(), configureOptions); + + public static IServiceCollection AddMasaIdentityModel( + this IServiceCollection services, + string name, Action configureOptions) { ArgumentNullException.ThrowIfNull(configureOptions); @@ -23,78 +28,33 @@ public static IServiceCollection AddMasaIdentityModel( return services; services.AddSingleton(); - services.TryAddSingleton(); + + services.AddJson(); + services.AddTypeConvert(DataType.Json.ToString()); services.AddHttpContextAccessor(); services.TryAddSingleton(); services.Configure(configureOptions); - if (identityType.HasFlag(IdentityType.MultiTenant) && identityType.HasFlag(IdentityType.MultiEnvironment)) - return services.AddMasaIdentityByIsolation(); - - if (identityType.HasFlag(IdentityType.MultiTenant)) - return services.AddMasaIdentityByMultiTenant(); - - if (identityType.HasFlag(IdentityType.MultiEnvironment)) - return services.AddMasaIdentityByMultiEnvironment(); - - if ((identityType & IdentityType.Basic) != 0) - return services.AddMasaIdentityByBasic(); - - throw new NotSupportedException(nameof(identityType)); - } - - private static IServiceCollection AddMasaIdentityByBasic(this IServiceCollection services) - { - services.TryAddScoped(); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - return services; - } - - private static IServiceCollection AddMasaIdentityByMultiTenant(this IServiceCollection services) - { - services.TryAddScoped(); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - return services; - } - - private static IServiceCollection AddMasaIdentityByMultiEnvironment(this IServiceCollection services) - { - services.TryAddScoped(); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - return services; + return services.AddMasaIdentityModelCore(name); } - private static IServiceCollection AddMasaIdentityByIsolation(this IServiceCollection services) + private static IServiceCollection AddMasaIdentityModelCore(this IServiceCollection services, string name) { - services.TryAddScoped(); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); - services.TryAddScoped(serviceProvider - => serviceProvider.GetRequiredService()); + services.TryAddScoped(serviceProvider => new DefaultUserContext( + serviceProvider.GetRequiredService().Create(name), + serviceProvider.GetRequiredService(), + serviceProvider.GetRequiredService>())); + + services.TryAddScoped(serviceProvider => serviceProvider.GetService()!); + services.TryAddScoped(serviceProvider => serviceProvider.GetService()!); + services.TryAddScoped(); + services.TryAddScoped(); + services.TryAddScoped(); return services; } - private class IdentityProvider + private sealed class IdentityProvider { } } diff --git a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/_Imports.cs b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/_Imports.cs index 83f8ab964..2c63df9d8 100644 --- a/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/_Imports.cs +++ b/src/Contrib/Authentication/Masa.Contrib.Authentication.Identity/_Imports.cs @@ -2,11 +2,16 @@ // Licensed under the MIT License. See LICENSE.txt in the project root for license information. global using Masa.BuildingBlocks.Authentication.Identity; +global using Masa.BuildingBlocks.Data; global using Masa.Contrib.Authentication.Identity; global using Masa.Contrib.Authentication.Identity.Const; +global using Masa.Contrib.Authentication.Identity.Internal; +global using Masa.Utils.Caching.Memory; global using Microsoft.AspNetCore.Http; +global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyInjection.Extensions; -global using Microsoft.Extensions.Logging; global using Microsoft.Extensions.Options; +global using System.Linq.Expressions; +global using System.Reflection; global using System.Security.Claims; -global using System.Text.Json; +global using IdentityUser = Masa.BuildingBlocks.Authentication.Identity.IdentityUser; diff --git a/src/Contrib/Authentication/Tests/Masa.Contrib.Authentication.Identity.Tests/CustomerUser.cs b/src/Contrib/Authentication/Tests/Masa.Contrib.Authentication.Identity.Tests/CustomerUser.cs new file mode 100644 index 000000000..18dea9af0 --- /dev/null +++ b/src/Contrib/Authentication/Tests/Masa.Contrib.Authentication.Identity.Tests/CustomerUser.cs @@ -0,0 +1,15 @@ +// 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.Authentication.Identity.Tests; + +public class CustomerUser : IIdentityUser +{ + public string Id { get; set; } + + public string? UserName { get; set; } + + public string? TrueName { get; set; } + + public string[] Roles { get; set; } +} diff --git a/src/Contrib/Authentication/Tests/Masa.Contrib.Authentication.Identity.Tests/CustomerUser2.cs b/src/Contrib/Authentication/Tests/Masa.Contrib.Authentication.Identity.Tests/CustomerUser2.cs new file mode 100644 index 000000000..9a1c619d6 --- /dev/null +++ b/src/Contrib/Authentication/Tests/Masa.Contrib.Authentication.Identity.Tests/CustomerUser2.cs @@ -0,0 +1,23 @@ +// 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.Authentication.Identity.Tests; + +public class CustomerUser2 : IIdentityUser +{ + public string Id { get; set; } + + public string? UserName { get; set; } + + public string? TrueName { get; set; } + + public string[] Roles { get; set; } + + public CustomerUser2(string id, string? userName, string? trueName, string[] roles) + { + Id = id; + UserName = userName; + TrueName = trueName; + Roles = roles; + } +} diff --git a/src/Contrib/Authentication/Tests/Masa.Contrib.Authentication.Identity.Tests/TestIdentity.cs b/src/Contrib/Authentication/Tests/Masa.Contrib.Authentication.Identity.Tests/TestIdentity.cs index c996c1d03..46d2dffd2 100644 --- a/src/Contrib/Authentication/Tests/Masa.Contrib.Authentication.Identity.Tests/TestIdentity.cs +++ b/src/Contrib/Authentication/Tests/Masa.Contrib.Authentication.Identity.Tests/TestIdentity.cs @@ -10,58 +10,22 @@ public class TestIdentity public void TestIdentityClaimOptionsReturnTenantIdEqualTenantId() { var services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.Basic | IdentityType.MultiTenant | IdentityType.MultiEnvironment, identityClaimOptions => + services.AddMasaIdentityModel(identityClaimOptions => { identityClaimOptions.TenantId = "TenantId"; }); var serviceProvider = services.BuildServiceProvider(); var optionsMonitor = serviceProvider.GetRequiredService>(); Assert.IsTrue(optionsMonitor.CurrentValue.TenantId == "TenantId"); - Assert.IsTrue(optionsMonitor.CurrentValue.Environment == ClaimType.DEFAULT_ENVIRONMENT); } [TestMethod] - public void TestIdentityType() + public void TestIdentityModelReturnIsNotNull() { var services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.Basic); + services.AddMasaIdentityModel(); var serviceProvider = services.BuildServiceProvider(); - Assert.IsNull(serviceProvider.GetService()); - Assert.IsNull(serviceProvider.GetService()); - - services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.MultiTenant); - serviceProvider = services.BuildServiceProvider(); - Assert.IsNotNull(serviceProvider.GetService()); - Assert.IsNull(serviceProvider.GetService()); - - services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.Basic | IdentityType.MultiTenant); - serviceProvider = services.BuildServiceProvider(); - Assert.IsNotNull(serviceProvider.GetService()); - Assert.IsNull(serviceProvider.GetService()); - - services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.MultiEnvironment); - serviceProvider = services.BuildServiceProvider(); - Assert.IsNull(serviceProvider.GetService()); - Assert.IsNotNull(serviceProvider.GetService()); - - services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.Basic | IdentityType.MultiEnvironment); - serviceProvider = services.BuildServiceProvider(); - Assert.IsNull(serviceProvider.GetService()); - Assert.IsNotNull(serviceProvider.GetService()); - - services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.MultiTenant | IdentityType.MultiEnvironment); - serviceProvider = services.BuildServiceProvider(); - Assert.IsNotNull(serviceProvider.GetService()); - Assert.IsNotNull(serviceProvider.GetService()); - - services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.Basic | IdentityType.MultiTenant | IdentityType.MultiEnvironment); - serviceProvider = services.BuildServiceProvider(); + Assert.IsNotNull(serviceProvider.GetService()); Assert.IsNotNull(serviceProvider.GetService()); Assert.IsNotNull(serviceProvider.GetService()); Assert.IsNotNull(serviceProvider.GetService()); @@ -74,6 +38,7 @@ public void TestDefaultIdentityReturnTenantIdEqualtenantid() services.AddMasaIdentityModel(); var serviceProvider = services.BuildServiceProvider(); var optionsMonitor = serviceProvider.GetRequiredService>(); + optionsMonitor.CurrentValue.Initialize(); Assert.IsTrue(optionsMonitor.CurrentValue.TenantId == ClaimType.DEFAULT_TENANT_ID); Assert.IsTrue(optionsMonitor.CurrentValue.Environment == ClaimType.DEFAULT_ENVIRONMENT); } @@ -82,7 +47,7 @@ public void TestDefaultIdentityReturnTenantIdEqualtenantid() public void TestAddIsolationIdentityReturnUserIdEqual1AndTenantIdEqual1() { var services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.Basic | IdentityType.MultiTenant | IdentityType.MultiEnvironment); + services.AddMasaIdentityModel(); var serviceProvider = services.BuildServiceProvider(); var httpContextAccessor = serviceProvider.GetRequiredService(); httpContextAccessor.HttpContext = new DefaultHttpContext() @@ -118,6 +83,7 @@ public void TestAddIsolationIdentityReturnUserIdEqual1AndTenantIdEqual1() Assert.IsTrue(isolationUserContext.IsAuthenticated); Assert.IsTrue(isolationUserContext.UserId == "1"); + Assert.IsTrue(isolationUserContext.GetUserId() == 1); Assert.IsTrue(isolationUserContext.UserName == "Jim"); Assert.IsTrue(isolationUserContext.TenantId == "1"); Assert.IsTrue(isolationUserContext.Environment == "dev"); @@ -139,7 +105,7 @@ public void TestAddSimpleIdentityReturnUserIdEqual1() new(ClaimType.DEFAULT_USER_ID, "1"), new(ClaimType.DEFAULT_USER_NAME, "Jim"), new(ClaimType.DEFAULT_TENANT_ID, "1"), - new(ClaimType.DEFAULT_USER_ROLE, "[\"roleId\"]") + new(ClaimType.DEFAULT_USER_ROLE, "[\"1\"]") }) }) }; @@ -149,22 +115,32 @@ public void TestAddSimpleIdentityReturnUserIdEqual1() Assert.IsTrue(userContext.UserId == "1"); Assert.IsTrue(userContext.UserName == "Jim"); Assert.IsTrue(userContext.GetUserRoles().Count() == 1); + var simpleUser = userContext.GetUser(); + Assert.IsNotNull(simpleUser); + Assert.IsTrue(simpleUser.Id == "1"); + Assert.IsTrue(simpleUser.UserName == "Jim"); + Assert.IsTrue(System.Text.Json.JsonSerializer.Serialize(simpleUser.Roles) == "[\"1\"]"); var multiTenantUserContext = serviceProvider.GetService(); - Assert.IsNull(multiTenantUserContext); + Assert.IsNotNull(multiTenantUserContext); var multiEnvironmentUserContext = serviceProvider.GetService(); - Assert.IsNull(multiEnvironmentUserContext); + Assert.IsNotNull(multiEnvironmentUserContext); var isolationUserContext = serviceProvider.GetService(); - Assert.IsNull(isolationUserContext); + Assert.IsNotNull(isolationUserContext); + + var user = isolationUserContext.GetUser(); + Assert.IsNotNull(user); + Assert.AreEqual("1", user.Id); + Assert.AreEqual("Jim", user.UserName); } [TestMethod] public void TestAddMultiTenantIdentityReturnTenantIdIs1() { var services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.MultiTenant); + services.AddMasaIdentityModel(); var serviceProvider = services.BuildServiceProvider(); var httpContextAccessor = serviceProvider.GetRequiredService(); httpContextAccessor.HttpContext = new DefaultHttpContext() @@ -176,7 +152,7 @@ public void TestAddMultiTenantIdentityReturnTenantIdIs1() new(ClaimType.DEFAULT_USER_ID, "1"), new(ClaimType.DEFAULT_USER_NAME, "Jim"), new(ClaimType.DEFAULT_TENANT_ID, "1"), - new(ClaimType.DEFAULT_USER_ROLE, "[\"1\"]") + new(ClaimType.DEFAULT_USER_ROLE, "[\"1\",\"2\"]") }) }) }; @@ -185,17 +161,28 @@ public void TestAddMultiTenantIdentityReturnTenantIdIs1() Assert.IsTrue(userContext.IsAuthenticated); Assert.IsTrue(userContext.UserId == "1"); Assert.IsTrue(userContext.UserName == "Jim"); - Assert.IsTrue(userContext.GetUserRoles().Count() > 0); + Assert.IsTrue(userContext.GetUserRoles().Any()); var multiTenantUserContext = serviceProvider.GetService(); Assert.IsNotNull(multiTenantUserContext); Assert.IsTrue(multiTenantUserContext.TenantId == "1"); + Assert.AreEqual(1, multiTenantUserContext.GetTenantId()); var multiEnvironmentUserContext = serviceProvider.GetService(); - Assert.IsNull(multiEnvironmentUserContext); + Assert.IsNotNull(multiEnvironmentUserContext); var isolationUserContext = serviceProvider.GetService(); - Assert.IsNull(isolationUserContext); + Assert.IsNotNull(isolationUserContext); + + Assert.AreEqual("1", isolationUserContext.TenantId); + Assert.AreEqual(1, isolationUserContext.GetTenantId()); + Assert.AreEqual(null, isolationUserContext.Environment); + + var simpleUser = userContext.GetUser(); + Assert.IsNotNull(simpleUser); + Assert.AreEqual("1", simpleUser.Id); + Assert.AreEqual("Jim", simpleUser.UserName); + Assert.AreEqual("[\"1\",\"2\"]", System.Text.Json.JsonSerializer.Serialize(simpleUser.Roles)); } [TestMethod] @@ -234,5 +221,121 @@ public void TestTemporarilyUserReturnUserIdEqual1() Assert.IsTrue(userContext.IsAuthenticated); Assert.IsTrue(userContext.UserId == "1"); Assert.IsTrue(userContext.UserName == "Jim"); + + var multiTenantUserContext = serviceProvider.GetService(); + Assert.IsNotNull(multiTenantUserContext); + Assert.AreEqual(null, multiTenantUserContext.TenantId); + Assert.AreEqual(null, multiTenantUserContext.GetTenantId()); + + var isolationUserContext = serviceProvider.GetService(); + Assert.IsNotNull(isolationUserContext); + + Assert.AreEqual(null, isolationUserContext.TenantId); + Assert.AreEqual(null, isolationUserContext.GetTenantId()); + } + + [TestMethod] + public void TestCustomerUserModelReturnTrueNameEqualLisi() + { + var services = new ServiceCollection(); + services.AddMasaIdentityModel(); + services.Configure(option => + { + option.Mapping(nameof(CustomerUser.TrueName), "realname"); + }); + var serviceProvider = services.BuildServiceProvider(); + var httpContextAccessor = serviceProvider.GetRequiredService(); + httpContextAccessor.HttpContext = new DefaultHttpContext() + { + User = new ClaimsPrincipal(new List() + { + new(new List() + { + new(ClaimType.DEFAULT_USER_ID, "1"), + new(ClaimType.DEFAULT_USER_NAME, "Jim"), + new("realname", "lisi") + }) + }) + }; + var userContext = serviceProvider.GetRequiredService(); + var user = userContext.GetUser(); + Assert.IsTrue(user is { TrueName: "lisi" }); + } + + [TestMethod] + public void TestCustomerUserModel2ReturnTrueNameEqualLisi() + { + var services = new ServiceCollection(); + services.AddMasaIdentityModel(option => + { + option.Mapping(nameof(CustomerUser.TrueName), "realname"); + }); + var serviceProvider = services.BuildServiceProvider(); + var httpContextAccessor = serviceProvider.GetRequiredService(); + httpContextAccessor.HttpContext = new DefaultHttpContext() + { + User = new ClaimsPrincipal(new List() + { + new(new List() + { + new(ClaimType.DEFAULT_USER_ID, "1"), + new(ClaimType.DEFAULT_USER_NAME, "Jim"), + new("realname", "lisi") + }) + }) + }; + var userContext = serviceProvider.GetRequiredService(); + var user = userContext.GetUser(); + Assert.IsTrue(user is { TrueName: "lisi" }); + } + + [TestMethod] + public void TestCustomerUserModel3ReturnTrueNameEqualLisi() + { + var services = new ServiceCollection(); + services.AddMasaIdentityModel(option => + { + option.Mapping(nameof(CustomerUser2.TrueName), "realname"); + }); + var serviceProvider = services.BuildServiceProvider(); + var httpContextAccessor = serviceProvider.GetRequiredService(); + httpContextAccessor.HttpContext = new DefaultHttpContext() + { + User = new ClaimsPrincipal(new List() + { + new(new List() + { + new(ClaimType.DEFAULT_USER_ID, "1"), + new(ClaimType.DEFAULT_USER_NAME, "Jim"), + new("realname", "lisi") + }) + }) + }; + var userContext = serviceProvider.GetRequiredService(); + Assert.ThrowsException(() => userContext.GetUser()); + } + + [TestMethod] + public void TestIdentityClaimOptions() + { + var services = new ServiceCollection(); + services.AddMasaIdentityModel(option => + { + option.UserId = "sub"; + option.UserName = "name"; + option.Role = "role"; + option.TenantId = "tenantid"; + option.Environment = "env"; + option.Mapping("age", "https://masastack.com/security/identity/claims/age"); + }); + + var serviceProvider = services.BuildServiceProvider(); + var identityClaimOptions = serviceProvider.GetRequiredService>(); + Assert.AreEqual("sub", identityClaimOptions.Value.UserId); + Assert.AreEqual("name", identityClaimOptions.Value.UserName); + Assert.AreEqual("role", identityClaimOptions.Value.Role); + Assert.AreEqual("tenantid", identityClaimOptions.Value.TenantId); + Assert.AreEqual("env", identityClaimOptions.Value.Environment); + Assert.AreEqual("https://masastack.com/security/identity/claims/age", identityClaimOptions.Value.GetClaimType("Age")); } } diff --git a/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/DefaultJsonDeserializer.cs b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/DefaultJsonDeserializer.cs new file mode 100644 index 000000000..0d1c151cf --- /dev/null +++ b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/DefaultJsonDeserializer.cs @@ -0,0 +1,17 @@ +// 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.Data.Serialization.Json; + +public class DefaultJsonDeserializer : IJsonDeserializer +{ + private readonly IOptions? _options; + + public DefaultJsonDeserializer(IOptions? options = null) => _options = options; + + public TValue? Deserialize(string value) + => JsonSerializer.Deserialize(value, _options?.Value); + + public object? Deserialize(string value, Type valueType) + => JsonSerializer.Deserialize(value, valueType, _options?.Value); +} diff --git a/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/DefaultJsonSerializer.cs b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/DefaultJsonSerializer.cs new file mode 100644 index 000000000..10e87fc50 --- /dev/null +++ b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/DefaultJsonSerializer.cs @@ -0,0 +1,13 @@ +// 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.Data.Serialization.Json; + +public class DefaultJsonSerializer : IJsonSerializer +{ + private readonly IOptions? _options; + + public DefaultJsonSerializer(IOptions? options = null) => _options = options; + + public string Serialize(TValue value) => JsonSerializer.Serialize(value, _options?.Value); +} diff --git a/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/Masa.Contrib.Data.Serialization.Json.csproj b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/Masa.Contrib.Data.Serialization.Json.csproj new file mode 100644 index 000000000..ce9a201a2 --- /dev/null +++ b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/Masa.Contrib.Data.Serialization.Json.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/ServiceCollectionExtensions.cs b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..0d3f88eb7 --- /dev/null +++ b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/ServiceCollectionExtensions.cs @@ -0,0 +1,37 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddJson(this IServiceCollection services) + { + if (services.Any(service => service.ImplementationType == typeof(JsonProvider))) + return services; + + services.AddSingleton(); + + services.AddSerializationCore(); + services.TryAddSingleton(); + services.TryAddSingleton(); + string name = DataType.Json.ToString(); + services.Configure(options => + { + options + .MappingSerializer(name, + serviceProvider => serviceProvider.GetRequiredService()); + }); + services.Configure(options => + { + options + .MappingDeserializer(name, + serviceProvider => serviceProvider.GetRequiredService()); + }); + return services; + } + + private sealed class JsonProvider + { + } +} diff --git a/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/_Imports.cs b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/_Imports.cs new file mode 100644 index 000000000..7f6e97c50 --- /dev/null +++ b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Json/_Imports.cs @@ -0,0 +1,8 @@ +// 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.Data.Serialization.Json; +global using Microsoft.Extensions.DependencyInjection.Extensions; +global using Microsoft.Extensions.Options; +global using System.Text.Json; diff --git a/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/DefaultYamlDeserializer.cs b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/DefaultYamlDeserializer.cs new file mode 100644 index 000000000..6159383cb --- /dev/null +++ b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/DefaultYamlDeserializer.cs @@ -0,0 +1,17 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public class DefaultYamlDeserializer : IYamlDeserializer +{ + private readonly YamlDotNet.Serialization.IDeserializer _deserializer; + + public DefaultYamlDeserializer(YamlDotNet.Serialization.IDeserializer deserializer) => _deserializer = deserializer; + + public TValue? Deserialize(string value) + => _deserializer.Deserialize(value); + + public object? Deserialize(string value, Type valueType) + => _deserializer.Deserialize(value, valueType); +} diff --git a/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/DefaultYamlSerializer.cs b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/DefaultYamlSerializer.cs new file mode 100644 index 000000000..aa5800a17 --- /dev/null +++ b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/DefaultYamlSerializer.cs @@ -0,0 +1,13 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.BuildingBlocks.Data; + +public class DefaultYamlSerializer : IYamlSerializer +{ + private readonly YamlDotNet.Serialization.ISerializer _serializer; + + public DefaultYamlSerializer(YamlDotNet.Serialization.ISerializer serializer) => _serializer = serializer; + + public string Serialize(TValue value) => value == null ? string.Empty : _serializer.Serialize(value); +} diff --git a/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/Masa.Contrib.Data.Serialization.Yaml.csproj b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/Masa.Contrib.Data.Serialization.Yaml.csproj new file mode 100644 index 000000000..32f3a2e21 --- /dev/null +++ b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/Masa.Contrib.Data.Serialization.Yaml.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/ServiceCollectionExtensions.cs b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..7b646fe9a --- /dev/null +++ b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/ServiceCollectionExtensions.cs @@ -0,0 +1,71 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddYaml(this IServiceCollection services) + => services.AddYaml( + () => new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build(), + () => new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build()); + + public static IServiceCollection AddYaml(this IServiceCollection services, + Action serializerAction, + Action deserializerAction) + { + return services.AddYaml(() => + { + var serializerBuilder = new SerializerBuilder(); + serializerAction.Invoke(serializerBuilder); + return serializerBuilder.Build(); + }, () => + { + var deserializerBuilder = new DeserializerBuilder(); + deserializerAction.Invoke(deserializerBuilder); + return deserializerBuilder.Build(); + }); + } + + public static IServiceCollection AddYaml(this IServiceCollection services, + Func serializerFunc, + Func deserializerFunc) + { + if (services.Any(service => service.ImplementationType == typeof(YamlProvider))) + return services; + + services.AddSingleton(); + + services.AddSerializationCore(); + + string name = DataType.Yml.ToString(); + services + .AddYamlCore(serializerFunc.Invoke(), deserializerFunc.Invoke()) + .Configure(options => + { + options + .MappingSerializer(name, + serviceProvider => serviceProvider.GetRequiredService()); + }) + .Configure(options => + { + options + .MappingDeserializer(name, + serviceProvider => serviceProvider.GetRequiredService()); + }); + return services; + } + + private static IServiceCollection AddYamlCore(this IServiceCollection services, + YamlDotNet.Serialization.ISerializer serializer, + YamlDotNet.Serialization.IDeserializer deserializer) + { + services.TryAddSingleton(_ => new DefaultYamlSerializer(serializer)); + services.TryAddSingleton(_ => new DefaultYamlDeserializer(deserializer)); + return services; + } + + private sealed class YamlProvider + { + } +} diff --git a/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/_Imports.cs b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/_Imports.cs new file mode 100644 index 000000000..c0db6cb8b --- /dev/null +++ b/src/Contrib/Data/Serialization/Masa.Contrib.Data.Serialization.Yaml/_Imports.cs @@ -0,0 +1,7 @@ +// 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 Microsoft.Extensions.DependencyInjection.Extensions; +global using YamlDotNet.Serialization; +global using YamlDotNet.Serialization.NamingConventions; diff --git a/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/JsonTest.cs b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/JsonTest.cs new file mode 100644 index 000000000..e36ad21f5 --- /dev/null +++ b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/JsonTest.cs @@ -0,0 +1,73 @@ +// 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.Data.Serialization.Json.Tests; + +[TestClass] +public class JsonTest +{ + [TestMethod] + public void TestSerialize() + { + var user = new User(1, "John"); + var json = new DefaultJsonSerializer().Serialize(user); + Assert.AreEqual("{\"Id\":1,\"Name\":\"John\"}", json); + } + + [TestMethod] + public void TestDeserialize() + { + var json = "{\"Id\":1,\"Name\":\"John\"}"; + var user = new DefaultJsonDeserializer().Deserialize(json); + Assert.IsNotNull(user); + Assert.AreEqual(1, user.Id); + Assert.AreEqual("John", user.Name); + } + + [TestMethod] + public void TestAddJsonReturnNotNull() + { + var services = new ServiceCollection(); + services.AddJson(); + var serviceProvider = services.BuildServiceProvider(); + Assert.IsNotNull(serviceProvider.GetService()); + Assert.IsNotNull(serviceProvider.GetService()); + + var serializer = serviceProvider.GetService(); + Assert.IsNotNull(serializer); + Assert.IsTrue(serializer.GetType() == typeof(DefaultJsonSerializer)); + + var deserializer = serviceProvider.GetService(); + Assert.IsNotNull(deserializer); + Assert.IsTrue(deserializer.GetType() == typeof(DefaultJsonDeserializer)); + } + + [TestMethod] + public void TestAddJsonByUseMasaAppReturnNotNull() + { + var services = new ServiceCollection(); + MasaApp.Services = services; + services.AddJson(); + MasaApp.Build(); + Assert.IsNotNull(MasaApp.GetService()); + Assert.IsNotNull(MasaApp.GetService()); + + var serializer = MasaApp.GetService(); + Assert.IsNotNull(serializer); + Assert.IsTrue(serializer.GetType() == typeof(DefaultJsonSerializer)); + + var deserializer = MasaApp.GetService(); + Assert.IsNotNull(deserializer); + Assert.IsTrue(deserializer.GetType() == typeof(DefaultJsonDeserializer)); + } + + [TestMethod] + public void TestAddMultiJsonReturnCountIs1() + { + var services = new ServiceCollection(); + services.AddJson().AddJson(); + var serviceProvider = services.BuildServiceProvider(); + Assert.IsTrue(serviceProvider.GetServices().Count() == 1); + Assert.IsTrue(serviceProvider.GetServices().Count() == 1); + } +} diff --git a/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/Masa.Contrib.Data.Serialization.Json.Tests.csproj b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/Masa.Contrib.Data.Serialization.Json.Tests.csproj new file mode 100644 index 000000000..b769a6ea2 --- /dev/null +++ b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/Masa.Contrib.Data.Serialization.Json.Tests.csproj @@ -0,0 +1,21 @@ + + + + net6.0 + enable + enable + false + + + + + + + + + + + + + + diff --git a/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/Model/User.cs b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/Model/User.cs new file mode 100644 index 000000000..e822a4f69 --- /dev/null +++ b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/Model/User.cs @@ -0,0 +1,17 @@ +// 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.Data.Serialization.Json.Tests.Model; + +public class User +{ + public int Id { get; set; } + + public string Name { get; set; } + + public User(int id, string name) + { + Id = id; + Name = name; + } +} diff --git a/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/_Imports.cs b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/_Imports.cs new file mode 100644 index 000000000..946e29d96 --- /dev/null +++ b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Json.Tests/_Imports.cs @@ -0,0 +1,7 @@ +// 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.Data.Serialization.Json.Tests.Model; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/Masa.Contrib.Data.Serialization.Yaml.Tests.csproj b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/Masa.Contrib.Data.Serialization.Yaml.Tests.csproj new file mode 100644 index 000000000..5915bd182 --- /dev/null +++ b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/Masa.Contrib.Data.Serialization.Yaml.Tests.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + + + + diff --git a/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/Model/User.cs b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/Model/User.cs new file mode 100644 index 000000000..3f590032d --- /dev/null +++ b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/Model/User.cs @@ -0,0 +1,22 @@ +// 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.Data.Serialization.Yaml.Tests.Model; + +public class User +{ + public decimal Age { get; set; } + + public string Name { get; set; } + + public User() + { + + } + + public User(decimal age, string name) + { + Age = age; + Name = name; + } +} diff --git a/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/YamlTest.cs b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/YamlTest.cs new file mode 100644 index 000000000..d335e001c --- /dev/null +++ b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/YamlTest.cs @@ -0,0 +1,97 @@ +// 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.Data.Serialization.Yaml.Tests; + +[TestClass] +public class YamlTest +{ + [TestMethod] + public void TestSerializeAndDeserialize() + { + var user = new User(1.5m, "John"); + var serializer = new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build(); + var yaml = new DefaultYamlSerializer(serializer).Serialize(user); + var deserializer = new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build(); + var deserializerUser = new DefaultYamlDeserializer(deserializer).Deserialize(yaml); + Assert.IsNotNull(deserializerUser); + Assert.IsTrue(user.Age == deserializerUser.Age && user.Name == deserializerUser.Name); + } + + [TestMethod] + public void TestSerializeAndValueIsNullReturnEmpty() + { + var serializer = new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build(); + object? user = null; + var yaml = new DefaultYamlSerializer(serializer).Serialize(user); + Assert.AreEqual(string.Empty, yaml); + } + + [TestMethod] + public void TestAddYamlReturnNotNull() + { + var services = new ServiceCollection(); + services.AddYaml(); + var serviceProvider = services.BuildServiceProvider(); + Assert.IsNotNull(serviceProvider.GetService()); + Assert.IsNotNull(serviceProvider.GetService()); + + var serializer = serviceProvider.GetService(); + Assert.IsNotNull(serializer); + Assert.IsTrue(serializer.GetType() == typeof(DefaultYamlSerializer)); + + var deserializer = serviceProvider.GetService(); + Assert.IsNotNull(deserializer); + Assert.IsTrue(deserializer.GetType() == typeof(DefaultYamlDeserializer)); + } + + [TestMethod] + public void TestAddYamlByUseMasaAppReturnNotNull() + { + var services = new ServiceCollection(); + MasaApp.Services = services; + services.AddYaml(); + MasaApp.Build(); + Assert.IsNotNull(MasaApp.GetService()); + Assert.IsNotNull(MasaApp.GetService()); + + var serializer = MasaApp.GetService(); + Assert.IsNotNull(serializer); + Assert.IsTrue(serializer.GetType() == typeof(DefaultYamlSerializer)); + + var deserializer = MasaApp.GetService(); + Assert.IsNotNull(deserializer); + Assert.IsTrue(deserializer.GetType() == typeof(DefaultYamlDeserializer)); + } + + [TestMethod] + public void TestAddYamlByUseMasaAppReturnNotNull2() + { + var services = new ServiceCollection(); + MasaApp.Services = services; + services.AddYaml( + serializer => serializer.WithNamingConvention(CamelCaseNamingConvention.Instance), + deserializer => deserializer.WithNamingConvention(CamelCaseNamingConvention.Instance)); + MasaApp.Build(); + Assert.IsNotNull(MasaApp.GetService()); + Assert.IsNotNull(MasaApp.GetService()); + + var serializer = MasaApp.GetService(); + Assert.IsNotNull(serializer); + Assert.IsTrue(serializer.GetType() == typeof(DefaultYamlSerializer)); + + var deserializer = MasaApp.GetService(); + Assert.IsNotNull(deserializer); + Assert.IsTrue(deserializer.GetType() == typeof(DefaultYamlDeserializer)); + } + + [TestMethod] + public void TestAddMultiYamlReturnCountIs1() + { + var services = new ServiceCollection(); + services.AddYaml().AddYaml(); + var serviceProvider = services.BuildServiceProvider(); + Assert.IsTrue(serviceProvider.GetServices().Count() == 1); + Assert.IsTrue(serviceProvider.GetServices().Count() == 1); + } +} diff --git a/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/_Imports.cs b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/_Imports.cs new file mode 100644 index 000000000..88a7f7459 --- /dev/null +++ b/src/Contrib/Data/Serialization/Tests/Masa.Contrib.Data.Serialization.Yaml.Tests/_Imports.cs @@ -0,0 +1,11 @@ +// 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.Data.Serialization.Yaml.Tests.Model; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using YamlDotNet.Serialization; +global using YamlDotNet.Serialization.NamingConventions; +global using IDeserializer = Masa.BuildingBlocks.Data.IDeserializer; +global using ISerializer = Masa.BuildingBlocks.Data.ISerializer; diff --git a/src/Contrib/StackSdks/Tests/Masa.Contrib.StackSdks.Auth.Tests/AuthClientTest.cs b/src/Contrib/StackSdks/Tests/Masa.Contrib.StackSdks.Auth.Tests/AuthClientTest.cs index 2b27fb6b0..8bb4fae4a 100644 --- a/src/Contrib/StackSdks/Tests/Masa.Contrib.StackSdks.Auth.Tests/AuthClientTest.cs +++ b/src/Contrib/StackSdks/Tests/Masa.Contrib.StackSdks.Auth.Tests/AuthClientTest.cs @@ -10,7 +10,7 @@ public class AuthClientTest public void TestAddAuthClient() { var services = new ServiceCollection(); - services.AddMasaIdentityModel(IdentityType.MultiEnvironment); + services.AddMasaIdentityModel(); services.AddAuthClient("https://localhost:18102"); var authClient = services.BuildServiceProvider().GetRequiredService(); diff --git a/src/Utils/Security/Masa.Utils.Security.Token/ServiceCollectionExtensions.cs b/src/Utils/Security/Masa.Utils.Security.Token/ServiceCollectionExtensions.cs index 972fb39f0..6e3482b11 100644 --- a/src/Utils/Security/Masa.Utils.Security.Token/ServiceCollectionExtensions.cs +++ b/src/Utils/Security/Masa.Utils.Security.Token/ServiceCollectionExtensions.cs @@ -9,7 +9,6 @@ public static IServiceCollection AddJwt(this IServiceCollection services, Action { services.Configure(options); services.TryAddScoped(); - new JwtUtils(services); return services; } }