diff --git a/Masa.Contrib.sln b/Masa.Contrib.sln
index 2cbb866f5..e6962af9e 100644
--- a/Masa.Contrib.sln
+++ b/Masa.Contrib.sln
@@ -312,6 +312,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Dispatcher.Int
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Identity.IdentityModel.Tests", "test\Masa.Contrib.Identity.IdentityModel.Tests\Masa.Contrib.Identity.IdentityModel.Tests.csproj", "{4E237346-F948-46AC-801B-492545978280}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.BasicAbility.Mc", "src\BasicAbility\Masa.Contrib.BasicAbility.Mc\Masa.Contrib.BasicAbility.Mc.csproj", "{75A25CF6-9BA4-46F5-8BC3-90396230CB64}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.BuildingBlocks.BasicAbility.Mc", "src\BuildingBlocks\MASA.BuildingBlocks\src\BasicAbility\Masa.BuildingBlocks.BasicAbility.Mc\Masa.BuildingBlocks.BasicAbility.Mc.csproj", "{DA816A33-F164-4456-92DD-A672BAD1A6B1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.BasicAbility.Mc.Tests", "test\Masa.Contrib.BasicAbility.Mc.Tests\Masa.Contrib.BasicAbility.Mc.Tests.csproj", "{23633E49-F11A-4D14-899A-E2599C8182CE}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1296,6 +1302,30 @@ Global
{4E237346-F948-46AC-801B-492545978280}.Release|Any CPU.Build.0 = Release|Any CPU
{4E237346-F948-46AC-801B-492545978280}.Release|x64.ActiveCfg = Release|Any CPU
{4E237346-F948-46AC-801B-492545978280}.Release|x64.Build.0 = Release|Any CPU
+ {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Debug|x64.Build.0 = Debug|Any CPU
+ {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Release|Any CPU.Build.0 = Release|Any CPU
+ {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Release|x64.ActiveCfg = Release|Any CPU
+ {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Release|x64.Build.0 = Release|Any CPU
+ {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Debug|x64.Build.0 = Debug|Any CPU
+ {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Release|x64.ActiveCfg = Release|Any CPU
+ {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Release|x64.Build.0 = Release|Any CPU
+ {23633E49-F11A-4D14-899A-E2599C8182CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {23633E49-F11A-4D14-899A-E2599C8182CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {23633E49-F11A-4D14-899A-E2599C8182CE}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {23633E49-F11A-4D14-899A-E2599C8182CE}.Debug|x64.Build.0 = Debug|Any CPU
+ {23633E49-F11A-4D14-899A-E2599C8182CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {23633E49-F11A-4D14-899A-E2599C8182CE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {23633E49-F11A-4D14-899A-E2599C8182CE}.Release|x64.ActiveCfg = Release|Any CPU
+ {23633E49-F11A-4D14-899A-E2599C8182CE}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1451,6 +1481,9 @@ Global
{7C4B88FA-3681-4C29-BC3F-0FDB111C5681} = {FBD326D3-E59C-433E-A88E-14E179E3093D}
{592297DE-DA72-452D-9D88-61EE882FE9A6} = {38E6C400-90C0-493E-9266-C1602E229F1B}
{4E237346-F948-46AC-801B-492545978280} = {38E6C400-90C0-493E-9266-C1602E229F1B}
+ {75A25CF6-9BA4-46F5-8BC3-90396230CB64} = {5DFAF4A2-ECB5-46E4-904D-1EA5F48B2D48}
+ {DA816A33-F164-4456-92DD-A672BAD1A6B1} = {0D34A7F0-DC77-4789-A136-93089CBD15C3}
+ {23633E49-F11A-4D14-899A-E2599C8182CE} = {38E6C400-90C0-493E-9266-C1602E229F1B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {40383055-CC50-4600-AD9A-53C14F620D03}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Constants.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Constants.cs
new file mode 100644
index 000000000..150f4581d
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Constants.cs
@@ -0,0 +1,10 @@
+// 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.BasicAbility.Mc;
+
+internal class Constants
+{
+ public const string DEFAULT_CLIENT_NAME = "masa.contrib.basicability.mc";
+}
+
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/DictionaryExtensions.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/DictionaryExtensions.cs
new file mode 100644
index 000000000..07faf46c8
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/DictionaryExtensions.cs
@@ -0,0 +1,118 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace System.Collections.Concurrent;
+
+///
+/// Extension methods for Dictionary.
+///
+public static class DictionaryExtensions
+{
+ ///
+ /// This method is used to try to get a value in a dictionary if it does exists.
+ ///
+ /// Type of the value
+ /// The collection object
+ /// Key
+ /// Value of the key (or default value if key not exists)
+ /// True if key does exists in the dictionary
+ internal static bool TryGetValue(this IDictionary dictionary, string key, out T value)
+ {
+ object valueObj;
+ if (dictionary.TryGetValue(key, out valueObj) && valueObj is T)
+ {
+ value = (T)valueObj;
+ return true;
+ }
+
+ value = default;
+ return false;
+ }
+
+ ///
+ /// Gets a value from the dictionary with given key. Returns default value if can not find.
+ ///
+ /// Dictionary to check and get
+ /// Key to find the value
+ /// Type of the key
+ /// Type of the value
+ /// Value if found, default if can not found.
+ public static TValue? GetOrDefault(this IDictionary dictionary, TKey key)
+ {
+ return dictionary.TryGetValue(key, out var obj) ? obj : default;
+ }
+
+ ///
+ /// Gets a value from the dictionary with given key. Returns default value if can not find.
+ ///
+ /// Dictionary to check and get
+ /// Key to find the value
+ /// Type of the key
+ /// Type of the value
+ /// Value if found, default if can not found.
+ public static TValue? GetOrDefault(this IReadOnlyDictionary dictionary, TKey key)
+ {
+ return dictionary.TryGetValue(key, out var obj) ? obj : default;
+ }
+
+ ///
+ /// Gets a value from the dictionary with given key. Returns default value if can not find.
+ ///
+ /// Dictionary to check and get
+ /// Key to find the value
+ /// Type of the key
+ /// Type of the value
+ /// Value if found, default if can not found.
+ public static TValue? GetOrDefault(this ConcurrentDictionary dictionary, TKey key)
+ {
+ return dictionary.TryGetValue(key, out var obj) ? obj : default;
+ }
+
+ ///
+ /// Gets a value from the dictionary with given key. Returns default value if can not find.
+ ///
+ /// Dictionary to check and get
+ /// Key to find the value
+ /// A factory method used to create the value if not found in the dictionary
+ /// Type of the key
+ /// Type of the value
+ /// Value if found, default if can not found.
+ public static TValue GetOrAdd(this IDictionary dictionary, [NotNull] TKey key, Func factory)
+ {
+ TValue obj;
+ if (dictionary.TryGetValue(key, out obj))
+ {
+ return obj;
+ }
+
+ return dictionary[key] = factory(key);
+ }
+
+ ///
+ /// Gets a value from the dictionary with given key. Returns default value if can not find.
+ ///
+ /// Dictionary to check and get
+ /// Key to find the value
+ /// A factory method used to create the value if not found in the dictionary
+ /// Type of the key
+ /// Type of the value
+ /// Value if found, default if can not found.
+ public static TValue GetOrAdd(this IDictionary dictionary, [NotNull] TKey key, Func factory)
+ {
+ return dictionary.GetOrAdd(key, k => factory());
+ }
+
+ ///
+ /// Gets a value from the concurrent dictionary with given key. Returns default value if can not find.
+ ///
+ /// Concurrent dictionary to check and get
+ /// Key to find the value
+ /// A factory method used to create the value if not found in the dictionary
+ /// Type of the key
+ /// Type of the value
+ /// Value if found, default if can not found.
+ public static TValue GetOrAdd(this ConcurrentDictionary dictionary, [NotNull] TKey key, Func factory)
+ {
+ return dictionary.GetOrAdd(key, k => factory());
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/ExtraPropertiesExtensions.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/ExtraPropertiesExtensions.cs
new file mode 100644
index 000000000..85bade60a
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/ExtraPropertiesExtensions.cs
@@ -0,0 +1,61 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace System.Collections.Concurrent;
+
+public static class ExtraPropertiesExtensions
+{
+ public static bool HasProperty(this ExtraPropertyDictionary source, string name)
+ {
+ return source.ContainsKey(name);
+ }
+
+ public static object GetProperty(this ExtraPropertyDictionary source, string name, object defaultValue = null)
+ {
+ return source.GetOrDefault(name)
+ ?? defaultValue;
+ }
+
+ public static TProperty GetProperty(this ExtraPropertyDictionary source, string name, TProperty defaultValue = default)
+ {
+ var value = source.GetProperty(name);
+ if (value == null)
+ {
+ return defaultValue;
+ }
+
+ if (TypeHelper.IsPrimitiveExtended(typeof(TProperty), includeEnums: true))
+ {
+ var conversionType = typeof(TProperty);
+ if (TypeHelper.IsNullable(conversionType))
+ {
+ conversionType = conversionType.GetFirstGenericArgumentIfNullable();
+ }
+
+ if (conversionType == typeof(Guid))
+ {
+ return (TProperty)TypeDescriptor.GetConverter(conversionType).ConvertFromInvariantString(value.ToString());
+ }
+
+ if (conversionType == typeof(DateTimeOffset))
+ {
+ return (TProperty)TypeDescriptor.GetConverter(conversionType).ConvertFromInvariantString(value.ToString());
+ }
+
+ return (TProperty)Convert.ChangeType(value?.ToString(), conversionType, CultureInfo.InvariantCulture);
+ }
+
+ throw new Exception("GetProperty does not support non-primitive types. Use non-generic GetProperty method and handle type casting manually.");
+ }
+
+ public static TSource SetProperty(
+ this TSource source,
+ string name,
+ object value)
+ where TSource : ExtraPropertyDictionary
+ {
+ source[name] = value;
+
+ return source;
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Helper/TypeHelper.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Helper/TypeHelper.cs
new file mode 100644
index 000000000..e75189fea
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Helper/TypeHelper.cs
@@ -0,0 +1,170 @@
+// 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.BasicAbility.Mc.Infrastructure.Helper;
+
+public static class TypeHelper
+{
+ private static readonly HashSet FloatingTypes = new HashSet
+ {
+ typeof(float),
+ typeof(double),
+ typeof(decimal)
+ };
+
+ private static readonly HashSet NonNullablePrimitiveTypes = new HashSet
+ {
+ typeof(byte),
+ typeof(short),
+ typeof(int),
+ typeof(long),
+ typeof(sbyte),
+ typeof(ushort),
+ typeof(uint),
+ typeof(ulong),
+ typeof(bool),
+ typeof(float),
+ typeof(decimal),
+ typeof(DateTime),
+ typeof(DateTimeOffset),
+ typeof(TimeSpan),
+ typeof(Guid)
+ };
+
+ public static bool IsNonNullablePrimitiveType(Type type)
+ {
+ return NonNullablePrimitiveTypes.Contains(type);
+ }
+
+ public static bool IsFunc(object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+
+ var type = obj.GetType();
+ if (!type.GetTypeInfo().IsGenericType)
+ {
+ return false;
+ }
+
+ return type.GetGenericTypeDefinition() == typeof(Func<>);
+ }
+
+ public static bool IsFunc(object obj)
+ {
+ return obj != null && obj.GetType() == typeof(Func);
+ }
+
+ public static bool IsPrimitiveExtended(Type type, bool includeNullables = true, bool includeEnums = false)
+ {
+ if (IsPrimitiveExtendedInternal(type, includeEnums))
+ {
+ return true;
+ }
+
+ if (includeNullables && IsNullable(type) && type.GenericTypeArguments.Any())
+ {
+ return IsPrimitiveExtendedInternal(type.GenericTypeArguments[0], includeEnums);
+ }
+
+ return false;
+ }
+
+ public static bool IsNullable(Type type)
+ {
+ return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
+ }
+
+ public static Type GetFirstGenericArgumentIfNullable(this Type t)
+ {
+ if (t.GetGenericArguments().Length > 0 && t.GetGenericTypeDefinition() == typeof(Nullable<>))
+ {
+ return t.GetGenericArguments().FirstOrDefault();
+ }
+
+ return t;
+ }
+
+ private static bool IsPrimitiveExtendedInternal(Type type, bool includeEnums)
+ {
+ if (type.IsPrimitive)
+ {
+ return true;
+ }
+
+ if (includeEnums && type.IsEnum)
+ {
+ return true;
+ }
+
+ return type == typeof(string) ||
+ type == typeof(decimal) ||
+ type == typeof(DateTimeOffset) ||
+ type == typeof(DateTimeOffset) ||
+ type == typeof(TimeSpan) ||
+ type == typeof(Guid);
+ }
+
+ public static T? GetDefaultValue()
+ {
+ return default;
+ }
+
+ public static object? GetDefaultValue(Type type)
+ {
+ if (type.IsValueType)
+ {
+ return Activator.CreateInstance(type);
+ }
+
+ return null;
+ }
+
+ public static bool IsFloatingType(Type type, bool includeNullable = true)
+ {
+ if (FloatingTypes.Contains(type))
+ {
+ return true;
+ }
+
+ if (includeNullable &&
+ IsNullable(type) &&
+ FloatingTypes.Contains(type.GenericTypeArguments[0]))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public static object ConvertFrom(object value)
+ {
+ return ConvertFrom(typeof(TTargetType), value);
+ }
+
+ public static object ConvertFrom(Type targetType, object value)
+ {
+ return TypeDescriptor
+ .GetConverter(targetType)
+ .ConvertFrom(value);
+ }
+
+ public static Type StripNullable(Type type)
+ {
+ return IsNullable(type)
+ ? type.GenericTypeArguments[0]
+ : type;
+ }
+
+ public static bool IsDefaultValue(object obj)
+ {
+ if (obj == null)
+ {
+ return true;
+ }
+
+ return obj.Equals(GetDefaultValue(obj.GetType()));
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Masa.Contrib.BasicAbility.Mc.csproj b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Masa.Contrib.BasicAbility.Mc.csproj
new file mode 100644
index 000000000..dc5193a50
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Masa.Contrib.BasicAbility.Mc.csproj
@@ -0,0 +1,17 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/McClient.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/McClient.cs
new file mode 100644
index 000000000..60f2c4a9e
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/McClient.cs
@@ -0,0 +1,26 @@
+// 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.BasicAbility.Mc;
+
+public class McClient: IMcClient
+{
+ public McClient(ICallerProvider callerProvider)
+ {
+ ChannelService = new ChannelService(callerProvider);
+ MessageTaskService = new MessageTaskService(callerProvider);
+ MessageTemplateService = new MessageTemplateService(callerProvider);
+ ReceiverGroupService = new ReceiverGroupService(callerProvider);
+ WebsiteMessageService = new WebsiteMessageService(callerProvider);
+ }
+
+ public IChannelService ChannelService { get; }
+
+ public IMessageTaskService MessageTaskService { get; }
+
+ public IMessageTemplateService MessageTemplateService { get; }
+
+ public IReceiverGroupService ReceiverGroupService { get; }
+
+ public IWebsiteMessageService WebsiteMessageService { get; }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ChannelService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ChannelService.cs
new file mode 100644
index 000000000..4698a5e7e
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ChannelService.cs
@@ -0,0 +1,27 @@
+// 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.BasicAbility.Mc.Service;
+
+public class ChannelService : IChannelService
+{
+ readonly ICallerProvider _callerProvider;
+ readonly string _party = "api/channel";
+
+ public ChannelService(ICallerProvider callerProvider)
+ {
+ _callerProvider = callerProvider;
+ }
+
+ public async Task GetAsync(Guid id)
+ {
+ var requestUri = $"{_party}/{id}";
+ return await _callerProvider.GetAsync(requestUri);
+ }
+
+ public async Task> GetListAsync(GetChannelModel options)
+ {
+ var requestUri = $"{_party}";
+ return await _callerProvider.GetAsync>(requestUri, options) ?? new();
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTaskService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTaskService.cs
new file mode 100644
index 000000000..8afe18b0c
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTaskService.cs
@@ -0,0 +1,33 @@
+// 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.BasicAbility.Mc.Service;
+
+public class MessageTaskService : IMessageTaskService
+{
+ readonly ICallerProvider _callerProvider;
+ readonly string _party = "api/message-task";
+
+ public MessageTaskService(ICallerProvider callerProvider)
+ {
+ _callerProvider = callerProvider;
+ }
+
+ public async Task GetAsync(Guid id)
+ {
+ var requestUri = $"{_party}/{id}";
+ return await _callerProvider.GetAsync(requestUri);
+ }
+
+ public async Task SendOrdinaryMessageAsync(SendOrdinaryMessageModel options)
+ {
+ var requestUri = $"{_party}";
+ await _callerProvider.PostAsync(requestUri, (MessageTaskUpsertModel)options);
+ }
+
+ public async Task SendTemplateMessageAsync(SendTemplateMessageModel options)
+ {
+ var requestUri = $"{_party}";
+ await _callerProvider.PostAsync(requestUri, (MessageTaskUpsertModel)options);
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTemplateService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTemplateService.cs
new file mode 100644
index 000000000..5a110ce81
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTemplateService.cs
@@ -0,0 +1,27 @@
+// 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.BasicAbility.Mc.Service;
+
+public class MessageTemplateService : IMessageTemplateService
+{
+ readonly ICallerProvider _callerProvider;
+ readonly string _party = "api/message-template";
+
+ public MessageTemplateService(ICallerProvider callerProvider)
+ {
+ _callerProvider = callerProvider;
+ }
+
+ public async Task GetAsync(Guid id)
+ {
+ var requestUri = $"{_party}/{id}";
+ return await _callerProvider.GetAsync(requestUri);
+ }
+
+ public async Task> GetListAsync(GetMessageTemplateModel options)
+ {
+ var requestUri = $"{_party}";
+ return await _callerProvider.GetAsync>(requestUri, options) ?? new();
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ReceiverGroupService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ReceiverGroupService.cs
new file mode 100644
index 000000000..a6b6606ab
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ReceiverGroupService.cs
@@ -0,0 +1,27 @@
+// 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.BasicAbility.Mc.Service;
+
+public class ReceiverGroupService : IReceiverGroupService
+{
+ readonly ICallerProvider _callerProvider;
+ readonly string _party = "api/receiver-group";
+
+ public ReceiverGroupService(ICallerProvider callerProvider)
+ {
+ _callerProvider = callerProvider;
+ }
+
+ public async Task GetAsync(Guid id)
+ {
+ var requestUri = $"{_party}/{id}";
+ return await _callerProvider.GetAsync(requestUri);
+ }
+
+ public async Task> GetListAsync(GetReceiverGroupModel options)
+ {
+ var requestUri = $"{_party}";
+ return await _callerProvider.GetAsync>(requestUri, options) ?? new();
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/WebsiteMessageService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/WebsiteMessageService.cs
new file mode 100644
index 000000000..261c82556
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/WebsiteMessageService.cs
@@ -0,0 +1,60 @@
+namespace Masa.Contrib.BasicAbility.Mc.Service;
+
+public class WebsiteMessageService : IWebsiteMessageService
+{
+ readonly ICallerProvider _callerProvider;
+ readonly string _party = "api/website-message";
+
+ public WebsiteMessageService(ICallerProvider callerProvider)
+ {
+ _callerProvider = callerProvider;
+ }
+
+ public async Task CheckAsync()
+ {
+ var requestUri = $"{_party}/Check";
+ await _callerProvider.PostAsync(requestUri, null);
+ }
+
+ public async Task DeleteAsync(Guid id)
+ {
+ var requestUri = $"{_party}/{id}";
+ await _callerProvider.DeleteAsync(requestUri, null);
+ }
+
+ public async Task GetAsync(Guid id)
+ {
+ var requestUri = $"{_party}/{id}";
+ return await _callerProvider.GetAsync(requestUri);
+ }
+
+ public async Task> GetChannelListAsync()
+ {
+ var requestUri = $"{_party}/GetChannelList";
+ return await _callerProvider.GetAsync>(requestUri)??new();
+ }
+
+ public async Task> GetListAsync(GetWebsiteMessageModel options)
+ {
+ var requestUri = $"{_party}";
+ return await _callerProvider.GetAsync>(requestUri, options) ?? new();
+ }
+
+ public async Task> GetNoticeListAsync(GetNoticeListModel options)
+ {
+ var requestUri = $"{_party}/GetNoticeList";
+ return await _callerProvider.GetAsync>(requestUri, options) ?? new();
+ }
+
+ public async Task ReadAsync(ReadWebsiteMessageModel options)
+ {
+ var requestUri = $"{_party}/Read";
+ await _callerProvider.PostAsync(requestUri, options);
+ }
+
+ public async Task SetAllReadAsync(ReadAllWebsiteMessageModel options)
+ {
+ var requestUri = $"{_party}/SetAllRead";
+ await _callerProvider.PostAsync(requestUri, options);
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/ServiceCollectionExtensions.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/ServiceCollectionExtensions.cs
new file mode 100644
index 000000000..5d3866f56
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/ServiceCollectionExtensions.cs
@@ -0,0 +1,43 @@
+// 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 AddMcClient(this IServiceCollection services, string mcServiceBaseAddress)
+ {
+ if (string.IsNullOrWhiteSpace(mcServiceBaseAddress))
+ {
+ throw new ArgumentNullException(nameof(mcServiceBaseAddress));
+ }
+
+ return services.AddMcClient(callerOptions =>
+ {
+ callerOptions.UseHttpClient(builder =>
+ {
+ builder.Name = DEFAULT_CLIENT_NAME;
+ builder.Configure = opt => opt.BaseAddress = new Uri(mcServiceBaseAddress);
+ });
+ });
+ }
+
+ public static IServiceCollection AddMcClient(this IServiceCollection services, Action callerOptions)
+ {
+ ArgumentNullException.ThrowIfNull(callerOptions, nameof(callerOptions));
+
+ if (services.Any(service => service.ServiceType == typeof(IMcClient)))
+ return services;
+
+ services.AddCaller(callerOptions.Invoke);
+
+ services.AddSingleton(serviceProvider =>
+ {
+ var callProvider = serviceProvider.GetRequiredService().CreateClient(DEFAULT_CLIENT_NAME);
+ var mcCaching = new McClient(callProvider);
+ return mcCaching;
+ });
+
+ return services;
+ }
+}
diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/_Imports.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/_Imports.cs
new file mode 100644
index 000000000..8f0f9087a
--- /dev/null
+++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/_Imports.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.
+
+global using Masa.BuildingBlocks.BasicAbility.Mc;
+global using Masa.BuildingBlocks.BasicAbility.Mc.Service;
+global using Masa.BuildingBlocks.BasicAbility.Mc.Model;
+global using Masa.Contrib.BasicAbility.Mc;
+global using static Masa.Contrib.BasicAbility.Mc.Constants;
+global using Masa.Contrib.BasicAbility.Mc.Infrastructure.Helper;
+global using Masa.Contrib.BasicAbility.Mc.Service;
+global using Masa.Utils.Caller.Core;
+global using Masa.Utils.Caller.HttpClient;
+global using System.ComponentModel;
+global using System.Diagnostics.CodeAnalysis;
+global using System.Globalization;
+global using System.Reflection;
diff --git a/src/BuildingBlocks/MASA.BuildingBlocks b/src/BuildingBlocks/MASA.BuildingBlocks
index c23cac480..da00ccea9 160000
--- a/src/BuildingBlocks/MASA.BuildingBlocks
+++ b/src/BuildingBlocks/MASA.BuildingBlocks
@@ -1 +1 @@
-Subproject commit c23cac480f83f5f9cc4970e38e782ff8270fe8e2
+Subproject commit da00ccea99a5f3efb0b4d8750ccbb59ab44fa2ef
diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/ChannelServiceTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/ChannelServiceTest.cs
new file mode 100644
index 000000000..4fd23e9ba
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/ChannelServiceTest.cs
@@ -0,0 +1,36 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.BasicAbility.Mc.Tests;
+
+[TestClass]
+public class ChannelServiceTest
+{
+ [TestMethod]
+ public async Task TestGetAsync()
+ {
+ var data = new ChannelModel();
+ Guid channelId = Guid.NewGuid();
+ var requestUri = $"api/channel/{channelId}";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable();
+ var channelService = new Mock(callerProvider.Object);
+ var result = await channelService.Object.GetAsync(channelId);
+ callerProvider.Verify(provider => provider.GetAsync(requestUri, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+
+ [TestMethod]
+ public async Task TestGetListAsync()
+ {
+ var options = new GetChannelModel();
+ var data = new PaginatedListModel();
+ var requestUri = $"api/channel";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync>(requestUri, options, default)).ReturnsAsync(data).Verifiable();
+ var channelService = new Mock(callerProvider.Object);
+ var result = await channelService.Object.GetListAsync(options);
+ callerProvider.Verify(provider => provider.GetAsync>(requestUri, options, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+}
diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/Masa.Contrib.BasicAbility.Mc.Tests.csproj b/test/Masa.Contrib.BasicAbility.Mc.Tests/Masa.Contrib.BasicAbility.Mc.Tests.csproj
new file mode 100644
index 000000000..226f1c111
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/Masa.Contrib.BasicAbility.Mc.Tests.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net6.0
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/McClientTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/McClientTest.cs
new file mode 100644
index 000000000..6ab73c254
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/McClientTest.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.BasicAbility.Mc.Tests;
+
+[TestClass]
+public class McClientTest
+{
+ [TestMethod]
+ public void TestAddMcClient()
+ {
+ var services = new ServiceCollection();
+ services.AddMcClient("https://localhost:18102");
+ var mcClient = services.BuildServiceProvider().GetRequiredService();
+
+ Assert.IsNotNull(mcClient);
+ }
+
+ [TestMethod]
+ public void TestAddMcClientShouldThrowArgumentNullException()
+ {
+ var services = new ServiceCollection();
+ Assert.ThrowsException(() => services.AddMcClient(mcServiceBaseAddress: null!));
+ }
+
+ [TestMethod]
+ public void TestAddMcClientShouldThrowArgumentNullException2()
+ {
+ var services = new ServiceCollection();
+ Assert.ThrowsException(() => services.AddMcClient(callerOptions: null!));
+ }
+}
diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTaskServiceTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTaskServiceTest.cs
new file mode 100644
index 000000000..a018bfc5d
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTaskServiceTest.cs
@@ -0,0 +1,46 @@
+// 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.BasicAbility.Mc.Tests;
+
+[TestClass]
+public class MessageTaskServiceTest
+{
+ [TestMethod]
+ public async Task TestGetAsync()
+ {
+ var data = new MessageTaskModel();
+ Guid id = Guid.NewGuid();
+ var requestUri = $"api/message-task/{id}";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable();
+ var messageTaskService = new Mock(callerProvider.Object);
+ var result = await messageTaskService.Object.GetAsync(id);
+ callerProvider.Verify(provider => provider.GetAsync(requestUri, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+
+ [TestMethod]
+ public async Task TestSendOrdinaryMessageAsync()
+ {
+ var options = new SendOrdinaryMessageModel();
+ var requestUri = $"api/message-task";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, It.IsAny(), true, default)).Verifiable();
+ var messageTaskService = new Mock(callerProvider.Object);
+ await messageTaskService.Object.SendOrdinaryMessageAsync(options);
+ callerProvider.Verify(provider => provider.PostAsync(requestUri, It.IsAny(), true, default), Times.Once);
+ }
+
+ [TestMethod]
+ public async Task TestSendTemplateMessageAsync()
+ {
+ var options = new SendTemplateMessageModel();
+ var requestUri = $"api/message-task";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, It.IsAny(), true, default)).Verifiable();
+ var messageTaskService = new Mock(callerProvider.Object);
+ await messageTaskService.Object.SendTemplateMessageAsync(options);
+ callerProvider.Verify(provider => provider.PostAsync(requestUri, It.IsAny(), true, default), Times.Once);
+ }
+}
diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTemplateServiceTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTemplateServiceTest.cs
new file mode 100644
index 000000000..85aee36d3
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTemplateServiceTest.cs
@@ -0,0 +1,36 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.BasicAbility.Mc.Tests;
+
+[TestClass]
+public class MessageTemplateServiceTest
+{
+ [TestMethod]
+ public async Task TestGetAsync()
+ {
+ var data = new MessageTemplateModel();
+ Guid id = Guid.NewGuid();
+ var requestUri = $"api/message-template/{id}";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable();
+ var messageTemplateService = new Mock(callerProvider.Object);
+ var result = await messageTemplateService.Object.GetAsync(id);
+ callerProvider.Verify(provider => provider.GetAsync(requestUri, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+
+ [TestMethod]
+ public async Task TestGetListAsync()
+ {
+ var options = new GetMessageTemplateModel();
+ var data = new PaginatedListModel();
+ var requestUri = $"api/message-template";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync>(requestUri, options, default)).ReturnsAsync(data).Verifiable();
+ var messageTemplateService = new Mock(callerProvider.Object);
+ var result = await messageTemplateService.Object.GetListAsync(options);
+ callerProvider.Verify(provider => provider.GetAsync>(requestUri, options, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+}
diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/ReceiverGroupServiceTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/ReceiverGroupServiceTest.cs
new file mode 100644
index 000000000..50be6cad0
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/ReceiverGroupServiceTest.cs
@@ -0,0 +1,36 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.BasicAbility.Mc.Tests;
+
+[TestClass]
+public class ReceiverGroupServiceTest
+{
+ [TestMethod]
+ public async Task TestGetAsync()
+ {
+ var data = new ReceiverGroupModel();
+ Guid id = Guid.NewGuid();
+ var requestUri = $"api/receiver-group/{id}";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable();
+ var receiverGroupService = new Mock(callerProvider.Object);
+ var result = await receiverGroupService.Object.GetAsync(id);
+ callerProvider.Verify(provider => provider.GetAsync(requestUri, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+
+ [TestMethod]
+ public async Task TestGetListAsync()
+ {
+ var options = new GetReceiverGroupModel();
+ var data = new PaginatedListModel();
+ var requestUri = $"api/receiver-group";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync>(requestUri, options, default)).ReturnsAsync(data).Verifiable();
+ var receiverGroupService = new Mock(callerProvider.Object);
+ var result = await receiverGroupService.Object.GetListAsync(options);
+ callerProvider.Verify(provider => provider.GetAsync>(requestUri, options, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+}
diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/WebsiteMessageServiceTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/WebsiteMessageServiceTest.cs
new file mode 100644
index 000000000..8a2a7035e
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/WebsiteMessageServiceTest.cs
@@ -0,0 +1,110 @@
+// 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.BasicAbility.Mc.Tests;
+
+[TestClass]
+public class WebsiteMessageServiceTest
+{
+ [TestMethod]
+ public async Task TestGetAsync()
+ {
+ var data = new WebsiteMessageModel();
+ Guid id = Guid.NewGuid();
+ var requestUri = $"api/website-message/{id}";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable();
+ var websiteMessageService = new Mock(callerProvider.Object);
+ var result = await websiteMessageService.Object.GetAsync(id);
+ callerProvider.Verify(provider => provider.GetAsync(requestUri, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+
+ [TestMethod]
+ public async Task TestGetListAsync()
+ {
+ var options = new GetWebsiteMessageModel();
+ var data = new PaginatedListModel();
+ var requestUri = $"api/website-message";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync>(requestUri, options, default)).ReturnsAsync(data).Verifiable();
+ var websiteMessageService = new Mock(callerProvider.Object);
+ var result = await websiteMessageService.Object.GetListAsync(options);
+ callerProvider.Verify(provider => provider.GetAsync>(requestUri, options, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+
+ [TestMethod]
+ public async Task TestCheckAsync()
+ {
+ var requestUri = $"api/website-message/Check";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, null, true, default)).Verifiable();
+ var websiteMessageService = new Mock(callerProvider.Object);
+ await websiteMessageService.Object.CheckAsync();
+ callerProvider.Verify(provider => provider.PostAsync(requestUri, null, true, default), Times.Once);
+ }
+
+ [TestMethod]
+ public async Task TestDeleteAsync()
+ {
+ Guid id = Guid.NewGuid();
+ var requestUri = $"api/website-message/{id}";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.DeleteAsync(requestUri, null, true, default)).Verifiable();
+ var websiteMessageService = new Mock(callerProvider.Object);
+ await websiteMessageService.Object.DeleteAsync(id);
+ callerProvider.Verify(provider => provider.DeleteAsync(requestUri, null, true, default), Times.Once);
+ }
+
+ [TestMethod]
+ public async Task TestGetChannelListAsync()
+ {
+ var data = new List();
+ var requestUri = $"api/website-message/GetChannelList";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync>(requestUri, default)).ReturnsAsync(data).Verifiable();
+ var websiteMessageService = new Mock(callerProvider.Object);
+ var result = await websiteMessageService.Object.GetChannelListAsync();
+ callerProvider.Verify(provider => provider.GetAsync>(requestUri, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+
+ [TestMethod]
+ public async Task TestGetNoticeListAsync()
+ {
+ var options = new GetNoticeListModel();
+ var data = new List();
+ var requestUri = $"api/website-message/GetNoticeList";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.GetAsync>(requestUri, options, default)).ReturnsAsync(data).Verifiable();
+ var websiteMessageService = new Mock(callerProvider.Object);
+ var result = await websiteMessageService.Object.GetNoticeListAsync(options);
+ callerProvider.Verify(provider => provider.GetAsync>(requestUri, options, default), Times.Once);
+ Assert.IsTrue(result is not null);
+ }
+
+ [TestMethod]
+ public async Task TestReadAsync()
+ {
+ var options = new ReadWebsiteMessageModel();
+ var requestUri = $"api/website-message/Read";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, options, true, default)).Verifiable();
+ var websiteMessageService = new Mock(callerProvider.Object);
+ await websiteMessageService.Object.ReadAsync(options);
+ callerProvider.Verify(provider => provider.PostAsync(requestUri, options, true, default), Times.Once);
+ }
+
+ [TestMethod]
+ public async Task TestSetAllReadAsync()
+ {
+ var options = new ReadAllWebsiteMessageModel();
+ var requestUri = $"api/website-message/SetAllRead";
+ var callerProvider = new Mock();
+ callerProvider.Setup(provider => provider.PostAsync(requestUri, options, true, default)).Verifiable();
+ var websiteMessageService = new Mock(callerProvider.Object);
+ await websiteMessageService.Object.SetAllReadAsync(options);
+ callerProvider.Verify(provider => provider.PostAsync(requestUri, options, true, default), Times.Once);
+ }
+}
diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/_Imports.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/_Imports.cs
new file mode 100644
index 000000000..7a153ef0b
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/_Imports.cs
@@ -0,0 +1,14 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+global using Microsoft.VisualStudio.TestTools.UnitTesting;
+global using System.Threading.Tasks;
+global using Masa.BuildingBlocks.BasicAbility.Mc.Model;
+global using Masa.Utils.Caller.Core;
+global using Moq;
+global using System;
+global using Masa.Contrib.BasicAbility.Mc.Service;
+global using Masa.BuildingBlocks.Ddd.Domain.Repositories;
+global using Masa.BuildingBlocks.BasicAbility.Mc;
+global using Microsoft.Extensions.DependencyInjection;
+global using System.Collections.Generic;