diff --git a/aspnet-core/LINGYUN.MicroService.SingleProject.sln b/aspnet-core/LINGYUN.MicroService.SingleProject.sln
index 24066a7de..93e856774 100644
--- a/aspnet-core/LINGYUN.MicroService.SingleProject.sln
+++ b/aspnet-core/LINGYUN.MicroService.SingleProject.sln
@@ -496,6 +496,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.AspNetCore.Wrap
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OpenIddict.AspNetCore", "modules\openIddict\LINGYUN.Abp.OpenIddict.AspNetCore\LINGYUN.Abp.OpenIddict.AspNetCore.csproj", "{6026DAE3-F2AD-4F6B-99EF-EEAAA5873861}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Official.Application.Contracts", "framework\wechat\LINGYUN.Abp.WeChat.Official.Application.Contracts\LINGYUN.Abp.WeChat.Official.Application.Contracts.csproj", "{B7F866FF-8C8F-4C7D-9084-E0C206F1F26F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Official.Application", "framework\wechat\LINGYUN.Abp.WeChat.Official.Application\LINGYUN.Abp.WeChat.Official.Application.csproj", "{E957DB2E-589D-4310-9576-92F108A67CE7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Official.HttpApi", "framework\wechat\LINGYUN.Abp.WeChat.Official.HttpApi\LINGYUN.Abp.WeChat.Official.HttpApi.csproj", "{4DEFD1AB-C8CD-4240-B4C7-1C8EA4286B2A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Common", "framework\wechat\LINGYUN.Abp.WeChat.Common\LINGYUN.Abp.WeChat.Common.csproj", "{C4690A20-8628-4A39-8E71-2D09800D0E72}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.WeChat.Work.Common", "framework\wechat\LINGYUN.Abp.WeChat.Work.Common\LINGYUN.Abp.WeChat.Work.Common.csproj", "{8233A44F-4DFC-4701-9C04-834FD3C97060}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1298,6 +1308,26 @@ Global
{6026DAE3-F2AD-4F6B-99EF-EEAAA5873861}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6026DAE3-F2AD-4F6B-99EF-EEAAA5873861}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6026DAE3-F2AD-4F6B-99EF-EEAAA5873861}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B7F866FF-8C8F-4C7D-9084-E0C206F1F26F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B7F866FF-8C8F-4C7D-9084-E0C206F1F26F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B7F866FF-8C8F-4C7D-9084-E0C206F1F26F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B7F866FF-8C8F-4C7D-9084-E0C206F1F26F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E957DB2E-589D-4310-9576-92F108A67CE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E957DB2E-589D-4310-9576-92F108A67CE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E957DB2E-589D-4310-9576-92F108A67CE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E957DB2E-589D-4310-9576-92F108A67CE7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4DEFD1AB-C8CD-4240-B4C7-1C8EA4286B2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4DEFD1AB-C8CD-4240-B4C7-1C8EA4286B2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4DEFD1AB-C8CD-4240-B4C7-1C8EA4286B2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4DEFD1AB-C8CD-4240-B4C7-1C8EA4286B2A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C4690A20-8628-4A39-8E71-2D09800D0E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C4690A20-8628-4A39-8E71-2D09800D0E72}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C4690A20-8628-4A39-8E71-2D09800D0E72}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C4690A20-8628-4A39-8E71-2D09800D0E72}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8233A44F-4DFC-4701-9C04-834FD3C97060}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8233A44F-4DFC-4701-9C04-834FD3C97060}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8233A44F-4DFC-4701-9C04-834FD3C97060}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8233A44F-4DFC-4701-9C04-834FD3C97060}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1541,6 +1571,11 @@ Global
{0D34162C-0CE3-4D7B-B19A-4786C616D0B3} = {5531E2F2-2FC2-45A0-93C7-7FC6F6A4F0AD}
{FDBA1B4A-CC5D-4710-AB8C-FA5A91B91BDE} = {40A9F0DB-66AA-42A8-8670-9DD6DA992103}
{6026DAE3-F2AD-4F6B-99EF-EEAAA5873861} = {7C714185-D3D9-4D94-B5CB-D857A0091F04}
+ {B7F866FF-8C8F-4C7D-9084-E0C206F1F26F} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
+ {E957DB2E-589D-4310-9576-92F108A67CE7} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
+ {4DEFD1AB-C8CD-4240-B4C7-1C8EA4286B2A} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
+ {C4690A20-8628-4A39-8E71-2D09800D0E72} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
+ {8233A44F-4DFC-4701-9C04-834FD3C97060} = {91867618-0D86-4410-91C6-B1166A9ACDF9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {711A43C0-A2F8-4E5C-9B9F-F2551E4B3FF1}
diff --git a/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.QQ/LINGYUN/Abp/Authentication/QQ/AbpAuthenticationQQConsts.cs b/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.QQ/LINGYUN/Abp/Authentication/QQ/AbpAuthenticationQQConsts.cs
index cc7ee8c6f..1a002c916 100644
--- a/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.QQ/LINGYUN/Abp/Authentication/QQ/AbpAuthenticationQQConsts.cs
+++ b/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.QQ/LINGYUN/Abp/Authentication/QQ/AbpAuthenticationQQConsts.cs
@@ -4,5 +4,5 @@ public static class AbpAuthenticationQQConsts
{
public static string AuthenticationScheme { get; set; } = "QQ Connect";
public static string DisplayName { get; set; } = "QQ Connect";
- public static string CallbackPath { get; set; } = "/signin-callback";
+ public static string CallbackPath { get; set; } = "/signin-qq";
}
diff --git a/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.WeChat/LINGYUN/Abp/Authentication/WeChat/AbpAuthenticationWeChatConsts.cs b/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.WeChat/LINGYUN/Abp/Authentication/WeChat/AbpAuthenticationWeChatConsts.cs
index 481315312..038924adf 100644
--- a/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.WeChat/LINGYUN/Abp/Authentication/WeChat/AbpAuthenticationWeChatConsts.cs
+++ b/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.WeChat/LINGYUN/Abp/Authentication/WeChat/AbpAuthenticationWeChatConsts.cs
@@ -20,7 +20,7 @@ public static class AbpAuthenticationWeChatConsts
///
/// 回调地址
///
- public static string CallbackPath { get; set; } = "/signin-callback";
+ public static string CallbackPath { get; set; } = "/signin-wechat";
///
/// 微信客户端外的网页登录
diff --git a/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.WeChat/Microsoft/AspNetCore/Authentication/WeChat/Official/WeChatOfficialOAuthHandler.cs b/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.WeChat/Microsoft/AspNetCore/Authentication/WeChat/Official/WeChatOfficialOAuthHandler.cs
index a0786347f..faa5f0b43 100644
--- a/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.WeChat/Microsoft/AspNetCore/Authentication/WeChat/Official/WeChatOfficialOAuthHandler.cs
+++ b/aspnet-core/framework/authentication/LINGYUN.Abp.Authentication.WeChat/Microsoft/AspNetCore/Authentication/WeChat/Official/WeChatOfficialOAuthHandler.cs
@@ -2,7 +2,6 @@
using LINGYUN.Abp.WeChat.Official;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.WebUtilities;
-using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
@@ -16,7 +15,6 @@ using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading.Tasks;
-using Volo.Abp.Caching;
namespace Microsoft.AspNetCore.Authentication.WeChat.Official
{
@@ -25,10 +23,8 @@ namespace Microsoft.AspNetCore.Authentication.WeChat.Official
///
public class WeChatOfficialOAuthHandler : OAuthHandler
{
- protected IDistributedCache Cache { get; }
protected AbpWeChatOfficialOptionsFactory WeChatOfficialOptionsFactory { get; }
public WeChatOfficialOAuthHandler(
- IDistributedCache cache,
IOptionsMonitor options,
AbpWeChatOfficialOptionsFactory weChatOfficialOptionsFactory,
ILoggerFactory logger,
@@ -36,7 +32,6 @@ namespace Microsoft.AspNetCore.Authentication.WeChat.Official
ISystemClock clock)
: base(options, logger, encoder, clock)
{
- Cache = cache;
WeChatOfficialOptionsFactory = weChatOfficialOptionsFactory;
}
@@ -50,154 +45,137 @@ namespace Microsoft.AspNetCore.Authentication.WeChat.Official
await base.InitializeHandlerAsync();
}
+ ///
+ /// 第一步:构建用户授权地址
+ ///
+ protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
+ {
+ var isWeChatBrewserRequest = IsWeChatBrowser();
- protected override async Task CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
+ var scope = isWeChatBrewserRequest
+ ? AbpAuthenticationWeChatConsts.UserInfoScope
+ : AbpAuthenticationWeChatConsts.LoginScope;
+
+ var endPoint = isWeChatBrewserRequest
+ ? Options.AuthorizationEndpoint
+ : AbpAuthenticationWeChatConsts.QrConnectEndpoint;
+
+ redirectUri += $"?protected={Options.StateDataFormat.Protect(properties)}";
+
+ var parameters = new Dictionary
+ {
+ { "appid", Options.ClientId },
+ { "redirect_uri", redirectUri },
+ { "response_type", "code" },
+ { "scope", scope },
+ { "state", Guid.NewGuid().ToString("N") },
+ };
+
+ return $"{QueryHelpers.AddQueryString(endPoint, parameters)}#wechat_redirect";
+ }
+
+ ///
+ /// 第二步:code换取access_token
+ ///
+ protected async override Task ExchangeCodeAsync(OAuthCodeExchangeContext context)
{
- var address = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, new Dictionary
+ var parameters = new Dictionary()
{
- ["access_token"] = tokens.AccessToken,
- ["openid"] = tokens.Response.GetRootString("openid")
- });
+ { "appid", Options.ClientId },
+ { "secret", Options.ClientSecret },
+ { "code", context.Code },
+ { "grant_type", "authorization_code" },
+ };
+
+ var address = QueryHelpers.AddQueryString(Options.TokenEndpoint, parameters);
var response = await Backchannel.GetAsync(address);
if (!response.IsSuccessStatusCode)
{
- Logger.LogError("An error occurred while retrieving the user profile: the remote server " +
+ Logger.LogError("An error occurred while retrieving an access token: the remote server " +
"returned a {Status} response with the following payload: {Headers} {Body}.",
/* Status: */ response.StatusCode,
/* Headers: */ response.Headers.ToString(),
/* Body: */ await response.Content.ReadAsStringAsync());
- throw new HttpRequestException("An error occurred while retrieving user information.");
+ return OAuthTokenResponse.Failed(new Exception("An error occurred while retrieving an access token."));
}
var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
if (!string.IsNullOrEmpty(payload.GetRootString("errcode")))
{
- Logger.LogError("An error occurred while retrieving the user profile: the remote server " +
+ Logger.LogError("An error occurred while retrieving an access token: the remote server " +
"returned a {Status} response with the following payload: {Headers} {Body}.",
/* Status: */ response.StatusCode,
/* Headers: */ response.Headers.ToString(),
/* Body: */ await response.Content.ReadAsStringAsync());
- throw new HttpRequestException("An error occurred while retrieving user information.");
+ return OAuthTokenResponse.Failed(new Exception("An error occurred while retrieving an access token."));
}
-
- var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload.RootElement);
- context.RunClaimActions();
-
- await Events.CreatingTicket(context);
-
- // TODO: 此处通过唯一的 CorrelationId, 将 properties生成的State缓存删除
- var state = Request.Query["state"];
-
- var stateCacheKey = WeChatOfficialStateCacheItem.CalculateCacheKey(state.ToString().ToMd5(), null);
- await Cache.RemoveAsync(stateCacheKey, token: Context.RequestAborted);
-
- return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
+ return OAuthTokenResponse.Success(payload);
}
///
- /// code换取access_token
- ///
- protected override async Task ExchangeCodeAsync(OAuthCodeExchangeContext context)
+ /// 第三步:构建用户票据
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected async override Task CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
{
- var address = QueryHelpers.AddQueryString(Options.TokenEndpoint, new Dictionary()
+ var address = QueryHelpers.AddQueryString(Options.UserInformationEndpoint, new Dictionary
{
- ["appid"] = Options.ClientId,
- ["secret"] = Options.ClientSecret,
- ["code"] = context.Code,
- ["grant_type"] = "authorization_code"
+ ["access_token"] = tokens.AccessToken,
+ ["openid"] = tokens.Response.GetRootString("openid")
});
var response = await Backchannel.GetAsync(address);
if (!response.IsSuccessStatusCode)
{
- Logger.LogError("An error occurred while retrieving an access token: the remote server " +
+ Logger.LogError("An error occurred while retrieving the user profile: the remote server " +
"returned a {Status} response with the following payload: {Headers} {Body}.",
/* Status: */ response.StatusCode,
/* Headers: */ response.Headers.ToString(),
/* Body: */ await response.Content.ReadAsStringAsync());
- return OAuthTokenResponse.Failed(new Exception("An error occurred while retrieving an access token."));
+ throw new HttpRequestException("An error occurred while retrieving user information.");
}
var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
if (!string.IsNullOrEmpty(payload.GetRootString("errcode")))
{
- Logger.LogError("An error occurred while retrieving an access token: the remote server " +
+ Logger.LogError("An error occurred while retrieving the user profile: the remote server " +
"returned a {Status} response with the following payload: {Headers} {Body}.",
/* Status: */ response.StatusCode,
/* Headers: */ response.Headers.ToString(),
/* Body: */ await response.Content.ReadAsStringAsync());
- return OAuthTokenResponse.Failed(new Exception("An error occurred while retrieving an access token."));
+ throw new HttpRequestException("An error occurred while retrieving user information.");
}
- return OAuthTokenResponse.Success(payload);
- }
-
- protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
- {
- await base.HandleChallengeAsync(properties);
- // TODO: 此处已经生成唯一的 CorrelationId, 可以借此将 properties生成State之后再进行缓存
- // 注: 默认的State对于微信来说太长(微信只支持128位长度的State),因此巧妙的利用CorrelationId的MD5值来替代State
- // MD5转换防止直接通过CorrelationId干些别的事情...
- var state = properties.Items[".xsrf"];
+ var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload.RootElement);
+ context.RunClaimActions();
- var stateToken = Options.StateDataFormat.Protect(properties);
- var stateCacheKey = WeChatOfficialStateCacheItem.CalculateCacheKey(state.ToMd5(), null);
+ await Events.CreatingTicket(context);
- await Cache
- .SetAsync(
- stateCacheKey,
- new WeChatOfficialStateCacheItem(stateToken),
- new DistributedCacheEntryOptions
- {
- AbsoluteExpiration = Clock.UtcNow.AddMinutes(2) // TODO: 设定2分钟过期?
- },
- token: Context.RequestAborted);
+ return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
}
- ///
- /// 构建用户授权地址
- ///
- protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
- {
- var state = properties.Items[".xsrf"];
-
- var isWeChatBrewserRequest = IsWeChatBrowser();
-
- var scope = isWeChatBrewserRequest
- ? AbpAuthenticationWeChatConsts.UserInfoScope
- : FormatScope();
- var endPoint = isWeChatBrewserRequest
- ? Options.AuthorizationEndpoint
- : AbpAuthenticationWeChatConsts.QrConnectEndpoint;
-
- var challengeUrl = QueryHelpers.AddQueryString(endPoint, new Dictionary
- {
- ["appid"] = Options.ClientId,
- ["redirect_uri"] = redirectUri,
- ["response_type"] = "code"
- });
-
- challengeUrl += $"&scope={scope}&state={state.ToMd5()}";
-
- return challengeUrl;
+ public override Task HandleRequestAsync()
+ {
+ return base.HandleRequestAsync();
}
- protected override async Task HandleRemoteAuthenticateAsync()
+ protected async override Task HandleRemoteAuthenticateAsync()
{
var query = Request.Query;
// TODO: 此处借用唯一的 CorrelationId, 将 properties生成的State缓存取出,进行解密
- var state = query["state"];
-
- var stateCacheKey = WeChatOfficialStateCacheItem.CalculateCacheKey(state.ToString().ToMd5(), null);
- var stateCacheItem = await Cache.GetAsync(stateCacheKey, token: Context.RequestAborted);
+ var state = query["protected"];
- var properties = Options.StateDataFormat.Unprotect(stateCacheItem.State);
+ var properties = Options.StateDataFormat.Unprotect(state);
if (properties == null)
{
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/FodyWeavers.xml b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/FodyWeavers.xml
new file mode 100644
index 000000000..00e1d9a1c
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/FodyWeavers.xsd b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/FodyWeavers.xsd
new file mode 100644
index 000000000..3f3946e28
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN.Abp.WeChat.Common.csproj b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN.Abp.WeChat.Common.csproj
new file mode 100644
index 000000000..f2794ccd9
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN.Abp.WeChat.Common.csproj
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonModule.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonModule.cs
new file mode 100644
index 000000000..a87210d31
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/AbpWeChatCommonModule.cs
@@ -0,0 +1,33 @@
+using LINGYUN.Abp.WeChat.Common.Localization;
+using Volo.Abp.EventBus;
+using Volo.Abp.Localization;
+using Volo.Abp.Localization.ExceptionHandling;
+using Volo.Abp.Modularity;
+using Volo.Abp.VirtualFileSystem;
+
+namespace LINGYUN.Abp.WeChat.Common;
+
+[DependsOn(
+ typeof(AbpEventBusModule))]
+public class AbpWeChatCommonModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.FileSets.AddEmbedded();
+ });
+
+ Configure(options =>
+ {
+ options.Resources
+ .Add("zh-Hans")
+ .AddVirtualJson("/LINGYUN/Abp/WeChat/Common/Localization/Resources");
+ });
+
+ Configure(options =>
+ {
+ options.MapCodeNamespace(WeChatCommonErrorCodes.Namespace, typeof(WeChatCommonResource));
+ });
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/AbpWeChatException.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/AbpWeChatException.cs
similarity index 93%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/AbpWeChatException.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/AbpWeChatException.cs
index 2ef28d3f9..176bb465b 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/AbpWeChatException.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/AbpWeChatException.cs
@@ -2,7 +2,7 @@
using System.Runtime.Serialization;
using Volo.Abp;
-namespace LINGYUN.Abp.WeChat;
+namespace LINGYUN.Abp.WeChat.Common;
public class AbpWeChatException : BusinessException
{
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/AbpWeChatCryptoException.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/AbpWeChatCryptoException.cs
new file mode 100644
index 000000000..c6e1fe958
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/AbpWeChatCryptoException.cs
@@ -0,0 +1,37 @@
+using LINGYUN.Abp.WeChat.Common;
+using System;
+using System.Runtime.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Common.Crypto;
+public class AbpWeChatCryptoException : AbpWeChatException
+{
+ public AbpWeChatCryptoException()
+ {
+ }
+
+ public AbpWeChatCryptoException(
+ SerializationInfo serializationInfo,
+ StreamingContext context) : base(serializationInfo, context)
+ {
+ }
+
+ public AbpWeChatCryptoException(
+ string appId,
+ string message = null,
+ string details = null,
+ Exception innerException = null)
+ : this(appId, "WeChat:100400", message, details, innerException)
+ {
+ }
+
+ public AbpWeChatCryptoException(
+ string appId,
+ string code = null,
+ string message = null,
+ string details = null,
+ Exception innerException = null)
+ : base(code, message, details, innerException)
+ {
+ WithData("AppId", appId);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/IWeChatCryptoService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/IWeChatCryptoService.cs
new file mode 100644
index 000000000..a8beb523f
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/IWeChatCryptoService.cs
@@ -0,0 +1,29 @@
+using LINGYUN.Abp.WeChat.Common.Crypto.Models;
+
+namespace LINGYUN.Abp.WeChat.Common.Crypto
+{
+ public interface IWeChatCryptoService
+ {
+ ///
+ /// 校验
+ ///
+ ///
+ ///
+ ///
+ string Validation(WeChatCryptoEchoData data);
+ ///
+ /// 解密
+ ///
+ ///
+ ///
+ ///
+ string Decrypt(WeChatCryptoDecryptData data);
+ ///
+ /// 加密
+ ///
+ ///
+ ///
+ ///
+ string Encrypt(WeChatCryptoEncryptData data);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/Models/WeChatCryptoDecryptData.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/Models/WeChatCryptoDecryptData.cs
new file mode 100644
index 000000000..5e5ad65aa
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/Models/WeChatCryptoDecryptData.cs
@@ -0,0 +1,28 @@
+namespace LINGYUN.Abp.WeChat.Common.Crypto.Models;
+public class WeChatCryptoDecryptData
+{
+ public string MsgSignature { get; }
+ public string ReceiveId { get; }
+ public string Token { get; }
+ public string EncodingAESKey { get; }
+ public string TimeStamp { get; }
+ public string Nonce { get; }
+ public string PostData { get; }
+ public WeChatCryptoDecryptData(
+ string postData,
+ string receiveId,
+ string token,
+ string encodingAESKey,
+ string msgSignature,
+ string timeStamp,
+ string nonce)
+ {
+ PostData = postData;
+ ReceiveId = receiveId;
+ Token = token;
+ EncodingAESKey = encodingAESKey;
+ MsgSignature = msgSignature;
+ TimeStamp = timeStamp;
+ Nonce = nonce;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoData.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/Models/WeChatCryptoEchoData.cs
similarity index 73%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoData.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/Models/WeChatCryptoEchoData.cs
index bdaab08c1..6884944f0 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoData.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/Models/WeChatCryptoEchoData.cs
@@ -1,13 +1,15 @@
-namespace LINGYUN.Abp.WeChat.Work.Security.Models;
-public class WeChatWorkCryptoData
+namespace LINGYUN.Abp.WeChat.Common.Crypto.Models;
+public class WeChatCryptoEchoData
{
+ public string EchoStr { get; }
+ public string MsgSignature { get; }
public string ReceiveId { get; }
public string Token { get; }
public string EncodingAESKey { get; }
- public string MsgSignature { get; }
public string TimeStamp { get; }
public string Nonce { get; }
- public WeChatWorkCryptoData(
+ public WeChatCryptoEchoData(
+ string echoStr,
string receiveId,
string token,
string encodingAESKey,
@@ -15,6 +17,7 @@ public class WeChatWorkCryptoData
string timeStamp,
string nonce)
{
+ EchoStr = echoStr;
ReceiveId = receiveId;
Token = token;
EncodingAESKey = encodingAESKey;
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/Models/WeChatCryptoEncryptData.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/Models/WeChatCryptoEncryptData.cs
new file mode 100644
index 000000000..edb8e4404
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/Models/WeChatCryptoEncryptData.cs
@@ -0,0 +1,19 @@
+namespace LINGYUN.Abp.WeChat.Common.Crypto.Models;
+public class WeChatCryptoEncryptData
+{
+ public string Data { get; }
+ public string ReceiveId { get; }
+ public string Token { get; }
+ public string EncodingAESKey { get; }
+ public WeChatCryptoEncryptData(
+ string data,
+ string receiveId,
+ string token,
+ string encodingAESKey)
+ {
+ Data = data;
+ ReceiveId = receiveId;
+ Token = token;
+ EncodingAESKey = encodingAESKey;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/WeChatCryptoService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/WeChatCryptoService.cs
new file mode 100644
index 000000000..aaef074ae
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Crypto/WeChatCryptoService.cs
@@ -0,0 +1,94 @@
+using LINGYUN.Abp.WeChat.Common.Crypto.Models;
+using LINGYUN.Abp.WeChat.Common.Utils;
+using System;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.WeChat.Common.Crypto
+{
+ public class WeChatCryptoService : IWeChatCryptoService, ITransientDependency
+ {
+ public string Decrypt(WeChatCryptoDecryptData data)
+ {
+ var crypto = new WXBizMsgCrypt(
+ data.Token,
+ data.EncodingAESKey,
+ data.ReceiveId);
+
+ var retMsg = "";
+ var ret = crypto.DecryptMsg(
+ data.MsgSignature,
+ data.TimeStamp,
+ data.Nonce,
+ data.PostData,
+ ref retMsg);
+
+ if (ret != 0)
+ {
+ throw new AbpWeChatCryptoException(data.ReceiveId, code: $"WeChat:{ret}");
+ }
+
+ return retMsg;
+ }
+
+ public string Encrypt(WeChatCryptoEncryptData data)
+ {
+ var crypto = new WXBizMsgCrypt(
+ data.Token,
+ data.EncodingAESKey,
+ data.ReceiveId);
+
+ var sinature = "";
+ var timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString();
+ var nonce = DateTimeOffset.Now.Ticks.ToString("x");
+ var sinatureRet = WXBizMsgCrypt.GenarateSinature(
+ data.Token,
+ timestamp,
+ nonce,
+ data.Data,
+ ref sinature);
+ if (sinatureRet != 0)
+ {
+ throw new AbpWeChatCryptoException(data.ReceiveId, code: $"WeChat:{sinatureRet}");
+ }
+
+ var retMsg = "";
+
+ var ret = crypto.EncryptMsg(
+ sinature,
+ timestamp,
+ nonce,
+ ref retMsg);
+
+ if (ret != 0)
+ {
+ throw new AbpWeChatCryptoException(data.ReceiveId, code: $"WeChat:{ret}");
+ }
+
+ return retMsg;
+ }
+
+ public string Validation(WeChatCryptoEchoData data)
+ {
+ var crypto = new WXBizMsgCrypt(
+ data.Token,
+ data.EncodingAESKey,
+ data.ReceiveId);
+
+ var retMsg = "";
+
+ var ret = crypto.VerifyURL(
+ data.MsgSignature,
+ data.TimeStamp,
+ data.Nonce,
+ data.EchoStr,
+ ref retMsg);
+
+ if (ret != 0)
+ {
+ throw new AbpWeChatCryptoException(data.ReceiveId, code: $"WeChat:{ret}");
+ }
+
+ return retMsg;
+ }
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Localization/Resources/en.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Localization/Resources/en.json
new file mode 100644
index 000000000..5303f0e8e
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Localization/Resources/en.json
@@ -0,0 +1,16 @@
+{
+ "culture": "en",
+ "texts": {
+ "WeChat:-40001": "签名验证错误",
+ "WeChat:-40002": "xml/json解析失败",
+ "WeChat:-40003": "sha加密生成签名失败",
+ "WeChat:-40004": "AESKey 非法",
+ "WeChat:-40005": "AppId 校验错误",
+ "WeChat:-40006": "AES 加密失败",
+ "WeChat:-40007": "AES 解密失败",
+ "WeChat:-40008": "解密后得到的buffer非法",
+ "WeChat:-40009": "base64加密失败",
+ "WeChat:-40010": "base64解密失败",
+ "WeChat:-40011": "生成xml/json失败"
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Localization/Resources/zh-Hans.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Localization/Resources/zh-Hans.json
new file mode 100644
index 000000000..42683227d
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Localization/Resources/zh-Hans.json
@@ -0,0 +1,16 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "WeChat:-40001": "签名验证错误",
+ "WeChat:-40002": "xml/json解析失败",
+ "WeChat:-40003": "sha加密生成签名失败",
+ "WeChat:-40004": "AESKey 非法",
+ "WeChat:-40005": "AppId 校验错误",
+ "WeChat:-40006": "AES 加密失败",
+ "WeChat:-40007": "AES 解密失败",
+ "WeChat:-40008": "解密后得到的buffer非法",
+ "WeChat:-40009": "base64加密失败",
+ "WeChat:-40010": "base64解密失败",
+ "WeChat:-40011": "生成xml/json失败"
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Localization/WeChatCommonResource.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Localization/WeChatCommonResource.cs
new file mode 100644
index 000000000..9b8efa625
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Localization/WeChatCommonResource.cs
@@ -0,0 +1,8 @@
+using Volo.Abp.Localization;
+
+namespace LINGYUN.Abp.WeChat.Common.Localization;
+
+[LocalizationResourceName("WeChatCommon")]
+public class WeChatCommonResource
+{
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/AbpWeChatMessageResolveOptions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/AbpWeChatMessageResolveOptions.cs
new file mode 100644
index 000000000..91af5f200
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/AbpWeChatMessageResolveOptions.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+public class AbpWeChatMessageResolveOptions
+{
+ public List MessageResolvers { get; }
+
+ public AbpWeChatMessageResolveOptions()
+ {
+ MessageResolvers = new List();
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/AbpWeChatMessageHandleOptions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/AbpWeChatMessageHandleOptions.cs
new file mode 100644
index 000000000..fcab3676b
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/AbpWeChatMessageHandleOptions.cs
@@ -0,0 +1,40 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System;
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+public class AbpWeChatMessageHandleOptions
+{
+ internal IDictionary> EventHandlers { get; }
+ internal IDictionary> MessageHandlers { get; }
+
+ public AbpWeChatMessageHandleOptions()
+ {
+ EventHandlers = new Dictionary>();
+ MessageHandlers = new Dictionary>();
+ }
+
+ public void MapEvent()
+ where TEvent : WeChatEventMessage
+ where TEventHandler : IEventHandleContributor
+ {
+ var eventType = typeof(TEvent);
+ if (!EventHandlers.ContainsKey(eventType))
+ {
+ EventHandlers.Add(eventType, new List());
+ }
+ EventHandlers[eventType].AddIfNotContains(typeof(TEventHandler));
+ }
+
+ public void MapMessage()
+ where TMessage : WeChatGeneralMessage
+ where TMessageHandler : IMessageHandleContributor
+ {
+ var eventType = typeof(TMessage);
+ if (!MessageHandlers.ContainsKey(eventType))
+ {
+ MessageHandlers.Add(eventType, new List());
+ }
+ MessageHandlers[eventType].AddIfNotContains(typeof(TMessageHandler));
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/IEventHandleContributor.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/IEventHandleContributor.cs
new file mode 100644
index 000000000..ed96a3617
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/IEventHandleContributor.cs
@@ -0,0 +1,7 @@
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+public interface IEventHandleContributor where TMessage : WeChatEventMessage
+{
+ Task HandleAsync(MessageHandleContext context);
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/IMessageHandleContributor.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/IMessageHandleContributor.cs
new file mode 100644
index 000000000..eb1b1bcf3
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/IMessageHandleContributor.cs
@@ -0,0 +1,8 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+public interface IMessageHandleContributor where TMessage : WeChatGeneralMessage
+{
+ Task HandleAsync(MessageHandleContext context);
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/IMessageHandler.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/IMessageHandler.cs
new file mode 100644
index 000000000..c2f52ba5a
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/IMessageHandler.cs
@@ -0,0 +1,10 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+public interface IMessageHandler
+{
+ Task HandleEventAsync(TMessage data) where TMessage : WeChatEventMessage;
+
+ Task HandleMessageAsync(TMessage data) where TMessage : WeChatGeneralMessage;
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/MessageHandleContext.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/MessageHandleContext.cs
new file mode 100644
index 000000000..e4ef78838
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/MessageHandleContext.cs
@@ -0,0 +1,14 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+public class MessageHandleContext where TMessage : WeChatMessage
+{
+ public TMessage Message { get; }
+ public IServiceProvider ServiceProvider { get; }
+ public MessageHandleContext(TMessage message, IServiceProvider serviceProvider)
+ {
+ Message = message;
+ ServiceProvider = serviceProvider;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/MessageHandler.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/MessageHandler.cs
new file mode 100644
index 000000000..97b2c4caa
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/Handlers/MessageHandler.cs
@@ -0,0 +1,54 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+public class MessageHandler : IMessageHandler, ITransientDependency
+{
+ private readonly IServiceScopeFactory _serviceScopeFactory;
+ private readonly AbpWeChatMessageHandleOptions _handleOptions;
+
+ public MessageHandler(
+ IServiceScopeFactory serviceScopeFactory,
+ IOptions handleOptions)
+ {
+ _serviceScopeFactory = serviceScopeFactory;
+ _handleOptions = handleOptions.Value;
+ }
+
+ public async virtual Task HandleEventAsync(TMessage data) where TMessage : WeChatEventMessage
+ {
+ if (_handleOptions.EventHandlers.TryGetValue(data.GetType(), out var handleTypes))
+ {
+ using var scope = _serviceScopeFactory.CreateScope();
+ foreach (var handleType in handleTypes)
+ {
+ var handlerService = ActivatorUtilities.CreateInstance(scope.ServiceProvider, handleType);
+ if (handlerService is IEventHandleContributor handler)
+ {
+ var context = new MessageHandleContext(data, scope.ServiceProvider);
+ await handler.HandleAsync(context);
+ }
+ }
+ }
+ }
+
+ public async virtual Task HandleMessageAsync(TMessage data) where TMessage : WeChatGeneralMessage
+ {
+ if (_handleOptions.MessageHandlers.TryGetValue(data.GetType(), out var handleTypes))
+ {
+ using var scope = _serviceScopeFactory.CreateScope();
+ foreach (var handleType in handleTypes)
+ {
+ var handlerService = ActivatorUtilities.CreateInstance(scope.ServiceProvider, handleType);
+ if (handlerService is IMessageHandleContributor handler)
+ {
+ var context = new MessageHandleContext(data, scope.ServiceProvider);
+ await handler.HandleAsync(context);
+ }
+ }
+ }
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolveContext.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolveContext.cs
new file mode 100644
index 000000000..f547f40b2
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolveContext.cs
@@ -0,0 +1,11 @@
+using System.Xml.Linq;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+public interface IMessageResolveContext : IServiceProviderAccessor
+{
+ string Origin { get; }
+ XDocument MessageData { get; }
+ bool Handled { get; set; }
+ WeChatMessage Message { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolveContextExtensions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolveContextExtensions.cs
new file mode 100644
index 000000000..3cc22d533
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolveContextExtensions.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+public static class IMessageResolveContextExtensions
+{
+ public static bool HasMessageKey(this IMessageResolveContext context, string key)
+ {
+ return context.MessageData.Root.Element(key) != null;
+ }
+
+ public static string GetMessageData(this IMessageResolveContext context, string key)
+ {
+ return context.MessageData.Root.Element(key)?.Value;
+ }
+
+ public static T GetWeChatMessage(this IMessageResolveContext context) where T : WeChatMessage
+ {
+ return context.Origin.DeserializeWeChatMessage();
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolveContributor.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolveContributor.cs
new file mode 100644
index 000000000..78bb587b6
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolveContributor.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+public interface IMessageResolveContributor
+{
+ string Name { get; }
+
+ Task ResolveAsync(IMessageResolveContext context);
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolver.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolver.cs
new file mode 100644
index 000000000..c708a2aa1
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/IMessageResolver.cs
@@ -0,0 +1,7 @@
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+public interface IMessageResolver
+{
+ Task ResolveMessageAsync(MessageResolveData messageData);
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveContext.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveContext.cs
new file mode 100644
index 000000000..3e042f18b
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveContext.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Xml.Linq;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+public class MessageResolveContext : IMessageResolveContext
+{
+ public IServiceProvider ServiceProvider { get; }
+ public string Origin { get; }
+ public XDocument MessageData { get; }
+ public bool Handled { get; set; }
+ public WeChatMessage Message { get; set; }
+
+ public bool HasResolvedMessage()
+ {
+ return Handled || Message != null;
+ }
+
+ public MessageResolveContext(
+ string origin,
+ XDocument messageData,
+ IServiceProvider serviceProvider)
+ {
+ Origin = origin;
+ MessageData = messageData;
+ ServiceProvider = serviceProvider;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveContributorBase.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveContributorBase.cs
new file mode 100644
index 000000000..088b67e21
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveContributorBase.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+public abstract class MessageResolveContributorBase : IMessageResolveContributor
+{
+ public abstract string Name { get; }
+
+ public abstract Task ResolveAsync(IMessageResolveContext context);
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveData.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveData.cs
new file mode 100644
index 000000000..0d353bf79
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveData.cs
@@ -0,0 +1,34 @@
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+public class MessageResolveData
+{
+ public string AppId { get; set; }
+
+ public string Token { get; set; }
+
+ public string EncodingAESKey { get; set; }
+
+ public string Signature { get; set; }
+
+ public int TimeStamp { get; set; }
+
+ public string Nonce { get; set; }
+
+ public string Data { get; set; }
+ public MessageResolveData(
+ string appId,
+ string token,
+ string encodingAESKey,
+ string signature,
+ int timeStamp,
+ string nonce,
+ string data)
+ {
+ AppId = appId;
+ Token = token;
+ EncodingAESKey = encodingAESKey;
+ Signature = signature;
+ TimeStamp = timeStamp;
+ Nonce = nonce;
+ Data = data;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveResult.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveResult.cs
new file mode 100644
index 000000000..d7259a7d9
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolveResult.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+public class MessageResolveResult
+{
+ public string Input { get; internal set; }
+
+ public WeChatMessage Message { get; set; }
+
+ public List AppliedResolvers { get; }
+
+ public MessageResolveResult(string input)
+ {
+ Input = input;
+ AppliedResolvers = new List();
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolver.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolver.cs
new file mode 100644
index 000000000..2cbdc49c6
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/MessageResolver.cs
@@ -0,0 +1,88 @@
+using LINGYUN.Abp.WeChat.Common.Crypto;
+using LINGYUN.Abp.WeChat.Common.Crypto.Models;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+public class MessageResolver : IMessageResolver, ITransientDependency
+{
+ private readonly IWeChatCryptoService _cryptoService;
+ private readonly IServiceProvider _serviceProvider;
+ private readonly AbpWeChatMessageResolveOptions _options;
+
+ public MessageResolver(
+ IOptions options,
+ IWeChatCryptoService cryptoService,
+ IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ _cryptoService = cryptoService;
+ _options = options.Value;
+ }
+ ///
+ /// 解析微信服务器推送消息/事件
+ ///
+ ///
+ ///
+ public async virtual Task ResolveMessageAsync(MessageResolveData messageData)
+ {
+ var result = new MessageResolveResult(messageData.Data);
+ using (var serviceScope = _serviceProvider.CreateScope())
+ {
+ /* 明文数据格式
+ *
+ *
+
+ 1699433172
+
+
+
+
+
+ */
+ var xmlDocument = XDocument.Parse(messageData.Data);
+ var encryptData = xmlDocument.Root.Element("Encrypt")?.Value;
+ if (!encryptData.IsNullOrWhiteSpace())
+ {
+ /* 加密数据格式
+ *
+ *
+
+
+ */
+ var cryptoDecryptData = new WeChatCryptoDecryptData(
+ encryptData,
+ messageData.AppId,
+ messageData.Token,
+ messageData.EncodingAESKey,
+ messageData.Signature,
+ messageData.TimeStamp.ToString(),
+ messageData.Nonce);
+ // 经过解密函数得到如上真实数据
+ var decryptMessage = _cryptoService.Decrypt(cryptoDecryptData);
+ xmlDocument = XDocument.Parse(decryptMessage);
+ result.Input = decryptMessage;
+ }
+
+ var context = new MessageResolveContext(result.Input, xmlDocument, serviceScope.ServiceProvider);
+
+ foreach (var messageResolver in _options.MessageResolvers)
+ {
+ await messageResolver.ResolveAsync(context);
+
+ result.AppliedResolvers.Add(messageResolver.Name);
+
+ if (context.HasResolvedMessage())
+ {
+ result.Message = context.Message;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatEventMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatEventMessage.cs
new file mode 100644
index 000000000..7d725a604
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatEventMessage.cs
@@ -0,0 +1,14 @@
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+///
+/// 微信事件消息
+///
+public abstract class WeChatEventMessage : WeChatMessage
+{
+ ///
+ /// 事件类型
+ ///
+ [XmlElement("Event")]
+ public string Event { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatGeneralMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatGeneralMessage.cs
new file mode 100644
index 000000000..c40c9eba7
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatGeneralMessage.cs
@@ -0,0 +1,14 @@
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+///
+/// 微信普通消息
+///
+public abstract class WeChatGeneralMessage : WeChatMessage
+{
+ ///
+ /// 消息id,64位整型
+ ///
+ [XmlElement("MsgId")]
+ public long MsgId { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatMessage.cs
new file mode 100644
index 000000000..558ed61d8
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatMessage.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+///
+/// 微信消息
+///
+[Serializable]
+[XmlRoot("xml")]
+public abstract class WeChatMessage
+{
+ ///
+ /// 开发者微信号
+ ///
+ [XmlElement("ToUserName")]
+ public string ToUserName { get; set; }
+ ///
+ /// 发送方账号(一个OpenID)
+ ///
+ [XmlElement("FromUserName")]
+ public string FromUserName { get; set; }
+ ///
+ /// 消息创建时间 (整型)
+ ///
+ [XmlElement("CreateTime")]
+ public int CreateTime { get; set; }
+ ///
+ /// 消息类型,event
+ ///
+ [XmlElement("MsgType")]
+ public string MsgType { get; set; }
+
+ public abstract WeChatMessageEto ToEto();
+
+ public virtual string SerializeToJson()
+ {
+ return WeChatObjectSerializeExtensions.SerializeToJson(this);
+ }
+
+ public virtual string SerializeToXml()
+ {
+ return this.SerializeWeChatMessage();
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatMessageEto.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatMessageEto.cs
new file mode 100644
index 000000000..c5612ab91
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Messages/WeChatMessageEto.cs
@@ -0,0 +1,7 @@
+using Volo.Abp.Domain.Entities.Events.Distributed;
+
+namespace LINGYUN.Abp.WeChat.Common.Messages;
+
+public abstract class WeChatMessageEto : EtoBase
+{
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Security/Claims/AbpWeChatClaimTypes.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Security/Claims/AbpWeChatClaimTypes.cs
similarity index 97%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Security/Claims/AbpWeChatClaimTypes.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Security/Claims/AbpWeChatClaimTypes.cs
index 5f1181da3..4407215ee 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Security/Claims/AbpWeChatClaimTypes.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Security/Claims/AbpWeChatClaimTypes.cs
@@ -1,4 +1,4 @@
-namespace LINGYUN.Abp.WeChat.Security.Claims
+namespace LINGYUN.Abp.WeChat.Common.Security.Claims
{
///
/// 微信认证身份类型,可以像 自行配置
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Utils/Cryptography.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Utils/Cryptography.cs
similarity index 64%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Utils/Cryptography.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Utils/Cryptography.cs
index 35f014b7f..7ef1e2cd7 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Utils/Cryptography.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Utils/Cryptography.cs
@@ -6,23 +6,23 @@ using System.Security.Cryptography;
using System.IO;
using System.Net;
-namespace LINGYUN.Abp.WeChat.Work.Utils
+namespace LINGYUN.Abp.WeChat.Common.Utils
{
- internal class Cryptography
+ public class Cryptography
{
- public static UInt32 HostToNetworkOrder(UInt32 inval)
+ public static uint HostToNetworkOrder(uint inval)
{
- UInt32 outval = 0;
- for (int i = 0; i < 4; i++)
- outval = (outval << 8) + ((inval >> (i * 8)) & 255);
+ uint outval = 0;
+ for (var i = 0; i < 4; i++)
+ outval = (outval << 8) + (inval >> i * 8 & 255);
return outval;
}
- public static Int32 HostToNetworkOrder(Int32 inval)
+ public static int HostToNetworkOrder(int inval)
{
- Int32 outval = 0;
- for (int i = 0; i < 4; i++)
- outval = (outval << 8) + ((inval >> (i * 8)) & 255);
+ var outval = 0;
+ for (var i = 0; i < 4; i++)
+ outval = (outval << 8) + (inval >> i * 8 & 255);
return outval;
}
///
@@ -32,62 +32,62 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
///
///
///
- public static string AES_decrypt(String Input, string EncodingAESKey, ref string corpid)
+ public static string AES_decrypt(string Input, string EncodingAESKey, ref string corpid)
{
byte[] Key;
Key = Convert.FromBase64String(EncodingAESKey + "=");
- byte[] Iv = new byte[16];
+ var Iv = new byte[16];
Array.Copy(Key, Iv, 16);
- byte[] btmpMsg = AES_decrypt(Input, Iv, Key);
+ var btmpMsg = AES_decrypt(Input, Iv, Key);
- int len = BitConverter.ToInt32(btmpMsg, 16);
+ var len = BitConverter.ToInt32(btmpMsg, 16);
len = IPAddress.NetworkToHostOrder(len);
- byte[] bMsg = new byte[len];
- byte[] bCorpid = new byte[btmpMsg.Length - 20 - len];
+ var bMsg = new byte[len];
+ var bCorpid = new byte[btmpMsg.Length - 20 - len];
Array.Copy(btmpMsg, 20, bMsg, 0, len);
- Array.Copy(btmpMsg, 20+len , bCorpid, 0, btmpMsg.Length - 20 - len);
- string oriMsg = Encoding.UTF8.GetString(bMsg);
+ Array.Copy(btmpMsg, 20 + len, bCorpid, 0, btmpMsg.Length - 20 - len);
+ var oriMsg = Encoding.UTF8.GetString(bMsg);
corpid = Encoding.UTF8.GetString(bCorpid);
-
+
return oriMsg;
}
- public static String AES_encrypt(String Input, string EncodingAESKey, string corpid)
+ public static string AES_encrypt(string Input, string EncodingAESKey, string corpid)
{
byte[] Key;
Key = Convert.FromBase64String(EncodingAESKey + "=");
- byte[] Iv = new byte[16];
+ var Iv = new byte[16];
Array.Copy(Key, Iv, 16);
- string Randcode = CreateRandCode(16);
- byte[] bRand = Encoding.UTF8.GetBytes(Randcode);
- byte[] bCorpid = Encoding.UTF8.GetBytes(corpid);
- byte[] btmpMsg = Encoding.UTF8.GetBytes(Input);
- byte[] bMsgLen = BitConverter.GetBytes(HostToNetworkOrder(btmpMsg.Length));
- byte[] bMsg = new byte[bRand.Length + bMsgLen.Length + bCorpid.Length + btmpMsg.Length];
+ var Randcode = CreateRandCode(16);
+ var bRand = Encoding.UTF8.GetBytes(Randcode);
+ var bCorpid = Encoding.UTF8.GetBytes(corpid);
+ var btmpMsg = Encoding.UTF8.GetBytes(Input);
+ var bMsgLen = BitConverter.GetBytes(HostToNetworkOrder(btmpMsg.Length));
+ var bMsg = new byte[bRand.Length + bMsgLen.Length + bCorpid.Length + btmpMsg.Length];
Array.Copy(bRand, bMsg, bRand.Length);
Array.Copy(bMsgLen, 0, bMsg, bRand.Length, bMsgLen.Length);
Array.Copy(btmpMsg, 0, bMsg, bRand.Length + bMsgLen.Length, btmpMsg.Length);
Array.Copy(bCorpid, 0, bMsg, bRand.Length + bMsgLen.Length + btmpMsg.Length, bCorpid.Length);
-
+
return AES_encrypt(bMsg, Iv, Key);
}
private static string CreateRandCode(int codeLen)
{
- string codeSerial = "2,3,4,5,6,7,a,c,d,e,f,h,i,j,k,m,n,p,r,s,t,A,C,D,E,F,G,H,J,K,M,N,P,Q,R,S,U,V,W,X,Y,Z";
+ var codeSerial = "2,3,4,5,6,7,a,c,d,e,f,h,i,j,k,m,n,p,r,s,t,A,C,D,E,F,G,H,J,K,M,N,P,Q,R,S,U,V,W,X,Y,Z";
if (codeLen == 0)
{
codeLen = 16;
}
- string[] arr = codeSerial.Split(',');
- string code = "";
- int randValue = -1;
- Random rand = new Random(unchecked((int)DateTime.Now.Ticks));
- for (int i = 0; i < codeLen; i++)
+ var arr = codeSerial.Split(',');
+ var code = "";
+ var randValue = -1;
+ var rand = new Random(unchecked((int)DateTime.Now.Ticks));
+ for (var i = 0; i < codeLen; i++)
{
randValue = rand.Next(0, arr.Length - 1);
code += arr[randValue];
@@ -95,7 +95,7 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
return code;
}
- private static String AES_encrypt(String Input, byte[] Iv, byte[] Key)
+ private static string AES_encrypt(string Input, byte[] Iv, byte[] Key)
{
var aes = new RijndaelManaged();
//秘钥的大小,以位为单位
@@ -114,16 +114,16 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
{
using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
{
- byte[] xXml = Encoding.UTF8.GetBytes(Input);
+ var xXml = Encoding.UTF8.GetBytes(Input);
cs.Write(xXml, 0, xXml.Length);
}
xBuff = ms.ToArray();
}
- String Output = Convert.ToBase64String(xBuff);
+ var Output = Convert.ToBase64String(xBuff);
return Output;
}
- private static String AES_encrypt(byte[] Input, byte[] Iv, byte[] Key)
+ private static string AES_encrypt(byte[] Input, byte[] Iv, byte[] Key)
{
var aes = new RijndaelManaged();
//秘钥的大小,以位为单位
@@ -140,9 +140,9 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
byte[] xBuff = null;
#region 自己进行PKCS7补位,用系统自己带的不行
- byte[] msg = new byte[Input.Length + 32 - Input.Length % 32];
+ var msg = new byte[Input.Length + 32 - Input.Length % 32];
Array.Copy(Input, msg, Input.Length);
- byte[] pad = KCS7Encoder(Input.Length);
+ var pad = KCS7Encoder(Input.Length);
Array.Copy(pad, 0, msg, Input.Length, pad.Length);
#endregion
@@ -160,23 +160,23 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
xBuff = ms.ToArray();
}
- String Output = Convert.ToBase64String(xBuff);
+ var Output = Convert.ToBase64String(xBuff);
return Output;
}
private static byte[] KCS7Encoder(int text_length)
{
- int block_size = 32;
+ var block_size = 32;
// 计算需要填充的位数
- int amount_to_pad = block_size - (text_length % block_size);
+ var amount_to_pad = block_size - text_length % block_size;
if (amount_to_pad == 0)
{
amount_to_pad = block_size;
}
// 获得补位所用的字符
- char pad_chr = chr(amount_to_pad);
- string tmp = "";
- for (int index = 0; index < amount_to_pad; index++)
+ var pad_chr = chr(amount_to_pad);
+ var tmp = "";
+ for (var index = 0; index < amount_to_pad; index++)
{
tmp += pad_chr;
}
@@ -191,12 +191,12 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
static char chr(int a)
{
- byte target = (byte)(a & 0xFF);
+ var target = (byte)(a & 0xFF);
return (char)target;
}
- private static byte[] AES_decrypt(String Input, byte[] Iv, byte[] Key)
+ private static byte[] AES_decrypt(string Input, byte[] Iv, byte[] Key)
{
- RijndaelManaged aes = new RijndaelManaged();
+ var aes = new RijndaelManaged();
aes.KeySize = 256;
aes.BlockSize = 128;
aes.Mode = CipherMode.CBC;
@@ -209,8 +209,8 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
{
using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
{
- byte[] xXml = Convert.FromBase64String(Input);
- byte[] msg = new byte[xXml.Length + 32 - xXml.Length % 32];
+ var xXml = Convert.FromBase64String(Input);
+ var msg = new byte[xXml.Length + 32 - xXml.Length % 32];
Array.Copy(xXml, msg, xXml.Length);
cs.Write(xXml, 0, xXml.Length);
}
@@ -220,12 +220,12 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
}
private static byte[] decode2(byte[] decrypted)
{
- int pad = (int)decrypted[decrypted.Length - 1];
+ var pad = (int)decrypted[decrypted.Length - 1];
if (pad < 1 || pad > 32)
{
pad = 0;
}
- byte[] res = new byte[decrypted.Length - pad];
+ var res = new byte[decrypted.Length - pad];
Array.Copy(decrypted, 0, res, 0, decrypted.Length - pad);
return res;
}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Utils/WXBizMsgCrypt.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Utils/WXBizMsgCrypt.cs
similarity index 79%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Utils/WXBizMsgCrypt.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Utils/WXBizMsgCrypt.cs
index 7d34d817c..7a2068f72 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Utils/WXBizMsgCrypt.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/Utils/WXBizMsgCrypt.cs
@@ -16,9 +16,9 @@ using System.Security.Cryptography;
//-40008 : 解密后得到的buffer非法
//-40009 : base64加密异常
//-40010 : base64解密异常
-namespace LINGYUN.Abp.WeChat.Work.Utils
+namespace LINGYUN.Abp.WeChat.Common.Utils
{
- internal class WXBizMsgCrypt
+ public class WXBizMsgCrypt
{
string m_sToken;
string m_sEncodingAESKey;
@@ -39,9 +39,9 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
};
//构造函数
- // @param sToken: 企业微信后台,开发者设置的Token
- // @param sEncodingAESKey: 企业微信后台,开发者设置的EncodingAESKey
- // @param sReceiveId: 不同场景含义不同,详见文档说明
+ // @param sToken: 企业微信后台,开发者设置的Token
+ // @param sEncodingAESKey: 企业微信后台,开发者设置的EncodingAESKey
+ // @param sReceiveId: 不同场景含义不同,详见文档说明
public WXBizMsgCrypt(string sToken, string sEncodingAESKey, string sReceiveId)
{
m_sToken = sToken;
@@ -58,18 +58,18 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
// @return:成功0,失败返回对应的错误码
public int VerifyURL(string sMsgSignature, string sTimeStamp, string sNonce, string sEchoStr, ref string sReplyEchoStr)
{
- int ret = 0;
- if (m_sEncodingAESKey.Length!=43)
- {
- return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
- }
+ var ret = 0;
+ if (m_sEncodingAESKey.Length != 43)
+ {
+ return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
+ }
ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEchoStr, sMsgSignature);
if (0 != ret)
{
return ret;
}
sReplyEchoStr = "";
- string cpid = "";
+ var cpid = "";
try
{
sReplyEchoStr = Cryptography.AES_decrypt(sEchoStr, m_sEncodingAESKey, ref cpid); //m_sReceiveId);
@@ -96,11 +96,11 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
// @return: 成功0,失败返回对应的错误码
public int DecryptMsg(string sMsgSignature, string sTimeStamp, string sNonce, string sPostData, ref string sMsg)
{
- if (m_sEncodingAESKey.Length!=43)
- {
- return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
- }
- XmlDocument doc = new XmlDocument();
+ if (m_sEncodingAESKey.Length != 43)
+ {
+ return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
+ }
+ var doc = new XmlDocument();
XmlNode root;
string sEncryptMsg;
try
@@ -114,12 +114,12 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_ParseXml_Error;
}
//verify signature
- int ret = 0;
+ var ret = 0;
ret = VerifySignature(m_sToken, sTimeStamp, sNonce, sEncryptMsg, sMsgSignature);
if (ret != 0)
return ret;
//decrypt
- string cpid = "";
+ var cpid = "";
try
{
sMsg = Cryptography.AES_decrypt(sEncryptMsg, m_sEncodingAESKey, ref cpid);
@@ -148,11 +148,11 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
// return:成功0,失败返回对应的错误码
public int EncryptMsg(string sReplyMsg, string sTimeStamp, string sNonce, ref string sEncryptMsg)
{
- if (m_sEncodingAESKey.Length!=43)
- {
- return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
- }
- string raw = "";
+ if (m_sEncodingAESKey.Length != 43)
+ {
+ return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_IllegalAesKey;
+ }
+ var raw = "";
try
{
raw = Cryptography.AES_encrypt(sReplyMsg, m_sEncodingAESKey, m_sReceiveId);
@@ -161,21 +161,21 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
{
return (int)WXBizMsgCryptErrorCode.WXBizMsgCrypt_EncryptAES_Error;
}
- string MsgSigature = "";
- int ret = 0;
+ var MsgSigature = "";
+ var ret = 0;
ret = GenarateSinature(m_sToken, sTimeStamp, sNonce, raw, ref MsgSigature);
if (0 != ret)
return ret;
sEncryptMsg = "";
- string EncryptLabelHead = "";
- string MsgSigLabelHead = "";
- string TimeStampLabelHead = "";
- string NonceLabelHead = "";
+ var EncryptLabelHead = "";
+ var MsgSigLabelHead = "";
+ var TimeStampLabelHead = "";
+ var NonceLabelHead = "";
sEncryptMsg = sEncryptMsg + "" + EncryptLabelHead + raw + EncryptLabelTail;
sEncryptMsg = sEncryptMsg + MsgSigLabelHead + MsgSigature + MsgSigLabelTail;
sEncryptMsg = sEncryptMsg + TimeStampLabelHead + sTimeStamp + TimeStampLabelTail;
@@ -184,15 +184,15 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
return 0;
}
- public class DictionarySort : System.Collections.IComparer
+ public class DictionarySort : IComparer
{
public int Compare(object oLeft, object oRight)
{
- string sLeft = oLeft as string;
- string sRight = oRight as string;
- int iLeftLength = sLeft.Length;
- int iRightLength = sRight.Length;
- int index = 0;
+ var sLeft = oLeft as string;
+ var sRight = oRight as string;
+ var iLeftLength = sLeft.Length;
+ var iRightLength = sRight.Length;
+ var index = 0;
while (index < iLeftLength && index < iRightLength)
{
if (sLeft[index] < sRight[index])
@@ -209,8 +209,8 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
//Verify Signature
private static int VerifySignature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt, string sSigture)
{
- string hash = "";
- int ret = 0;
+ var hash = "";
+ var ret = 0;
ret = GenarateSinature(sToken, sTimeStamp, sNonce, sMsgEncrypt, ref hash);
if (ret != 0)
return ret;
@@ -222,29 +222,29 @@ namespace LINGYUN.Abp.WeChat.Work.Utils
}
}
- public static int GenarateSinature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt ,ref string sMsgSignature)
+ public static int GenarateSinature(string sToken, string sTimeStamp, string sNonce, string sMsgEncrypt, ref string sMsgSignature)
{
- ArrayList AL = new ArrayList();
+ var AL = new ArrayList();
AL.Add(sToken);
AL.Add(sTimeStamp);
AL.Add(sNonce);
AL.Add(sMsgEncrypt);
AL.Sort(new DictionarySort());
- string raw = "";
- for (int i = 0; i < AL.Count; ++i)
+ var raw = "";
+ for (var i = 0; i < AL.Count; ++i)
{
raw += AL[i];
}
SHA1 sha;
ASCIIEncoding enc;
- string hash = "";
+ var hash = "";
try
{
sha = new SHA1CryptoServiceProvider();
enc = new ASCIIEncoding();
- byte[] dataToHash = enc.GetBytes(raw);
- byte[] dataHashed = sha.ComputeHash(dataToHash);
+ var dataToHash = enc.GetBytes(raw);
+ var dataHashed = sha.ComputeHash(dataToHash);
hash = BitConverter.ToString(dataHashed).Replace("-", "");
hash = hash.ToLower();
}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/WeChatCommonErrorCodes.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/WeChatCommonErrorCodes.cs
new file mode 100644
index 000000000..4fa43dab3
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/LINGYUN/Abp/WeChat/Common/WeChatCommonErrorCodes.cs
@@ -0,0 +1,5 @@
+namespace LINGYUN.Abp.WeChat.Common;
+public static class WeChatCommonErrorCodes
+{
+ public const string Namespace = "WeChatCommon";
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/README.md b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/README.md
new file mode 100644
index 000000000..d16a17a72
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/README.md
@@ -0,0 +1,30 @@
+# LINGYUN.Abp.WeChat.Common
+
+## 模块说明
+
+由于微信体系众多产品部分功能有共同点, 抽象一个通用模块, 实现一些通用的接口.
+
+### 基础模块
+
+### 高阶模块
+
+### 权限定义
+
+### 功能定义
+
+### 配置定义
+
+### 如何使用
+
+
+```csharp
+
+ [DependsOn(
+ typeof(AbpWeChatCommonModule))]
+ public class YouProjectModule : AbpModule
+ {
+ }
+
+```
+
+### 更新日志
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/System/WeChatObjectSerializeExtensions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/System/WeChatObjectSerializeExtensions.cs
new file mode 100644
index 000000000..450e21310
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/System/WeChatObjectSerializeExtensions.cs
@@ -0,0 +1,10 @@
+using Newtonsoft.Json;
+
+namespace System;
+internal static class WeChatObjectSerializeExtensions
+{
+ public static string SerializeToJson(this object @object)
+ {
+ return JsonConvert.SerializeObject(@object);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/System/WeChatXmlDataSerializeExtensions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/System/WeChatXmlDataSerializeExtensions.cs
new file mode 100644
index 000000000..be11aeb99
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Common/System/WeChatXmlDataSerializeExtensions.cs
@@ -0,0 +1,66 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Collections;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Xml;
+using System.Xml.Serialization;
+
+namespace System;
+public static class WeChatXmlDataSerializeExtensions
+{
+ private readonly static Hashtable _xmlSerializers = new();
+ private readonly static XmlRootAttribute _xmlRoot = new("xml");
+
+ private static XmlSerializer GetTypedSerializer(Type type)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException(nameof(type));
+ }
+
+ var skey = type.AssemblyQualifiedName ?? type.GetHashCode().ToString();
+ if (_xmlSerializers[skey] is not XmlSerializer xmlSerializer)
+ {
+ xmlSerializer = new XmlSerializer(type, _xmlRoot);
+ _xmlSerializers[skey] = xmlSerializer;
+ }
+
+ return xmlSerializer;
+ }
+
+ public static T DeserializeWeChatMessage(this string xml, XmlDeserializationEvents? events = null) where T : WeChatMessage
+ {
+ var objectType = typeof(T);
+ using var stringReader = new StringReader(xml);
+ using var xmlReader = XmlReader.Create(stringReader);
+ var serializer = GetTypedSerializer(objectType);
+ var usingEvents = events ?? new XmlDeserializationEvents();
+ return (T)serializer.Deserialize(xmlReader, usingEvents);
+ }
+
+ public static string SerializeWeChatMessage(this WeChatMessage message)
+ {
+ var objectType = message.GetType();
+ var settings = new XmlWriterSettings
+ {
+ Encoding = Encoding.UTF8,
+ Indent = false,
+ OmitXmlDeclaration = true,
+ WriteEndDocumentOnClose = false,
+ NamespaceHandling = NamespaceHandling.OmitDuplicates
+ };
+ using var stream = new MemoryStream();
+ using var writer = XmlWriter.Create(stream, settings);
+ var serializer = GetTypedSerializer(objectType);
+ var ns = new XmlSerializerNamespaces();
+ ns.Add(string.Empty, string.Empty);
+ serializer.Serialize(writer, message, ns);
+ writer.Flush();
+ var xml = Encoding.UTF8.GetString(stream.ToArray());
+ xml = Regex.Replace(xml, "\\s*<\\w+ ([a-zA-Z0-9]+):nil=\"true\"[^>]*/>", string.Empty, RegexOptions.IgnoreCase);
+ xml = Regex.Replace(xml, "<\\?xml[^>]*\\?>", string.Empty, RegexOptions.IgnoreCase);
+
+ return xml;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/FodyWeavers.xml b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/FodyWeavers.xsd b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/FodyWeavers.xsd
new file mode 100644
index 000000000..3f3946e28
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN.Abp.WeChat.Official.Application.Contracts.csproj b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN.Abp.WeChat.Official.Application.Contracts.csproj
new file mode 100644
index 000000000..20daae9cc
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN.Abp.WeChat.Official.Application.Contracts.csproj
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialApplicationContractsModule.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialApplicationContractsModule.cs
new file mode 100644
index 000000000..7734f4a3f
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialApplicationContractsModule.cs
@@ -0,0 +1,10 @@
+using Volo.Abp.Application;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.WeChat.Official;
+
+[DependsOn(
+ typeof(AbpDddApplicationContractsModule))]
+public class AbpWeChatOfficialApplicationContractsModule : AbpModule
+{
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialRemoteServiceConsts.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialRemoteServiceConsts.cs
new file mode 100644
index 000000000..faec482a5
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialRemoteServiceConsts.cs
@@ -0,0 +1,8 @@
+namespace LINGYUN.Abp.WeChat.Official;
+
+public class AbpWeChatOfficialRemoteServiceConsts
+{
+ public const string RemoteServiceName = "AbpWeChatOfficial";
+
+ public const string ModuleName = "wechat-official";
+}
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Account/Dto/ParametricQrCodeGenerateInput.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Account/Dto/ParametricQrCodeGenerateInput.cs
new file mode 100644
index 000000000..e1b0dc2b8
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Account/Dto/ParametricQrCodeGenerateInput.cs
@@ -0,0 +1,5 @@
+namespace LINGYUN.Abp.WeChat.Official.Account;
+public class ParametricQrCodeGenerateInput
+{
+ public int SceneEnum { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Account/IParametricQrCodeAppService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Account/IParametricQrCodeAppService.cs
new file mode 100644
index 000000000..3961663ed
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Account/IParametricQrCodeAppService.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Content;
+
+namespace LINGYUN.Abp.WeChat.Official.Account;
+public interface IParametricQrCodeAppService : IApplicationService
+{
+ Task GenerateAsync(ParametricQrCodeGenerateInput input);
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Message/Dto/MessageHandleInput.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Message/Dto/MessageHandleInput.cs
new file mode 100644
index 000000000..317005143
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Message/Dto/MessageHandleInput.cs
@@ -0,0 +1,10 @@
+using LINGYUN.Abp.WeChat.Official.Models;
+using System;
+
+namespace LINGYUN.Abp.WeChat.Official.Message;
+
+[Serializable]
+public class MessageHandleInput : WeChatMessage
+{
+ public string Data { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Message/Dto/MessageValidationInput.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Message/Dto/MessageValidationInput.cs
new file mode 100644
index 000000000..0929bf76b
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Message/Dto/MessageValidationInput.cs
@@ -0,0 +1,12 @@
+using LINGYUN.Abp.WeChat.Official.Models;
+using System.Text.Json.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Official.Message;
+public class MessageValidationInput : WeChatMessage
+{
+ ///
+ /// 加密的字符串。需要解密得到消息内容明文,解密后有random、msg_len、msg、receiveid四个字段,其中msg即为消息内容明文
+ ///
+ [JsonPropertyName("echostr")]
+ public string EchoStr { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Message/IWeChatMessageAppService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Message/IWeChatMessageAppService.cs
new file mode 100644
index 000000000..1e70831d0
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Message/IWeChatMessageAppService.cs
@@ -0,0 +1,28 @@
+using System.Threading.Tasks;
+using Volo.Abp.Application.Services;
+
+namespace LINGYUN.Abp.WeChat.Official.Message;
+///
+/// 微信消息接口
+///
+public interface IWeChatMessageAppService : IApplicationService
+{
+ ///
+ /// 校验微信消息
+ ///
+ ///
+ /// 参考文档:
+ ///
+ ///
+ ///
+ Task Handle(MessageValidationInput input);
+ ///
+ /// 处理微信消息
+ ///
+ ///
+ /// 参考文档:
+ ///
+ ///
+ ///
+ Task Handle(MessageHandleInput input);
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Models/WeChatMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Models/WeChatMessage.cs
new file mode 100644
index 000000000..150abf143
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application.Contracts/LINGYUN/Abp/WeChat/Official/Models/WeChatMessage.cs
@@ -0,0 +1,25 @@
+using System.Text.Json.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Official.Models;
+public class WeChatMessage
+{
+ ///
+ /// 微信加密签名,
+ /// signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数
+ ///
+ ///
+ /// 签名计算方法参考: https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/Before_Develop/Message_encryption_and_decryption.html
+ ///
+ [JsonPropertyName("signature")]
+ public string Signature { get; set; }
+ ///
+ /// 时间戳。与nonce结合使用,用于防止请求重放攻击。
+ ///
+ [JsonPropertyName("timestamp")]
+ public int TimeStamp { get; set; }
+ ///
+ /// 随机数。与timestamp结合使用,用于防止请求重放攻击。
+ ///
+ [JsonPropertyName("nonce")]
+ public string Nonce { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/FodyWeavers.xml b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/FodyWeavers.xsd b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/FodyWeavers.xsd
new file mode 100644
index 000000000..3f3946e28
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN.Abp.WeChat.Official.Application.csproj b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN.Abp.WeChat.Official.Application.csproj
new file mode 100644
index 000000000..72e0f91c5
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN.Abp.WeChat.Official.Application.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialApplicationModule.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialApplicationModule.cs
new file mode 100644
index 000000000..458022a16
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialApplicationModule.cs
@@ -0,0 +1,13 @@
+using Volo.Abp.Application;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.WeChat.Official;
+
+[DependsOn(
+ typeof(AbpWeChatOfficialApplicationContractsModule),
+ typeof(AbpWeChatOfficialModule),
+ typeof(AbpDddApplicationModule))]
+public class AbpWeChatOfficialApplicationModule : AbpModule
+{
+
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN/Abp/WeChat/Official/Account/ParametricQrCodeAppService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN/Abp/WeChat/Official/Account/ParametricQrCodeAppService.cs
new file mode 100644
index 000000000..7d6720ae7
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN/Abp/WeChat/Official/Account/ParametricQrCodeAppService.cs
@@ -0,0 +1,24 @@
+using LINGYUN.Abp.WeChat.Official.Account.Models;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Services;
+using Volo.Abp.Content;
+
+namespace LINGYUN.Abp.WeChat.Official.Account;
+public class ParametricQrCodeAppService : ApplicationService, IParametricQrCodeAppService
+{
+ private readonly IParametricQrCodeGenerator _qrCodeGenerator;
+
+ public ParametricQrCodeAppService(IParametricQrCodeGenerator qrCodeGenerator)
+ {
+ _qrCodeGenerator = qrCodeGenerator;
+ }
+
+ public async virtual Task GenerateAsync(ParametricQrCodeGenerateInput input)
+ {
+ var createTicketModel = CreateTicketModel.EnumScene(input.SceneEnum);
+ var ticketModel = await _qrCodeGenerator.CreateTicketAsync(createTicketModel);
+ var stream = await _qrCodeGenerator.ShowQrCodeAsync(ticketModel.Ticket);
+
+ return new RemoteStreamContent(stream);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN/Abp/WeChat/Official/Message/WeChatMessageAppService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN/Abp/WeChat/Official/Message/WeChatMessageAppService.cs
new file mode 100644
index 000000000..bc4096c6b
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.Application/LINGYUN/Abp/WeChat/Official/Message/WeChatMessageAppService.cs
@@ -0,0 +1,85 @@
+using LINGYUN.Abp.WeChat.Common.Crypto;
+using LINGYUN.Abp.WeChat.Common.Crypto.Models;
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Microsoft.Extensions.Logging;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.Application.Services;
+using Volo.Abp.EventBus.Distributed;
+
+namespace LINGYUN.Abp.WeChat.Official.Message;
+public class WeChatMessageAppService : ApplicationService, IWeChatMessageAppService
+{
+ private readonly IWeChatCryptoService _cryptoService;
+ private readonly AbpWeChatOfficialOptionsFactory _optionsFactory;
+ private readonly IDistributedEventBus _distributedEventBus;
+ private readonly IMessageResolver _messageResolver;
+ public WeChatMessageAppService(
+ IMessageResolver messageResolver,
+ IWeChatCryptoService cryptoService,
+ IDistributedEventBus distributedEventBus,
+ AbpWeChatOfficialOptionsFactory optionsFactory)
+ {
+ _cryptoService = cryptoService;
+ _optionsFactory = optionsFactory;
+ _messageResolver = messageResolver;
+ _distributedEventBus = distributedEventBus;
+ }
+
+ public async virtual Task Handle(MessageValidationInput input)
+ {
+ var options = await _optionsFactory.CreateAsync();
+
+ Check.NotNull(options, nameof(options));
+
+ // 沙盒测试时,无需验证消息
+ if (options.IsSandBox)
+ {
+ return input.EchoStr;
+ }
+
+ var echoData = new WeChatCryptoEchoData(
+ input.EchoStr,
+ options.AppId,
+ options.Token,
+ options.EncodingAESKey,
+ input.Signature,
+ input.TimeStamp.ToString(),
+ input.Nonce);
+
+ var echoStr = _cryptoService.Validation(echoData);
+
+ return echoStr;
+ }
+
+ public async virtual Task Handle(MessageHandleInput input)
+ {
+ var options = await _optionsFactory.CreateAsync();
+
+ Check.NotNull(options, nameof(options));
+
+ var messageData = new MessageResolveData(
+ options.AppId,
+ options.Token,
+ options.EncodingAESKey,
+ input.Signature,
+ input.TimeStamp,
+ input.Nonce,
+ input.Data);
+
+ var result = await _messageResolver.ResolveMessageAsync(messageData);
+ if (result.Message == null)
+ {
+ Logger.LogWarning(input.Data);
+ Logger.LogWarning("解析消息失败, 无法处理微信消息.");
+ }
+ else
+ {
+ Logger.LogInformation(result.Message.SerializeToXml());
+ var eto = result.Message.ToEto();
+ await _distributedEventBus.PublishAsync(eto.GetType(), eto);
+ }
+ // https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html
+ return "success";
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/FodyWeavers.xml b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/FodyWeavers.xml
new file mode 100644
index 000000000..1715698cc
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/FodyWeavers.xsd b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/FodyWeavers.xsd
new file mode 100644
index 000000000..3f3946e28
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/FodyWeavers.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN.Abp.WeChat.Official.HttpApi.csproj b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN.Abp.WeChat.Official.HttpApi.csproj
new file mode 100644
index 000000000..44178a95d
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN.Abp.WeChat.Official.HttpApi.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ net7.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialHttpApiModule.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialHttpApiModule.cs
new file mode 100644
index 000000000..cf3ea0ab8
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialHttpApiModule.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.WeChat.Official;
+
+[DependsOn(
+ typeof(AbpWeChatOfficialApplicationContractsModule),
+ typeof(AbpAspNetCoreMvcModule))]
+public class AbpWeChatOfficialHttpApiModule : AbpModule
+{
+ public override void PreConfigureServices(ServiceConfigurationContext context)
+ {
+ PreConfigure(mvcBuilder =>
+ {
+ mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpWeChatOfficialHttpApiModule).Assembly);
+ });
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN/Abp/WeChat/Official/Account/ParametricQrCodeController.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN/Abp/WeChat/Official/Account/ParametricQrCodeController.cs
new file mode 100644
index 000000000..e1062aae4
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN/Abp/WeChat/Official/Account/ParametricQrCodeController.cs
@@ -0,0 +1,28 @@
+using Microsoft.AspNetCore.Mvc;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.Content;
+
+namespace LINGYUN.Abp.WeChat.Official.Account;
+
+[Controller]
+[RemoteService(Name = AbpWeChatOfficialRemoteServiceConsts.RemoteServiceName)]
+[Area(AbpWeChatOfficialRemoteServiceConsts.ModuleName)]
+[Route("api/wechat/official/account/parametric-qrcode")]
+public class ParametricQrCodeController : AbpControllerBase, IParametricQrCodeAppService
+{
+ private readonly IParametricQrCodeAppService _service;
+
+ public ParametricQrCodeController(IParametricQrCodeAppService service)
+ {
+ _service = service;
+ }
+
+ [HttpPost]
+ [Route("generate")]
+ public virtual Task GenerateAsync(ParametricQrCodeGenerateInput input)
+ {
+ return _service.GenerateAsync(input);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN/Abp/WeChat/Official/Message/WeChatMessageController.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN/Abp/WeChat/Official/Message/WeChatMessageController.cs
new file mode 100644
index 000000000..1d15902cd
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official.HttpApi/LINGYUN/Abp/WeChat/Official/Message/WeChatMessageController.cs
@@ -0,0 +1,39 @@
+using Microsoft.AspNetCore.Mvc;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using Volo.Abp;
+using Volo.Abp.AspNetCore.Mvc;
+
+namespace LINGYUN.Abp.WeChat.Official.Message;
+
+[Controller]
+[RemoteService(Name = AbpWeChatOfficialRemoteServiceConsts.RemoteServiceName)]
+[Area(AbpWeChatOfficialRemoteServiceConsts.ModuleName)]
+[Route("api/wechat/official/messages")]
+public class WeChatMessageController : AbpControllerBase, IWeChatMessageAppService
+{
+ private readonly IWeChatMessageAppService _service;
+
+ public WeChatMessageController(IWeChatMessageAppService service)
+ {
+ _service = service;
+ }
+
+ [HttpGet]
+ public virtual Task Handle([FromQuery] MessageValidationInput input)
+ {
+ return _service.Handle(input);
+ }
+
+ [HttpPost]
+ public async virtual Task Handle([FromQuery] MessageHandleInput input)
+ {
+ using var reader = new StreamReader(Request.Body, Encoding.UTF8);
+ var content = await reader.ReadToEndAsync();
+
+ input.Data = content;
+
+ return await _service.Handle(input);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialModule.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialModule.cs
index 4ce2cfbab..66a074f75 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialModule.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialModule.cs
@@ -1,5 +1,12 @@
-using LINGYUN.Abp.WeChat.Localization;
+using LINGYUN.Abp.WeChat.Common.Messages;
+using LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+using LINGYUN.Abp.WeChat.Localization;
+using LINGYUN.Abp.WeChat.Official.Messages;
+using LINGYUN.Abp.WeChat.Official.Messages.Handlers;
+using LINGYUN.Abp.WeChat.Official.Messages.Models;
using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
@@ -12,6 +19,48 @@ namespace LINGYUN.Abp.WeChat.Official
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
+ Configure(options =>
+ {
+ options.MapEvent("subscribe", context =>
+ {
+ return context.HasMessageKey("Ticket")
+ // 用户未关注公众号时, 扫描带参数二维码后进行关注的事件
+ ? context.GetWeChatMessage()
+ // 用户关注/取消关注
+ : context.GetWeChatMessage();
+ });
+ options.MapEvent("unsubscribe", context => context.GetWeChatMessage());
+ options.MapEvent("LOCATION", context => context.GetWeChatMessage());
+ options.MapEvent("CLICK", context => context.GetWeChatMessage());
+ options.MapEvent("VIEW", context => context.GetWeChatMessage());
+ options.MapEvent("SCAN", context => context.GetWeChatMessage());
+
+ options.MapMessage("text", context => context.GetWeChatMessage());
+ options.MapMessage("image", context => context.GetWeChatMessage());
+ options.MapMessage("voice", context => context.GetWeChatMessage());
+ options.MapMessage("video", context => context.GetWeChatMessage());
+ options.MapMessage("shortvideo", context => context.GetWeChatMessage());
+ options.MapMessage("location", context => context.GetWeChatMessage());
+ options.MapMessage("link", context => context.GetWeChatMessage());
+ });
+
+ Configure(options =>
+ {
+ // 事件处理器
+ options.MessageResolvers.AddIfNotContains(new WeChatOfficialEventResolveContributor());
+ // 消息处理器
+ options.MessageResolvers.AddIfNotContains(new WeChatOfficialMessageResolveContributor());
+ });
+
+ Configure(options =>
+ {
+ // 回复文本消息
+ options.MapMessage();
+
+ // 处理关注事件
+ options.MapEvent();
+ });
+
Configure(options =>
{
options.FileSets.AddEmbedded();
@@ -25,6 +74,12 @@ namespace LINGYUN.Abp.WeChat.Official
});
context.Services.AddAbpDynamicOptions();
+
+ context.Services.AddHttpClient(AbpWeChatOfficialConsts.HttpClient,
+ options =>
+ {
+ options.BaseAddress = new Uri("https://mp.weixin.qq.com");
+ });
}
}
}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptions.cs
index 628cd7733..5e9a88cf0 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptions.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptions.cs
@@ -2,6 +2,13 @@
{
public class AbpWeChatOfficialOptions
{
+ ///
+ /// 是否沙盒测试
+ ///
+ ///
+ /// Tips: 当使用测试号时,消息为明文传输,调试时需要启用
+ ///
+ public bool IsSandBox { get; set; }
///
/// 公众号服务器消息Url
///
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptionsManager.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptionsManager.cs
index 5dd42e928..fb8197f0f 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptionsManager.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/AbpWeChatOfficialOptionsManager.cs
@@ -17,14 +17,16 @@ namespace LINGYUN.Abp.WeChat.Official
SettingProvider = settingProvider;
}
- protected override async Task OverrideOptionsAsync(string name, AbpWeChatOfficialOptions options)
+ protected async override Task OverrideOptionsAsync(string name, AbpWeChatOfficialOptions options)
{
+ var isSandBox = await SettingProvider.IsTrueAsync(WeChatOfficialSettingNames.IsSandBox);
var appId = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.AppId);
var appSecret = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.AppSecret);
var url = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.Url);
var token = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.Token);
var aesKey = await SettingProvider.GetOrNullAsync(WeChatOfficialSettingNames.EncodingAESKey);
+ options.IsSandBox = isSandBox;
options.AppId = appId ?? options.AppId;
options.AppSecret = appSecret ?? options.AppSecret;
options.Url = url ?? options.Url;
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Enums/SceneEnum.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Enums/SceneEnum.cs
new file mode 100644
index 000000000..580bd7ecd
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Enums/SceneEnum.cs
@@ -0,0 +1,6 @@
+namespace LINGYUN.Abp.WeChat.Official.Account.Enums;
+public enum SceneEnum
+{
+ Login = 0,
+ Binding = 1,
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/IParametricQrCodeGenerator.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/IParametricQrCodeGenerator.cs
new file mode 100644
index 000000000..322918b92
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/IParametricQrCodeGenerator.cs
@@ -0,0 +1,29 @@
+using LINGYUN.Abp.WeChat.Official.Account.Models;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Official.Account;
+///
+/// 生成带参数的二维码接口
+///
+///
+/// 详情见: https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
+///
+public interface IParametricQrCodeGenerator
+{
+ ///
+ /// 创建二维码ticket
+ ///
+ ///
+ ///
+ ///
+ Task CreateTicketAsync(CreateTicketModel model, CancellationToken cancellationToken = default);
+ ///
+ /// 通过ticket换取二维码
+ ///
+ ///
+ ///
+ ///
+ Task ShowQrCodeAsync(string ticket, CancellationToken cancellationToken = default);
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/CreateTicketModel.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/CreateTicketModel.cs
new file mode 100644
index 000000000..b5b5e3535
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/CreateTicketModel.cs
@@ -0,0 +1,97 @@
+using Newtonsoft.Json;
+using System.Text.Json.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Official.Account.Models;
+public class CreateTicketModel : WeChatRequest
+{
+ ///
+ /// 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为60秒。
+ ///
+ [JsonProperty("expire_seconds")]
+ [JsonPropertyName("expire_seconds")]
+ public int? ExpireSeconds { get; set; }
+ ///
+ /// 二维码类型
+ ///
+ ///
+ ///
+ /// - QR_SCENE为临时的整型参数值
+ /// - QR_STR_SCENE为临时的字符串参数值
+ /// - QR_LIMIT_SCENE为永久的整型参数值
+ /// - QR_LIMIT_STR_SCENE为永久的字符串参数值
+ ///
+ ///
+ [JsonProperty("action_name")]
+ [JsonPropertyName("action_name")]
+ public string ActionName { get; private set; }
+ ///
+ /// 二维码详细信息
+ ///
+ [JsonProperty("action_info")]
+ [JsonPropertyName("action_info")]
+ public Scene SceneInfo { get; private set; }
+ private CreateTicketModel()
+ {
+
+ }
+ ///
+ /// 通过场景值名称创建临时二维码ticket
+ ///
+ /// 场景值名称
+ /// 二维码有效时间
+ ///
+ public static CreateTicketModel StringScene(
+ string sceneStr,
+ int expireSeconds = 60)
+ {
+ return new CreateTicketModel
+ {
+ ExpireSeconds = expireSeconds,
+ ActionName = "QR_STR_SCENE",
+ SceneInfo = new StringScene(sceneStr),
+ };
+ }
+ ///
+ /// 通过场景值名称创建永久二维码ticket
+ ///
+ /// 场景值名称
+ ///
+ public static CreateTicketModel LimitStringScene(string sceneStr)
+ {
+ return new CreateTicketModel
+ {
+ ActionName = "QR_LIMIT_STR_SCENE",
+ SceneInfo = new StringScene(sceneStr),
+ };
+ }
+ ///
+ /// 通过场景值标识创建二维码ticket
+ ///
+ /// 场景值标识
+ /// 二维码有效时间
+ ///
+ public static CreateTicketModel EnumScene(
+ int sceneId,
+ int expireSeconds = 60)
+ {
+ return new CreateTicketModel
+ {
+ ExpireSeconds = expireSeconds,
+ ActionName = "QR_SCENE",
+ SceneInfo = new EnumScene(sceneId),
+ };
+ }
+ ///
+ /// 通过场景值标识创建永久二维码ticket
+ ///
+ /// 场景值标识
+ ///
+ public static CreateTicketModel LimitEnumScene(int sceneId)
+ {
+ return new CreateTicketModel
+ {
+ ActionName = "QR_LIMIT_SCENE",
+ SceneInfo = new EnumScene(sceneId),
+ };
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/EnumScene.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/EnumScene.cs
new file mode 100644
index 000000000..de339816f
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/EnumScene.cs
@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+using System.Text.Json.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Official.Account.Models;
+public class EnumScene : Scene
+{
+ ///
+ /// 场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)
+ ///
+ [JsonProperty("scene_id")]
+ [JsonPropertyName("scene_id")]
+ public int SceneId { get; }
+ public EnumScene(int sceneId)
+ {
+ SceneId = sceneId;
+ }
+
+ public override string GetKey()
+ {
+ return SceneId.ToString();
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/Scene.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/Scene.cs
new file mode 100644
index 000000000..46202d0df
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/Scene.cs
@@ -0,0 +1,5 @@
+namespace LINGYUN.Abp.WeChat.Official.Account.Models;
+public abstract class Scene
+{
+ public abstract string GetKey();
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/StringScene.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/StringScene.cs
new file mode 100644
index 000000000..e5621d75e
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/StringScene.cs
@@ -0,0 +1,22 @@
+using Newtonsoft.Json;
+using System.Text.Json.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Official.Account.Models;
+public class StringScene : Scene
+{
+ ///
+ /// 场景值ID(字符串形式的ID),字符串类型,长度限制为1到64
+ ///
+ [JsonProperty("scene_str")]
+ [JsonPropertyName("scene_str")]
+ public string SceneStr { get; }
+ public StringScene(string sceneStr)
+ {
+ SceneStr = sceneStr;
+ }
+
+ public override string GetKey()
+ {
+ return SceneStr;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/TicketModel.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/TicketModel.cs
new file mode 100644
index 000000000..013c15a25
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/TicketModel.cs
@@ -0,0 +1,25 @@
+using Newtonsoft.Json;
+using System.Text.Json.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Official.Account.Models;
+public class TicketModel
+{
+ ///
+ /// 获取的二维码ticket,凭借此ticket可以在有效时间内换取二维码
+ ///
+ [JsonProperty("ticket")]
+ [JsonPropertyName("ticket")]
+ public string Ticket { get; set; }
+ ///
+ /// 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天)。
+ ///
+ [JsonProperty("expire_seconds")]
+ [JsonPropertyName("expire_seconds")]
+ public int ExpireSeconds { get; set; }
+ ///
+ /// 二维码图片解析后的地址,开发者可根据该地址自行生成需要的二维码图片
+ ///
+ [JsonProperty("url")]
+ [JsonPropertyName("url")]
+ public string Url { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/TicketModelCacheItem.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/TicketModelCacheItem.cs
new file mode 100644
index 000000000..218ee5569
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/Models/TicketModelCacheItem.cs
@@ -0,0 +1,26 @@
+namespace LINGYUN.Abp.WeChat.Official.Account.Models;
+public class TicketModelCacheItem
+{
+ public string Ticket { get; set; }
+
+ public int ExpireSeconds { get; set; }
+
+ public string Url { get; set; }
+
+ public TicketModelCacheItem()
+ {
+
+ }
+
+ public TicketModelCacheItem(string ticket, int expireSeconds, string url)
+ {
+ Ticket = ticket;
+ ExpireSeconds = expireSeconds;
+ Url = url;
+ }
+
+ public static string CalculateCacheKey(string action, string scene)
+ {
+ return "a:" + action + ";s:" + scene;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/ParametricQrCodeGenerator.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/ParametricQrCodeGenerator.cs
new file mode 100644
index 000000000..4027c388b
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Account/ParametricQrCodeGenerator.cs
@@ -0,0 +1,87 @@
+using LINGYUN.Abp.WeChat.Official.Account.Models;
+using LINGYUN.Abp.WeChat.Token;
+using Microsoft.Extensions.Caching.Distributed;
+using Newtonsoft.Json;
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.Caching;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.WeChat.Official.Account;
+public class ParametricQrCodeGenerator : IParametricQrCodeGenerator, ITransientDependency
+{
+ protected IHttpClientFactory HttpClientFactory { get; }
+ protected AbpWeChatOfficialOptionsFactory OfficialOptionsFactory { get; }
+ protected IWeChatTokenProvider WeChatTokenProvider { get; }
+ protected IDistributedCache TicketModelCache { get; }
+ public ParametricQrCodeGenerator(
+ IHttpClientFactory httpClientFactory,
+ IWeChatTokenProvider weChatTokenProvider,
+ AbpWeChatOfficialOptionsFactory officialOptionsFactory,
+ IDistributedCache ticketModelCache)
+ {
+ TicketModelCache = ticketModelCache;
+ HttpClientFactory = httpClientFactory;
+ WeChatTokenProvider = weChatTokenProvider;
+ OfficialOptionsFactory = officialOptionsFactory;
+ }
+
+ public async virtual Task CreateTicketAsync(CreateTicketModel model, CancellationToken cancellationToken = default)
+ {
+ var cacheItem = await GetOrCreateTicketModelCacheItem(model, cancellationToken);
+
+ return new TicketModel
+ {
+ ExpireSeconds = cacheItem.ExpireSeconds,
+ Ticket = cacheItem.Ticket,
+ Url = cacheItem.Url,
+ };
+ }
+
+ public async virtual Task ShowQrCodeAsync(string ticket, CancellationToken cancellationToken = default)
+ {
+ var client = HttpClientFactory.CreateClient(AbpWeChatOfficialConsts.HttpClient);
+ var response = await client.GetAsync($"/cgi-bin/showqrcode?ticket={ticket}", cancellationToken);
+ response.ThrowNotSuccessStatusCode();
+
+ return await response.Content.ReadAsStreamAsync();
+ }
+
+ protected async virtual Task GetOrCreateTicketModelCacheItem(CreateTicketModel model, CancellationToken cancellationToken = default)
+ {
+ var cacheKey = TicketModelCacheItem.CalculateCacheKey(model.ActionName, model.SceneInfo.GetKey());
+ var cacheItem = await TicketModelCache.GetAsync(cacheKey, token: cancellationToken);
+ if (cacheItem != null)
+ {
+ return cacheItem;
+ }
+
+ var options = await OfficialOptionsFactory.CreateAsync();
+
+ var token = await WeChatTokenProvider.GetTokenAsync(options.AppId, options.AppSecret, cancellationToken);
+
+ var client = HttpClientFactory.CreateClient(AbpWeChatGlobalConsts.HttpClient);
+ var response = await client.PostAsync(
+ $"/cgi-bin/qrcode/create?access_token={token.AccessToken}",
+ new StringContent(model.SerializeToJson()));
+ response.ThrowNotSuccessStatusCode();
+
+ var responseContent = await response.Content.ReadAsStringAsync();
+ var ticketModel = JsonConvert.DeserializeObject(responseContent);
+
+ cacheItem = new TicketModelCacheItem(ticketModel.Ticket, ticketModel.ExpireSeconds, ticketModel.Url);
+
+ var cacheOptions = new DistributedCacheEntryOptions
+ {
+ // 设置绝对过期时间为Token有效期剩余的二分钟
+ AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(ticketModel.ExpireSeconds)
+ };
+
+ await TicketModelCache.SetAsync(cacheKey, cacheItem, cacheOptions, token: cancellationToken);
+
+ return cacheItem;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/zh-Hans.json b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/zh-Hans.json
index e133623c2..0ab6d3ed9 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/zh-Hans.json
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Localization/Resources/zh-Hans.json
@@ -3,6 +3,8 @@
"texts": {
"DisplayName:WeChat.Official": "微信公众号",
"Description:WeChat.Official": "微信公众号",
+ "DisplayName:WeChat.Official.IsSandBox": "是否沙盒测试",
+ "Description:WeChat.Official.IsSandBox": "在使用微信公众号能力前,可通过申请测试号熟悉调用,详情见:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Requesting_an_API_Test_Account.html",
"DisplayName:WeChat.Official.AppId": "公众号AppId",
"Description:WeChat.Official.AppId": "微信公众号AppId,详情见:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html",
"DisplayName:WeChat.Official.AppSecret": "公众号AppSecret",
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/AbpWeChatOfficialMessageResolveOptions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/AbpWeChatOfficialMessageResolveOptions.cs
new file mode 100644
index 000000000..d145468e7
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/AbpWeChatOfficialMessageResolveOptions.cs
@@ -0,0 +1,25 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System;
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages;
+public class AbpWeChatOfficialMessageResolveOptions
+{
+ public IDictionary> EventMaps { get; }
+ public IDictionary> MessageMaps { get; }
+ public AbpWeChatOfficialMessageResolveOptions()
+ {
+ EventMaps = new Dictionary>();
+ MessageMaps = new Dictionary>();
+ }
+
+ public void MapEvent(string eventName, Func mapFunc)
+ {
+ EventMaps[eventName] = mapFunc;
+ }
+
+ public void MapMessage(string messageType, Func mapFunc)
+ {
+ MessageMaps[messageType] = mapFunc;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/TextMessageReplyContributor.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/TextMessageReplyContributor.cs
new file mode 100644
index 000000000..9d3bff545
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/TextMessageReplyContributor.cs
@@ -0,0 +1,23 @@
+using LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+using LINGYUN.Abp.WeChat.Official.Messages.Models;
+using LINGYUN.Abp.WeChat.Official.Services;
+using Microsoft.Extensions.DependencyInjection;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Handlers;
+///
+/// 文本消息客服回复
+///
+public class TextMessageReplyContributor : IMessageHandleContributor
+{
+ public async virtual Task HandleAsync(MessageHandleContext context)
+ {
+ var messageSender = context.ServiceProvider.GetRequiredService();
+
+ await messageSender.SendAsync(
+ new Services.Models.TextMessageModel(
+ context.Message.FromUserName,
+ new Services.Models.TextMessage(
+ context.Message.Content)));
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/UserSubscribeEventContributor.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/UserSubscribeEventContributor.cs
new file mode 100644
index 000000000..216a050e8
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/UserSubscribeEventContributor.cs
@@ -0,0 +1,23 @@
+using LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+using LINGYUN.Abp.WeChat.Official.Messages.Models;
+using LINGYUN.Abp.WeChat.Official.Services;
+using Microsoft.Extensions.DependencyInjection;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Handlers;
+///
+/// 用户关注回复消息
+///
+public class UserSubscribeEventContributor : IEventHandleContributor
+{
+ public async virtual Task HandleAsync(MessageHandleContext context)
+ {
+ var messageSender = context.ServiceProvider.GetRequiredService();
+
+ await messageSender.SendAsync(
+ new Services.Models.TextMessageModel(
+ context.Message.FromUserName,
+ new Services.Models.TextMessage(
+ "感谢您的关注, 点击菜单了解更多.")));
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/WeChatOfficialEventEventHandler.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/WeChatOfficialEventEventHandler.cs
new file mode 100644
index 000000000..65fdf013f
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/WeChatOfficialEventEventHandler.cs
@@ -0,0 +1,54 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+using LINGYUN.Abp.WeChat.Official.Messages.Models;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.EventBus.Distributed;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Handlers;
+public class WeChatOfficialEventEventHandler :
+ IDistributedEventHandler>,
+ IDistributedEventHandler>,
+ IDistributedEventHandler>,
+ IDistributedEventHandler>,
+ IDistributedEventHandler>,
+ IDistributedEventHandler>,
+ ITransientDependency
+{
+ private readonly IMessageHandler _messageHandler;
+
+ public WeChatOfficialEventEventHandler(IMessageHandler messageHandler)
+ {
+ _messageHandler = messageHandler;
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialEventMessageEto eventData)
+ {
+ await _messageHandler.HandleEventAsync(eventData.Event);
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialEventMessageEto eventData)
+ {
+ await _messageHandler.HandleEventAsync(eventData.Event);
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialEventMessageEto eventData)
+ {
+ await _messageHandler.HandleEventAsync(eventData.Event);
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialEventMessageEto eventData)
+ {
+ await _messageHandler.HandleEventAsync(eventData.Event);
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialEventMessageEto eventData)
+ {
+ await _messageHandler.HandleEventAsync(eventData.Event);
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialEventMessageEto eventData)
+ {
+ await _messageHandler.HandleEventAsync(eventData.Event);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/WeChatOfficialMessageEventHandler.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/WeChatOfficialMessageEventHandler.cs
new file mode 100644
index 000000000..674866605
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Handlers/WeChatOfficialMessageEventHandler.cs
@@ -0,0 +1,54 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using LINGYUN.Abp.WeChat.Common.Messages.Handlers;
+using LINGYUN.Abp.WeChat.Official.Messages.Models;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.EventBus.Distributed;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Handlers;
+public class WeChatOfficialMessageEventHandler :
+ IDistributedEventHandler>,
+ IDistributedEventHandler>,
+ IDistributedEventHandler>,
+ IDistributedEventHandler>,
+ IDistributedEventHandler>,
+ IDistributedEventHandler>,
+ ITransientDependency
+{
+ private readonly IMessageHandler _messageHandler;
+
+ public WeChatOfficialMessageEventHandler(IMessageHandler messageHandler)
+ {
+ _messageHandler = messageHandler;
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialGeneralMessageEto eventData)
+ {
+ await _messageHandler.HandleMessageAsync(eventData.Message);
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialGeneralMessageEto eventData)
+ {
+ await _messageHandler.HandleMessageAsync(eventData.Message);
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialGeneralMessageEto eventData)
+ {
+ await _messageHandler.HandleMessageAsync(eventData.Message);
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialGeneralMessageEto eventData)
+ {
+ await _messageHandler.HandleMessageAsync(eventData.Message);
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialGeneralMessageEto eventData)
+ {
+ await _messageHandler.HandleMessageAsync(eventData.Message);
+ }
+
+ public async virtual Task HandleEventAsync(WeChatOfficialGeneralMessageEto eventData)
+ {
+ await _messageHandler.HandleMessageAsync(eventData.Message);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/CustomMenuEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/CustomMenuEvent.cs
new file mode 100644
index 000000000..773e2ffcf
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/CustomMenuEvent.cs
@@ -0,0 +1,22 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 自定义菜单事件
+///
+[EventName("custom_menu")]
+public class CustomMenuEvent : WeChatEventMessage
+{
+ ///
+ /// 事件KEY值
+ ///
+ [XmlElement("EventKey")]
+ public string EventKey { get; set; }
+
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/GeoLocationMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/GeoLocationMessage.cs
new file mode 100644
index 000000000..1179993da
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/GeoLocationMessage.cs
@@ -0,0 +1,36 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 地理位置消息
+///
+[EventName("geo_location")]
+public class GeoLocationMessage : WeChatOfficialGeneralMessage
+{
+ ///
+ /// 地理位置纬度
+ ///
+ [XmlElement("Location_X")]
+ public double Latitude { get; set; }
+ ///
+ /// 地理位置经度
+ ///
+ [XmlElement("Location_Y")]
+ public double Longitude { get; set; }
+ ///
+ /// 地图缩放大小
+ ///
+ [XmlElement("Scale")]
+ public double Scale { get; set; }
+ ///
+ /// 地理位置信息
+ ///
+ [XmlElement("Label")]
+ public string Label { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/LinkMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/LinkMessage.cs
new file mode 100644
index 000000000..1c4423295
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/LinkMessage.cs
@@ -0,0 +1,31 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 链接消息
+///
+[EventName("link")]
+public class LinkMessage : WeChatOfficialGeneralMessage
+{
+ ///
+ /// 消息标题
+ ///
+ [XmlElement("Title")]
+ public string Title { get; set; }
+ ///
+ /// 消息描述
+ ///
+ [XmlElement("Description")]
+ public string Description { get; set; }
+ ///
+ /// 消息链接
+ ///
+ [XmlElement("Url")]
+ public string Url { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/MenuClickJumpLinkEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/MenuClickJumpLinkEvent.cs
new file mode 100644
index 000000000..487e4fb65
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/MenuClickJumpLinkEvent.cs
@@ -0,0 +1,21 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 点击菜单跳转链接时的事件推送
+///
+[EventName("menu_click_jump_link")]
+public class MenuClickJumpLinkEvent : WeChatEventMessage
+{
+ ///
+ /// 事件KEY值
+ ///
+ [XmlElement("EventKey")]
+ public string EventKey { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/ParametricQrCodeEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/ParametricQrCodeEvent.cs
new file mode 100644
index 000000000..696ed977c
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/ParametricQrCodeEvent.cs
@@ -0,0 +1,26 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 扫描带参数二维码事件
+///
+[EventName("parametric_qr_code")]
+public class ParametricQrCodeEvent : WeChatEventMessage
+{
+ ///
+ /// 事件KEY值
+ ///
+ [XmlElement("EventKey")]
+ public string EventKey { get; set; }
+ ///
+ /// 二维码的ticket,可用来换取二维码图片
+ ///
+ [XmlElement("Ticket")]
+ public string Ticket { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/PictureMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/PictureMessage.cs
new file mode 100644
index 000000000..13a06cde9
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/PictureMessage.cs
@@ -0,0 +1,26 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 图片消息
+///
+[EventName("picture")]
+public class PictureMessage : WeChatOfficialGeneralMessage
+{
+ ///
+ /// 图片链接(由系统生成)
+ ///
+ [XmlElement("PicUrl")]
+ public string PicUrl { get; set; }
+ ///
+ /// 图片消息媒体id,可以调用获取临时素材接口拉取数据。
+ ///
+ [XmlElement("MediaId")]
+ public string MediaId { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/ReportingGeoLocationEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/ReportingGeoLocationEvent.cs
new file mode 100644
index 000000000..9d22fcae9
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/ReportingGeoLocationEvent.cs
@@ -0,0 +1,31 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 上报地理位置事件
+///
+[EventName("reporting_geo_location")]
+public class ReportingGeoLocationEvent : WeChatEventMessage
+{
+ ///
+ /// 地理位置纬度
+ ///
+ [XmlElement("Latitude")]
+ public double Latitude { get; set; }
+ ///
+ /// 地理位置经度
+ ///
+ [XmlElement("Longitude")]
+ public double Longitude { get; set; }
+ ///
+ /// 地理位置精度
+ ///
+ [XmlElement("Precision")]
+ public double Precision { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/TextMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/TextMessage.cs
new file mode 100644
index 000000000..f9e495433
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/TextMessage.cs
@@ -0,0 +1,21 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 文本消息
+///
+[EventName("text")]
+public class TextMessage : WeChatOfficialGeneralMessage
+{
+ ///
+ /// 文本消息内容
+ ///
+ [XmlElement("Content")]
+ public string Content { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/UserSubscribeEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/UserSubscribeEvent.cs
new file mode 100644
index 000000000..8dee66f71
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/UserSubscribeEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 用户关注事件
+///
+[EventName("user_subscribe")]
+public class UserSubscribeEvent : WeChatEventMessage
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/UserUnSubscribeEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/UserUnSubscribeEvent.cs
new file mode 100644
index 000000000..00b6d4b6e
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/UserUnSubscribeEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 用户取消关注事件
+///
+[EventName("user_un_subscribe")]
+public class UserUnSubscribeEvent : WeChatEventMessage
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/VideoMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/VideoMessage.cs
new file mode 100644
index 000000000..bfd211376
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/VideoMessage.cs
@@ -0,0 +1,26 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 视频消息
+///
+[EventName("video")]
+public class VideoMessage : WeChatOfficialGeneralMessage
+{
+ ///
+ /// 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
+ ///
+ [XmlElement("ThumbMediaId")]
+ public string ThumbMediaId { get; set; }
+ ///
+ /// 视频消息媒体id,可以调用获取临时素材接口拉取数据。
+ ///
+ [XmlElement("MediaId")]
+ public string MediaId { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/VoiceMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/VoiceMessage.cs
new file mode 100644
index 000000000..2f8990c53
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/Models/VoiceMessage.cs
@@ -0,0 +1,35 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages.Models;
+///
+/// 语音消息
+///
+[EventName("voice")]
+public class VoiceMessage : WeChatOfficialGeneralMessage
+{
+ ///
+ /// 语音格式,如amr,speex等
+ ///
+ [XmlElement("Format")]
+ public string Format { get; set; }
+ ///
+ /// 语音识别结果,UTF8编码
+ ///
+ ///
+ /// 开通语音识别后,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,增加一个Recognition字段(
+ /// 注:由于客户端缓存,开发者开启或者关闭语音识别功能,对新关注者立刻生效,对已关注用户需要24小时生效。开发者可以重新关注此账号进行测试)。
+ ///
+ [XmlElement("Recognition")]
+ public string Recognition { get; set; }
+ ///
+ /// 语音消息媒体id,可以调用获取临时素材接口拉取该媒体
+ ///
+ [XmlElement("MediaId")]
+ public string MediaId { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatOfficialGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialEventMessageEto.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialEventMessageEto.cs
new file mode 100644
index 000000000..b63df0c34
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialEventMessageEto.cs
@@ -0,0 +1,19 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages;
+
+[GenericEventName(Prefix = "wechat.official.events")]
+public class WeChatOfficialEventMessageEto : WeChatMessageEto
+ where TEvent : WeChatEventMessage
+{
+ public TEvent Event { get; set; }
+ public WeChatOfficialEventMessageEto()
+ {
+
+ }
+ public WeChatOfficialEventMessageEto(TEvent @event)
+ {
+ Event = @event;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialEventResolveContributor.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialEventResolveContributor.cs
new file mode 100644
index 000000000..d6052e7c3
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialEventResolveContributor.cs
@@ -0,0 +1,29 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages;
+///
+/// 微信公众号事件处理器
+///
+public class WeChatOfficialEventResolveContributor : MessageResolveContributorBase
+{
+ public override string Name => "WeChat.Official.Event";
+
+ public override Task ResolveAsync(IMessageResolveContext context)
+ {
+ var options = context.ServiceProvider.GetRequiredService>().Value;
+ var messageType = context.GetMessageData("MsgType");
+ var eventName = context.GetMessageData("Event");
+ if ("event".Equals(messageType, StringComparison.InvariantCultureIgnoreCase) &&
+ !eventName.IsNullOrWhiteSpace() &&
+ options.EventMaps.TryGetValue(eventName, out var eventFactory))
+ {
+ context.Message = eventFactory(context);
+ context.Handled = true;
+ }
+ return Task.CompletedTask;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialGeneralMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialGeneralMessage.cs
new file mode 100644
index 000000000..0979fa034
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialGeneralMessage.cs
@@ -0,0 +1,17 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages;
+public abstract class WeChatOfficialGeneralMessage : WeChatGeneralMessage
+{
+ ///
+ /// 消息的数据ID(消息如果来自文章时才有)
+ ///
+ [XmlElement("MsgDataId")]
+ public string MsgDataId { get; set; }
+ ///
+ /// 多图文时第几篇文章,从1开始(消息如果来自文章时才有)
+ ///
+ [XmlElement("Idx")]
+ public string Idx { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialGeneralMessageEto.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialGeneralMessageEto.cs
new file mode 100644
index 000000000..a5129d268
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialGeneralMessageEto.cs
@@ -0,0 +1,19 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages;
+
+[GenericEventName(Prefix = "wechat.official.messages")]
+public class WeChatOfficialGeneralMessageEto : WeChatMessageEto
+ where TMessage : WeChatOfficialGeneralMessage
+{
+ public TMessage Message { get; set; }
+ public WeChatOfficialGeneralMessageEto()
+ {
+
+ }
+ public WeChatOfficialGeneralMessageEto(TMessage message)
+ {
+ Message = message;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialMessageResolveContributor.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialMessageResolveContributor.cs
new file mode 100644
index 000000000..8a8408523
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Messages/WeChatOfficialMessageResolveContributor.cs
@@ -0,0 +1,25 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Official.Messages;
+///
+/// 微信公众号消息处理器
+///
+public class WeChatOfficialMessageResolveContributor : MessageResolveContributorBase
+{
+ public override string Name => "WeChat.Official.Message";
+
+ public override Task ResolveAsync(IMessageResolveContext context)
+ {
+ var options = context.ServiceProvider.GetRequiredService>().Value;
+ var messageType = context.GetMessageData("MsgType");
+ if (options.MessageMaps.TryGetValue(messageType, out var messageFactory))
+ {
+ context.Message = messageFactory(context);
+ context.Handled = true;
+ }
+ return Task.CompletedTask;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/IServiceCenterMessageSender.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/IServiceCenterMessageSender.cs
new file mode 100644
index 000000000..a32ee7938
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/IServiceCenterMessageSender.cs
@@ -0,0 +1,12 @@
+using LINGYUN.Abp.WeChat.Official.Services.Models;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace LINGYUN.Abp.WeChat.Official.Services;
+///
+/// 客服中心消息接口
+///
+public interface IServiceCenterMessageSender
+{
+ Task SendAsync(MessageModel message, CancellationToken cancellationToken = default);
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/Models/MessageModel.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/Models/MessageModel.cs
new file mode 100644
index 000000000..e6f768c21
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/Models/MessageModel.cs
@@ -0,0 +1,17 @@
+using Newtonsoft.Json;
+using System.Text.Json.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Official.Services.Models;
+public abstract class MessageModel : WeChatRequest
+{
+ ///
+ /// 消息类型
+ ///
+ [JsonProperty("msgtype")]
+ [JsonPropertyName("msgtype")]
+ public string MsgType { get; }
+ protected MessageModel(string msgType)
+ {
+ MsgType = msgType;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/Models/TextMessageModel.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/Models/TextMessageModel.cs
new file mode 100644
index 000000000..2bac29137
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/Models/TextMessageModel.cs
@@ -0,0 +1,44 @@
+using Newtonsoft.Json;
+using System;
+using System.Text.Json.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Official.Services.Models;
+///
+/// 发送文本消息
+///
+[Serializable]
+public class TextMessageModel : MessageModel
+{
+ ///
+ /// 接收消息用户
+ ///
+ [JsonProperty("touser")]
+ [JsonPropertyName("touser")]
+ public string ToUser { get; }
+ ///
+ /// 消息内容
+ ///
+ [JsonProperty("text")]
+ [JsonPropertyName("text")]
+ public TextMessage Text { get; }
+ public TextMessageModel(string toUser, TextMessage text)
+ : base("text")
+ {
+ ToUser = toUser;
+ Text = text;
+ }
+}
+
+public class TextMessage
+{
+ ///
+ /// 内容文本
+ ///
+ [JsonProperty("content")]
+ [JsonPropertyName("content")]
+ public string Content { get; set; }
+ public TextMessage(string content)
+ {
+ Content = content;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/ServiceCenterMessageSender.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/ServiceCenterMessageSender.cs
new file mode 100644
index 000000000..546e28e2b
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Services/ServiceCenterMessageSender.cs
@@ -0,0 +1,34 @@
+using LINGYUN.Abp.WeChat.Official.Services.Models;
+using LINGYUN.Abp.WeChat.Token;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace LINGYUN.Abp.WeChat.Official.Services;
+public class ServiceCenterMessageSender : IServiceCenterMessageSender, ITransientDependency
+{
+ protected IHttpClientFactory HttpClientFactory { get; }
+ protected AbpWeChatOfficialOptionsFactory OfficialOptionsFactory { get; }
+ protected IWeChatTokenProvider WeChatTokenProvider { get; }
+ public ServiceCenterMessageSender(
+ IHttpClientFactory httpClientFactory,
+ IWeChatTokenProvider weChatTokenProvider,
+ AbpWeChatOfficialOptionsFactory officialOptionsFactory)
+ {
+ HttpClientFactory = httpClientFactory;
+ WeChatTokenProvider = weChatTokenProvider;
+ OfficialOptionsFactory = officialOptionsFactory;
+ }
+
+ public async virtual Task SendAsync(MessageModel message, CancellationToken cancellationToken = default)
+ {
+ var options = await OfficialOptionsFactory.CreateAsync();
+ var token = await WeChatTokenProvider.GetTokenAsync(options.AppId, options.AppSecret, cancellationToken);
+ var client = HttpClientFactory.CreateClient(AbpWeChatGlobalConsts.HttpClient);
+ await client.PostAsync(
+ $"cgi-bin/message/custom/send?access_token={token.AccessToken}",
+ new StringContent(message.SerializeToJson()),
+ cancellationToken);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingDefinitionProvider.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingDefinitionProvider.cs
index 9c803963e..f3432169c 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingDefinitionProvider.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingDefinitionProvider.cs
@@ -9,6 +9,18 @@ namespace LINGYUN.Abp.WeChat.Official.Settings
public override void Define(ISettingDefinitionContext context)
{
context.Add(
+ new SettingDefinition(
+ WeChatOfficialSettingNames.IsSandBox,
+ "false",
+ L("DisplayName:WeChat.Official.IsSandBox"),
+ L("Description:WeChat.Official.IsSandBox"),
+ isVisibleToClients: false,
+ isEncrypted: false)
+ .WithProviders(
+ DefaultValueSettingValueProvider.ProviderName,
+ ConfigurationSettingValueProvider.ProviderName,
+ GlobalSettingValueProvider.ProviderName,
+ TenantSettingValueProvider.ProviderName),
new SettingDefinition(
WeChatOfficialSettingNames.AppId, "",
L("DisplayName:WeChat.Official.AppId"),
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingNames.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingNames.cs
index 9c20f0481..9b179e1c4 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingNames.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Official/LINGYUN/Abp/WeChat/Official/Settings/WeChatOfficialSettingNames.cs
@@ -6,6 +6,7 @@ namespace LINGYUN.Abp.WeChat.Official.Settings
{
private const string Prefix = WeChatSettingNames.Prefix + ".Official";
+ public static string IsSandBox = Prefix + "." + nameof(AbpWeChatOfficialOptions.IsSandBox);
public static string AppId = Prefix + "." + nameof(AbpWeChatOfficialOptions.AppId);
public static string AppSecret = Prefix + "." + nameof(AbpWeChatOfficialOptions.AppSecret);
public static string Url = Prefix + "." + nameof(AbpWeChatOfficialOptions.Url);
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.SettingManagement/LINGYUN/Abp/WeChat/SettingManagement/WeChatSettingAppService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.SettingManagement/LINGYUN/Abp/WeChat/SettingManagement/WeChatSettingAppService.cs
index 0d91c5844..1616fcd76 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.SettingManagement/LINGYUN/Abp/WeChat/SettingManagement/WeChatSettingAppService.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.SettingManagement/LINGYUN/Abp/WeChat/SettingManagement/WeChatSettingAppService.cs
@@ -59,6 +59,12 @@ namespace LINGYUN.Abp.WeChat.SettingManagement
#region 公众号
var officialSetting = wechatSettingGroup.AddSetting(L["DisplayName:WeChat.Official"], L["Description:WeChat.Official"]);
+ officialSetting.AddDetail(
+ await SettingDefinitionManager.GetAsync(WeChatOfficialSettingNames.IsSandBox),
+ StringLocalizerFactory,
+ await SettingManager.GetOrNullAsync(WeChatOfficialSettingNames.IsSandBox, providerName, providerKey),
+ ValueType.Boolean,
+ providerName);
officialSetting.AddDetail(
await SettingDefinitionManager.GetAsync(WeChatOfficialSettingNames.AppId),
StringLocalizerFactory,
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageAppService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageAppService.cs
index e1aeed744..b4552c38a 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageAppService.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Application/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageAppService.cs
@@ -1,22 +1,30 @@
-using LINGYUN.Abp.WeChat.Work.Security;
-using LINGYUN.Abp.WeChat.Work.Security.Models;
+using LINGYUN.Abp.WeChat.Common.Crypto;
+using LINGYUN.Abp.WeChat.Common.Crypto.Models;
+using LINGYUN.Abp.WeChat.Common.Messages;
using LINGYUN.Abp.WeChat.Work.Settings;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
+using Volo.Abp.EventBus.Distributed;
namespace LINGYUN.Abp.WeChat.Work.Message;
public class WeChatWorkMessageAppService : ApplicationService, IWeChatWorkMessageAppService
{
- private readonly IWeChatWorkCryptoService _cryptoService;
+ private readonly IWeChatCryptoService _cryptoService;
private readonly WeChatWorkOptions _options;
-
+ private readonly IDistributedEventBus _distributedEventBus;
+ private readonly IMessageResolver _messageResolver;
public WeChatWorkMessageAppService(
- IWeChatWorkCryptoService cryptoService,
+ IMessageResolver messageResolver,
+ IWeChatCryptoService cryptoService,
+ IDistributedEventBus distributedEventBus,
IOptionsMonitor options)
{
_cryptoService = cryptoService;
+ _messageResolver = messageResolver;
+ _distributedEventBus = distributedEventBus;
_options = options.CurrentValue;
}
@@ -27,7 +35,7 @@ public class WeChatWorkMessageAppService : ApplicationService, IWeChatWorkMessag
var applicationConfiguration = _options.Applications.GetConfiguration(agentId);
var cryptoConfiguration = applicationConfiguration.GetCryptoConfiguration("Message");
- var echoData = new WeChatWorkCryptoEchoData(
+ var echoData = new WeChatCryptoEchoData(
input.EchoStr,
corpId,
cryptoConfiguration.Token,
@@ -48,16 +56,29 @@ public class WeChatWorkMessageAppService : ApplicationService, IWeChatWorkMessag
var applicationConfiguration = _options.Applications.GetConfiguration(agentId);
var cryptoConfiguration = applicationConfiguration.GetCryptoConfiguration("Message");
- var decryptData = new WeChatWorkCryptoDecryptData(
- input.Data,
+
+ var messageData = new MessageResolveData(
corpId,
cryptoConfiguration.Token,
cryptoConfiguration.EncodingAESKey,
input.Msg_Signature,
- input.TimeStamp.ToString(),
- input.Nonce);
+ input.TimeStamp,
+ input.Nonce,
+ input.Data);
- var msg = _cryptoService.Decrypt(decryptData);
- return msg;
+ var result = await _messageResolver.ResolveMessageAsync(messageData);
+ if (result.Message == null)
+ {
+ Logger.LogWarning(input.Data);
+ Logger.LogWarning("解析消息失败, 无法处理企业微信消息.");
+ }
+ else
+ {
+ Logger.LogInformation(result.Message.SerializeToXml());
+ var eto = result.Message.ToEto();
+ await _distributedEventBus.PublishAsync(eto.GetType(), eto);
+ }
+ // https://developer.work.weixin.qq.com/document/path/90238
+ return "success";
}
}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN.Abp.WeChat.Work.Common.csproj b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN.Abp.WeChat.Work.Common.csproj
new file mode 100644
index 000000000..4b3e4eb03
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN.Abp.WeChat.Work.Common.csproj
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/AbpWeChatWorkCommonModule.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/AbpWeChatWorkCommonModule.cs
new file mode 100644
index 000000000..e0bea9a15
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/AbpWeChatWorkCommonModule.cs
@@ -0,0 +1,62 @@
+using LINGYUN.Abp.WeChat.Common;
+using LINGYUN.Abp.WeChat.Common.Messages;
+using LINGYUN.Abp.WeChat.Work.Common.Messages;
+using LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+using System;
+using System.Xml.Serialization;
+using Volo.Abp.Modularity;
+
+namespace LINGYUN.Abp.WeChat.Work.Common;
+
+[DependsOn(
+ typeof(AbpWeChatCommonModule))]
+public class AbpWeChatWorkCommonModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ Configure(options =>
+ {
+ options.MapEvent("click", context => context.GetWeChatMessage());
+ options.MapEvent("view", context => context.GetWeChatMessage());
+ options.MapEvent("scancode_push", context => context.GetWeChatMessage());
+ options.MapEvent("scancode_waitmsg", context => context.GetWeChatMessage());
+ options.MapEvent("pic_sysphoto", context => context.GetWeChatMessage());
+ options.MapEvent("pic_photo_or_album", context => context.GetWeChatMessage());
+ options.MapEvent("pic_weixin", context => context.GetWeChatMessage());
+ options.MapEvent("subscribe", context => context.GetWeChatMessage());
+ options.MapEvent("unsubscribe", context => context.GetWeChatMessage());
+ options.MapEvent("enter_agent", context => context.GetWeChatMessage());
+ options.MapEvent("LOCATION", context => context.GetWeChatMessage());
+ options.MapEvent("batch_job_result", context => context.GetWeChatMessage());
+ options.MapEvent("change_contact", context =>
+ {
+ static UserChangeEvent CreateUserChangeEvent(string originXml) where TEvent : UserChangeEvent
+ {
+ var events = new XmlDeserializationEvents();
+ return originXml.DeserializeWeChatMessage(events);
+ }
+
+ var changeType = context.GetMessageData("ChangeType");
+ return changeType switch
+ {
+ "create_user" => CreateUserChangeEvent(context.Origin),
+ "update_user" => CreateUserChangeEvent(context.Origin),
+ "delete_user" => context.GetWeChatMessage(),
+ "create_party" => context.GetWeChatMessage(),
+ "update_party" => context.GetWeChatMessage(),
+ "delete_party" => context.GetWeChatMessage(),
+ "update_tag" => context.GetWeChatMessage(),
+ _ => throw new AbpWeChatException($"Contact change event {changeType} is not mounted!"),
+ };
+ });
+
+ options.MapMessage("text", context => context.GetWeChatMessage());
+ options.MapMessage("image", context => context.GetWeChatMessage());
+ options.MapMessage("voice", context => context.GetWeChatMessage());
+ options.MapMessage("video", context => context.GetWeChatMessage());
+ options.MapMessage("shortvideo", context => context.GetWeChatMessage());
+ options.MapMessage("location", context => context.GetWeChatMessage());
+ options.MapMessage("link", context => context.GetWeChatMessage());
+ });
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/AbpWeChatWorkMessageResolveOptions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/AbpWeChatWorkMessageResolveOptions.cs
new file mode 100644
index 000000000..e994957b3
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/AbpWeChatWorkMessageResolveOptions.cs
@@ -0,0 +1,25 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System;
+using System.Collections.Generic;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages;
+public class AbpWeChatWorkMessageResolveOptions
+{
+ public IDictionary> EventMaps { get; }
+ public IDictionary> MessageMaps { get; }
+ public AbpWeChatWorkMessageResolveOptions()
+ {
+ EventMaps = new Dictionary>();
+ MessageMaps = new Dictionary>();
+ }
+
+ public void MapEvent(string eventName, Func mapFunc)
+ {
+ EventMaps[eventName] = mapFunc;
+ }
+
+ public void MapMessage(string messageType, Func mapFunc)
+ {
+ MessageMaps[messageType] = mapFunc;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/BatchJobResultEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/BatchJobResultEvent.cs
new file mode 100644
index 000000000..504f8ec3c
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/BatchJobResultEvent.cs
@@ -0,0 +1,50 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 进入应用事件
+///
+[EventName("batch_job_result")]
+public class BatchJobResultEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 异步任务信息
+ ///
+ [XmlElement("BatchJob")]
+ public BatchJobResult BatchJob { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
+
+public class BatchJobResult
+{
+ ///
+ /// 异步任务id,最大长度为64字符
+ ///
+ [XmlElement("JobId")]
+ public string JobId { get; set; }
+ ///
+ /// 操作类型,字符串,
+ /// 目前分别有:
+ /// sync_user(增量更新成员)、
+ /// replace_user(全量覆盖成员)、
+ /// invite_user(邀请成员关注)、
+ /// replace_party(全量覆盖部门)
+ ///
+ [XmlElement("JobType")]
+ public string JobType { get; set; }
+ ///
+ /// 返回码
+ ///
+ [XmlElement("ErrCode")]
+ public int ErrCode { get; set; }
+ ///
+ /// 返回码
+ ///
+ [XmlElement("ErrMsg")]
+ public string ErrMsg { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/CreateDepartmentEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/CreateDepartmentEvent.cs
new file mode 100644
index 000000000..ae79490d6
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/CreateDepartmentEvent.cs
@@ -0,0 +1,21 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 新增部门事件
+///
+[EventName("create_party")]
+public class CreateDepartmentEvent : DepartmentUpdateEvent
+{
+ ///
+ /// 部门排序
+ ///
+ [XmlElement("Order", IsNullable = true)]
+ public int? Order { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/CreateUserEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/CreateUserEvent.cs
new file mode 100644
index 000000000..22320382e
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/CreateUserEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 新增成员事件
+///
+[EventName("create_user")]
+public class CreateUserEvent : UserChangeEvent
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/CustomMenuEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/CustomMenuEvent.cs
new file mode 100644
index 000000000..fb9aa9b82
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/CustomMenuEvent.cs
@@ -0,0 +1,22 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 自定义菜单事件
+///
+[EventName("custom_menu")]
+public class CustomMenuEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 事件KEY值
+ ///
+ [XmlElement("EventKey")]
+ public string EventKey { get; set; }
+
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/DeleteDepartmentEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/DeleteDepartmentEvent.cs
new file mode 100644
index 000000000..6827d82db
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/DeleteDepartmentEvent.cs
@@ -0,0 +1,22 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 删除部门事件
+///
+[EventName("delete_party")]
+public class DeleteDepartmentEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 部门Id
+ ///
+ [XmlElement("Id")]
+ public string Id { get; set; }
+
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/DeleteUserEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/DeleteUserEvent.cs
new file mode 100644
index 000000000..3d98b97fe
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/DeleteUserEvent.cs
@@ -0,0 +1,22 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 删除成员事件
+///
+[EventName("delete_user")]
+public class DeleteUserEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 变更信息的成员UserID
+ ///
+ [XmlElement("UserID")]
+ public string UserId { get; set; }
+
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/DepartmentUpdateEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/DepartmentUpdateEvent.cs
new file mode 100644
index 000000000..628dca80c
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/DepartmentUpdateEvent.cs
@@ -0,0 +1,24 @@
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 部门变更事件
+///
+public abstract class DepartmentUpdateEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 部门Id
+ ///
+ [XmlElement("Id")]
+ public int Id { get; set; }
+ ///
+ /// 部门名称
+ ///
+ [XmlElement("Name")]
+ public int Name { get; set; }
+ ///
+ /// 父部门id
+ ///
+ [XmlElement("ParentId", IsNullable = true)]
+ public int? ParentId { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/EnterAgentEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/EnterAgentEvent.cs
new file mode 100644
index 000000000..6902e593a
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/EnterAgentEvent.cs
@@ -0,0 +1,21 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 进入应用事件
+///
+[EventName("enter_agent")]
+public class EnterAgentEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 事件KEY值
+ ///
+ [XmlElement("EventKey")]
+ public string EventKey { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/GeoLocationMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/GeoLocationMessage.cs
new file mode 100644
index 000000000..8f19d4517
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/GeoLocationMessage.cs
@@ -0,0 +1,41 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 地理位置消息
+///
+[EventName("geo_location")]
+public class GeoLocationMessage : WeChatWorkGeneralMessage
+{
+ ///
+ /// 地理位置纬度
+ ///
+ [XmlElement("Location_X")]
+ public double Latitude { get; set; }
+ ///
+ /// 地理位置经度
+ ///
+ [XmlElement("Location_Y")]
+ public double Longitude { get; set; }
+ ///
+ /// 地图缩放大小
+ ///
+ [XmlElement("Scale")]
+ public double Scale { get; set; }
+ ///
+ /// 地理位置信息
+ ///
+ [XmlElement("Label")]
+ public string Label { get; set; }
+ ///
+ /// app类型,在企业微信固定返回wxwork,在微信不返回该字段
+ ///
+ [XmlElement("AppType")]
+ public string AppType { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/LinkMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/LinkMessage.cs
new file mode 100644
index 000000000..d0af61f62
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/LinkMessage.cs
@@ -0,0 +1,31 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 链接消息
+///
+[EventName("link")]
+public class LinkMessage : WeChatWorkGeneralMessage
+{
+ ///
+ /// 消息标题
+ ///
+ [XmlElement("Title")]
+ public string Title { get; set; }
+ ///
+ /// 消息描述
+ ///
+ [XmlElement("Description")]
+ public string Description { get; set; }
+ ///
+ /// 消息链接
+ ///
+ [XmlElement("Url")]
+ public string Url { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/MemberExtendAttribute.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/MemberExtendAttribute.cs
new file mode 100644
index 000000000..087516069
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/MemberExtendAttribute.cs
@@ -0,0 +1,50 @@
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+[XmlRoot("Item")]
+public class MemberExtendAttribute
+{
+ ///
+ /// 扩展属性类型: 0-本文 1-网页
+ ///
+ [XmlElement("Type")]
+ public byte Type { get; set; }
+ ///
+ /// 扩展属性类型: 0-本文 1-网页
+ ///
+ public MemberExtend Extend { get; set; }
+}
+
+public abstract class MemberExtend
+{
+}
+
+///
+/// 文本属性类型,扩展属性类型为0时填写
+///
+[XmlRoot("Text")]
+public class MemberTextExtend : MemberExtend
+{
+ ///
+ /// 文本属性内容
+ ///
+ [XmlElement("Value")]
+ public string Value { get; set;}
+}
+///
+/// 网页类型属性,扩展属性类型为1时填写
+///
+[XmlRoot("Web")]
+public class MemberWebExtend : MemberExtend
+{
+ ///
+ /// 网页的展示标题
+ ///
+ [XmlElement("Title")]
+ public string Title { get; set; }
+ ///
+ /// 网页的url
+ ///
+ [XmlElement("Url")]
+ public string Url { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/MenuClickJumpLinkEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/MenuClickJumpLinkEvent.cs
new file mode 100644
index 000000000..310feb627
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/MenuClickJumpLinkEvent.cs
@@ -0,0 +1,21 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 点击菜单跳转链接时的事件推送
+///
+[EventName("menu_click_jump_link")]
+public class MenuClickJumpLinkEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 事件KEY值
+ ///
+ [XmlElement("EventKey")]
+ public string EventKey { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureAlbumPushEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureAlbumPushEvent.cs
new file mode 100644
index 000000000..6ac952379
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureAlbumPushEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 弹出拍照或者相册发图的事件推送
+///
+[EventName("pic_photo_or_album")]
+public class PictureAlbumPushEvent : PicturePushEvent
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureMessage.cs
new file mode 100644
index 000000000..dedcc371b
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureMessage.cs
@@ -0,0 +1,26 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 图片消息
+///
+[EventName("picture")]
+public class PictureMessage : WeChatWorkGeneralMessage
+{
+ ///
+ /// 图片链接(由系统生成)
+ ///
+ [XmlElement("PicUrl")]
+ public string PicUrl { get; set; }
+ ///
+ /// 图片消息媒体id,可以调用获取临时素材接口拉取数据。
+ ///
+ [XmlElement("MediaId")]
+ public string MediaId { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PicturePushEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PicturePushEvent.cs
new file mode 100644
index 000000000..836e59a86
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PicturePushEvent.cs
@@ -0,0 +1,43 @@
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 弹出系统发图的事件推送
+///
+public abstract class PicturePushEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 事件KEY值
+ ///
+ [XmlElement("EventKey")]
+ public string EventKey { get; set; }
+ ///
+ /// 事件KEY值
+ ///
+ [XmlElement("SendPicsInfo")]
+ public PictureInfo SendPicsInfo { get; set; }
+}
+
+public class PictureInfo
+{
+ ///
+ /// 发送的图片数量
+ ///
+ [XmlElement("Count")]
+ public int Count { get; set; }
+ ///
+ /// 发送的图片数量
+ ///
+ [XmlArrayItem("Item")]
+ public Picture Picture { get; set; }
+}
+
+[XmlRoot("PicList")]
+public class Picture
+{
+ ///
+ /// 图片的MD5值,开发者若需要,可用于验证接收到图片
+ ///
+ [XmlElement("PicMd5Sum")]
+ public string PicMd5Sum { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureSystemPushEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureSystemPushEvent.cs
new file mode 100644
index 000000000..7106ef6e8
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureSystemPushEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 弹出系统拍照发图的事件推送
+///
+[EventName("pic_sysphoto")]
+public class PictureSystemPushEvent : PicturePushEvent
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureWeixinPushEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureWeixinPushEvent.cs
new file mode 100644
index 000000000..cb2fd3884
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/PictureWeixinPushEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 弹出微信相册发图器的事件推送
+///
+[EventName("pic_weixin")]
+public class PictureWeixinPushEvent : PicturePushEvent
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ReportingGeoLocationEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ReportingGeoLocationEvent.cs
new file mode 100644
index 000000000..e61abcf0f
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ReportingGeoLocationEvent.cs
@@ -0,0 +1,36 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 上报地理位置事件
+///
+[EventName("reporting_geo_location")]
+public class ReportingGeoLocationEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 地理位置纬度
+ ///
+ [XmlElement("Latitude")]
+ public double Latitude { get; set; }
+ ///
+ /// 地理位置经度
+ ///
+ [XmlElement("Longitude")]
+ public double Longitude { get; set; }
+ ///
+ /// 地理位置精度
+ ///
+ [XmlElement("Precision")]
+ public double Precision { get; set; }
+ ///
+ /// app类型,在企业微信固定返回wxwork,在微信不返回该字段
+ ///
+ [XmlElement("AppType")]
+ public string AppType { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ScanCodeEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ScanCodeEvent.cs
new file mode 100644
index 000000000..131b36cad
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ScanCodeEvent.cs
@@ -0,0 +1,33 @@
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 用户扫码事件
+///
+public abstract class ScanCodeEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 事件KEY值
+ ///
+ [XmlElement("EventKey")]
+ public string EventKey { get; set; }
+ ///
+ /// 扫描信息
+ ///
+ [XmlElement("ScanCodeInfo")]
+ public ScanCodeInfo ScanCodeInfo { get; set; }
+}
+
+public class ScanCodeInfo
+{
+ ///
+ /// 扫描类型,一般是qrcode
+ ///
+ [XmlElement("ScanType")]
+ public string ScanType { get; set; }
+ ///
+ /// 扫描结果,即二维码对应的字符串信息
+ ///
+ [XmlElement("ScanResult")]
+ public string ScanResult { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ScanCodePushEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ScanCodePushEvent.cs
new file mode 100644
index 000000000..9f89f0617
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ScanCodePushEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 自定义菜单事件
+///
+[EventName("scancode_push")]
+public class ScanCodePushEvent : ScanCodeEvent
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ScanCodeWaitMsgEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ScanCodeWaitMsgEvent.cs
new file mode 100644
index 000000000..e0cf6d723
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/ScanCodeWaitMsgEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 自定义菜单事件
+///
+[EventName("scancode_waitmsg")]
+public class ScanCodeWaitMsgEvent : ScanCodeEvent
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/TextMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/TextMessage.cs
new file mode 100644
index 000000000..ea1c3ac46
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/TextMessage.cs
@@ -0,0 +1,21 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 文本消息
+///
+[EventName("text")]
+public class TextMessage : WeChatWorkGeneralMessage
+{
+ ///
+ /// 文本消息内容
+ ///
+ [XmlElement("Content")]
+ public string Content { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UpdateDepartmentEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UpdateDepartmentEvent.cs
new file mode 100644
index 000000000..9ff67015e
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UpdateDepartmentEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 更新部门事件
+///
+[EventName("update_party")]
+public class UpdateDepartmentEvent : DepartmentUpdateEvent
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UpdateUserEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UpdateUserEvent.cs
new file mode 100644
index 000000000..b19136b47
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UpdateUserEvent.cs
@@ -0,0 +1,22 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 更新成员事件
+///
+[EventName("update_user")]
+public class UpdateUserEvent : UserChangeEvent
+{
+ ///
+ /// 新的UserID,变更时推送(userid由系统生成时可更改一次)
+ ///
+ [XmlElement("NewUserID")]
+ public string NewUserId { get; set; }
+
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserChangeEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserChangeEvent.cs
new file mode 100644
index 000000000..48c2d95be
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserChangeEvent.cs
@@ -0,0 +1,148 @@
+using System.Collections.Generic;
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 成员变更事件
+///
+public abstract class UserChangeEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 改变类型
+ ///
+ [XmlElement("ChangeType")]
+ public string ChangeType { get; set; }
+ ///
+ /// 成员UserID
+ ///
+ [XmlElement("UserID")]
+ public string UserId { get; set; }
+ ///
+ /// 成员名称;代开发自建应用需要管理员授权才返回
+ ///
+ [XmlElement("Name")]
+ public string Name { get; set; }
+ ///
+ /// 成员部门列表,仅返回该应用有查看权限的部门id
+ ///
+ [XmlElement("Department")]
+ public string Department { get; set; }
+ ///
+ /// 主部门
+ ///
+ [XmlElement("MainDepartment")]
+ public string MainDepartment { get; set; }
+ ///
+ /// 表示所在部门是否为部门负责人,
+ /// 0-否,
+ /// 1-是,
+ /// 顺序与Department字段的部门逐一对应。
+ /// 第三方通讯录应用或者授权了“组织架构信息-应用可获取企业的部门组织架构信息-部门负责人”权限的第三方应用和代开发应用可获取;
+ /// 对于非第三方创建的成员,第三方通讯录应用不可获取;
+ /// 上游企业不可获取下游企业成员该字段
+ ///
+ [XmlElement("IsLeaderInDept")]
+ public string IsLeaderInDept { get; set; }
+ ///
+ /// 直属上级UserID,最多1个。
+ /// 第三方通讯录应用或者授权了“组织架构信息-应用可获取可见范围内成员组织架构信息-直属上级”权限的第三方应用和代开发应用可获取;
+ /// 对于非第三方创建的成员,第三方通讯录应用不可获取;
+ /// 上游企业不可获取下游企业成员该字段
+ ///
+ [XmlElement("DirectLeader")]
+ public string DirectLeader { get; set; }
+ ///
+ /// 职位信息。
+ /// 长度为0~64个字节;代开发自建应用需要管理员授权才返回。
+ /// 上游共享的应用不返回该字段
+ ///
+ [XmlElement("Position")]
+ public string Position { get; set; }
+ ///
+ /// 手机号码,代开发自建应用需要管理员授权且成员oauth2授权获取;
+ /// 第三方仅通讯录应用可获取;
+ /// 对于非第三方创建的成员,第三方通讯录应用也不可获取;
+ /// 上游企业不可获取下游企业成员该字段
+ ///
+ [XmlElement("Mobile")]
+ public string Mobile { get; set; }
+ ///
+ /// 性别。
+ /// 0表示未定义,
+ /// 1表示男性,
+ /// 2表示女性。
+ /// 代开发自建应用需要管理员授权且成员oauth2授权获取;
+ /// 第三方仅通讯录应用可获取;
+ /// 对于非第三方创建的成员,第三方通讯录应用也不可获取;
+ /// 上游企业不可获取下游企业成员该字段。
+ /// 注:不可获取指返回值0
+ ///
+ [XmlElement("Gender")]
+ public byte Gender { get; set; }
+ ///
+ /// 邮箱,
+ /// 代开发自建应用需要管理员授权且成员oauth2授权获取;
+ /// 第三方仅通讯录应用可获取;
+ /// 对于非第三方创建的成员,第三方通讯录应用也不可获取;
+ /// 上游企业不可获取下游企业成员该字段
+ ///
+ [XmlElement("Email")]
+ public string Email { get; set; }
+ ///
+ /// 企业邮箱,
+ /// 代开发自建应用需要管理员授权且成员oauth2授权获取;
+ /// 第三方仅通讯录应用可获取;
+ /// 对于非第三方创建的成员,第三方通讯录应用也不可获取;
+ /// 上游企业不可获取下游企业成员该字段
+ ///
+ [XmlElement("BizMail")]
+ public string BizMail { get; set; }
+ ///
+ /// 激活状态:
+ /// 1=已激活
+ /// 2=已禁用
+ /// 4=未激活 已激活代表已激活企业微信或已关注微信插件(原企业号)
+ /// 5=成员退出
+ ///
+ [XmlElement("Status")]
+ public byte Status { get; set; }
+ ///
+ /// 头像url。
+ /// 注:如果要获取小图将url最后的”/0”改成”/100”即可。
+ /// 代开发自建应用需要管理员授权且成员oauth2授权获取;
+ /// 第三方仅通讯录应用可获取;
+ /// 对于非第三方创建的成员,第三方通讯录应用也不可获取;
+ /// 上游企业不可获取下游企业成员该字段
+ ///
+ [XmlElement("Avatar")]
+ public string Avatar { get; set; }
+ ///
+ /// 成员别名。
+ /// 上游共享的应用不返回该字段
+ ///
+ [XmlElement("Alias")]
+ public string Alias { get; set; }
+ ///
+ /// 座机;
+ /// 代开发自建应用需要管理员授权才返回。
+ /// 上游共享的应用不返回该字段
+ ///
+ [XmlElement("Telephone")]
+ public string Telephone { get; set; }
+ ///
+ /// 地址。
+ /// 代开发自建应用需要管理员授权且成员oauth2授权获取;
+ /// 第三方仅通讯录应用可获取;
+ /// 对于非第三方创建的成员,第三方通讯录应用也不可获取;
+ /// 上游企业不可获取下游企业成员该字段
+ ///
+ [XmlElement("Address")]
+ public string Address { get; set; }
+ ///
+ /// 扩展属性;
+ /// 代开发自建应用需要管理员授权才返回。
+ /// 上游共享的应用不返回该字段
+ ///
+ [XmlArray("ExtAttr")]
+ public List Extend { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserSubscribeEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserSubscribeEvent.cs
new file mode 100644
index 000000000..e08ce7da5
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserSubscribeEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 用户关注事件
+///
+[EventName("user_subscribe")]
+public class UserSubscribeEvent : WeChatWorkEventMessage
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserTagChangeEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserTagChangeEvent.cs
new file mode 100644
index 000000000..5e770c7e6
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserTagChangeEvent.cs
@@ -0,0 +1,41 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 标签成员变更事件
+///
+[EventName("update_tag")]
+public class UserTagChangeEvent : WeChatWorkEventMessage
+{
+ ///
+ /// 标签Id
+ ///
+ [XmlElement("TagId")]
+ public string TagId { get; set; }
+ ///
+ /// 标签中新增的成员userid列表,用逗号分隔
+ ///
+ [XmlElement("AddUserItems", IsNullable = true)]
+ public string AddUserItems { get; set; }
+ ///
+ /// 标签中删除的成员userid列表,用逗号分隔
+ ///
+ [XmlElement("DelUserItems", IsNullable = true)]
+ public string DelUserItems { get; set; }
+ ///
+ /// 标签中新增的部门id列表,用逗号分隔
+ ///
+ [XmlElement("AddPartyItems", IsNullable = true)]
+ public string AddPartyItems { get; set; }
+ ///
+ /// 标签中删除的部门id列表,用逗号分隔
+ ///
+ [XmlElement("DelPartyItems", IsNullable = true)]
+ public string DelPartyItems { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserUnSubscribeEvent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserUnSubscribeEvent.cs
new file mode 100644
index 000000000..be1116314
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/UserUnSubscribeEvent.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 用户取消关注事件
+///
+[EventName("user_un_subscribe")]
+public class UserUnSubscribeEvent : WeChatWorkEventMessage
+{
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkEventMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/VideoMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/VideoMessage.cs
new file mode 100644
index 000000000..729591b92
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/VideoMessage.cs
@@ -0,0 +1,26 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 视频消息
+///
+[EventName("video")]
+public class VideoMessage : WeChatWorkGeneralMessage
+{
+ ///
+ /// 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
+ ///
+ [XmlElement("ThumbMediaId")]
+ public string ThumbMediaId { get; set; }
+ ///
+ /// 视频消息媒体id,可以调用获取临时素材接口拉取数据。
+ ///
+ [XmlElement("MediaId")]
+ public string MediaId { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/VoiceMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/VoiceMessage.cs
new file mode 100644
index 000000000..ac4233ce3
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/Models/VoiceMessage.cs
@@ -0,0 +1,26 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages.Models;
+///
+/// 语音消息
+///
+[EventName("voice")]
+public class VoiceMessage : WeChatWorkGeneralMessage
+{
+ ///
+ /// 语音格式,如amr,speex等
+ ///
+ [XmlElement("Format")]
+ public string Format { get; set; }
+ ///
+ /// 语音消息媒体id,可以调用获取临时素材接口拉取该媒体
+ ///
+ [XmlElement("MediaId")]
+ public string MediaId { get; set; }
+ public override WeChatMessageEto ToEto()
+ {
+ return new WeChatWorkGeneralMessageEto(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkEventMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkEventMessage.cs
new file mode 100644
index 000000000..8760cc30e
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkEventMessage.cs
@@ -0,0 +1,20 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages;
+///
+/// 企业微信事件消息
+///
+public abstract class WeChatWorkEventMessage : WeChatMessage
+{
+ ///
+ /// 事件类型
+ ///
+ [XmlElement("Event")]
+ public string Event { get; set; }
+ ///
+ /// 企业应用的id,整型。可在应用的设置页面查看
+ ///
+ [XmlElement("AgentID")]
+ public int AgentId { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkEventMessageEto.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkEventMessageEto.cs
new file mode 100644
index 000000000..3d9d67723
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkEventMessageEto.cs
@@ -0,0 +1,19 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages;
+
+[GenericEventName(Prefix = "wechat.work.events")]
+public class WeChatWorkEventMessageEto : WeChatMessageEto
+ where TEvent : WeChatWorkEventMessage
+{
+ public TEvent Event { get; set; }
+ public WeChatWorkEventMessageEto()
+ {
+
+ }
+ public WeChatWorkEventMessageEto(TEvent @event)
+ {
+ Event = @event;
+ }
+}
\ No newline at end of file
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkGeneralMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkGeneralMessage.cs
new file mode 100644
index 000000000..6833cf564
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkGeneralMessage.cs
@@ -0,0 +1,15 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using System.Xml.Serialization;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages;
+///
+/// 企业微信普通消息
+///
+public abstract class WeChatWorkGeneralMessage : WeChatGeneralMessage
+{
+ ///
+ /// 企业应用的id,整型。可在应用的设置页面查看
+ ///
+ [XmlElement("AgentID")]
+ public int AgentId { get; set; }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkGeneralMessageEto.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkGeneralMessageEto.cs
new file mode 100644
index 000000000..734642916
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work.Common/LINGYUN/Abp/WeChat/Work/Common/Messages/WeChatWorkGeneralMessageEto.cs
@@ -0,0 +1,19 @@
+using LINGYUN.Abp.WeChat.Common.Messages;
+using Volo.Abp.EventBus;
+
+namespace LINGYUN.Abp.WeChat.Work.Common.Messages;
+
+[GenericEventName(Prefix = "wechat.work.messages")]
+public class WeChatWorkGeneralMessageEto : WeChatMessageEto
+ where TMessage : WeChatWorkGeneralMessage
+{
+ public TMessage Message { get; set; }
+ public WeChatWorkGeneralMessageEto()
+ {
+
+ }
+ public WeChatWorkGeneralMessageEto(TMessage message)
+ {
+ Message = message;
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN.Abp.WeChat.Work.csproj b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN.Abp.WeChat.Work.csproj
index 42ec2af81..f1a173153 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN.Abp.WeChat.Work.csproj
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN.Abp.WeChat.Work.csproj
@@ -23,6 +23,7 @@
+
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkModule.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkModule.cs
index fe43837a0..2ba94b9ee 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkModule.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/AbpWeChatWorkModule.cs
@@ -1,4 +1,6 @@
using LINGYUN.Abp.Features.LimitValidation;
+using LINGYUN.Abp.WeChat.Common;
+using LINGYUN.Abp.WeChat.Common.Localization;
using LINGYUN.Abp.WeChat.Work.Localization;
using Microsoft.Extensions.DependencyInjection;
using System;
@@ -16,7 +18,8 @@ namespace LINGYUN.Abp.WeChat.Work;
typeof(AbpCachingModule),
typeof(AbpExceptionHandlingModule),
typeof(AbpFeaturesLimitValidationModule),
- typeof(AbpSettingsModule))]
+ typeof(AbpSettingsModule),
+ typeof(AbpWeChatCommonModule))]
public class AbpWeChatWorkModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
@@ -33,6 +36,7 @@ public class AbpWeChatWorkModule : AbpModule
{
options.Resources
.Add("zh-Hans")
+ .AddBaseTypes(typeof(WeChatCommonResource))
.AddVirtualJson("/LINGYUN/Abp/WeChat/Work/Localization/Resources");
});
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageManager.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageManager.cs
similarity index 94%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageManager.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageManager.cs
index 74598baa9..e85edb5e6 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageManager.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageManager.cs
@@ -1,7 +1,7 @@
using System.Threading;
using System.Threading.Tasks;
-namespace LINGYUN.Abp.WeChat.Work.Message;
+namespace LINGYUN.Abp.WeChat.Work.Messages;
///
/// 企业微信消息管理器
///
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageSender.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageSender.cs
similarity index 96%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageSender.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageSender.cs
index aedc69f81..db393d368 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/IWeChatWorkMessageSender.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/IWeChatWorkMessageSender.cs
@@ -2,7 +2,7 @@
using System.Threading;
using System.Threading.Tasks;
-namespace LINGYUN.Abp.WeChat.Work.Message;
+namespace LINGYUN.Abp.WeChat.Work.Messages;
///
/// 消息发送接口
///
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/MarkdownMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/MarkdownMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/MarkdownMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/MarkdownMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/MediaMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/MediaMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/MediaMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/MediaMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/MiniProgramMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/MiniProgramMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/MiniProgramMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/MiniProgramMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/MpNewMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/MpNewMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/MpNewMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/MpNewMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/NewMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/NewMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/NewMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/NewMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/TextCardMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TextCardMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/TextCardMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TextCardMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/TextMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TextMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/TextMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/TextMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/VideoMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/VideoMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/VideoMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/VideoMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatFileMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatFileMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatFileMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatFileMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatImageMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatImageMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatImageMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatImageMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatMarkdownMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatMarkdownMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatMarkdownMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatMarkdownMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatMpNewMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatMpNewMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatMpNewMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatMpNewMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatNewMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatNewMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatNewMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatNewMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatTextCardMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatTextCardMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatTextCardMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatTextCardMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatTextMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatTextMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatTextMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatTextMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatVideoMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatVideoMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatVideoMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatVideoMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatVoiceMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatVoiceMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkAppChatVoiceMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkAppChatVoiceMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkFileMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkFileMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkFileMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkFileMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkImageMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkImageMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkImageMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkImageMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMarkdownMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkMarkdownMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMarkdownMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkMarkdownMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMiniProgramMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkMiniProgramMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMiniProgramMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkMiniProgramMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMpNewMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkMpNewMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkMpNewMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkMpNewMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkNewMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkNewMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkNewMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkNewMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkTextCardMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkTextCardMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkTextCardMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkTextCardMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkTextMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkTextMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkTextMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkTextMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkVideoMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkVideoMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkVideoMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkVideoMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkVoiceMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkVoiceMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Models/WeChatWorkVoiceMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Models/WeChatWorkVoiceMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Request/WeChatWorkMessageReCallRequest.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Request/WeChatWorkMessageReCallRequest.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Request/WeChatWorkMessageReCallRequest.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Request/WeChatWorkMessageReCallRequest.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Request/WeChatWorkMessageRequest.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Request/WeChatWorkMessageRequest.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Request/WeChatWorkMessageRequest.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Request/WeChatWorkMessageRequest.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Response/WeChatWorkMessageResponse.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Response/WeChatWorkMessageResponse.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Response/WeChatWorkMessageResponse.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Response/WeChatWorkMessageResponse.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCard.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCard.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCard.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCard.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardAction.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardAction.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardAction.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardAction.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardActionMenu.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardActionMenu.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardActionMenu.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardActionMenu.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardCardAction.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardCardAction.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardCardAction.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardCardAction.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardEmphasisContent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardEmphasisContent.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardEmphasisContent.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardEmphasisContent.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardHorizontalContent.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardHorizontalContent.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardHorizontalContent.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardHorizontalContent.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardJump.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardJump.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardJump.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardJump.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardMainTitle.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardMainTitle.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardMainTitle.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardMainTitle.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardQuoteArea.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardQuoteArea.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardQuoteArea.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardQuoteArea.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardSource.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardSource.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TemplateCardSource.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TemplateCardSource.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TextTemplateCard.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TextTemplateCard.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/TextTemplateCard.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/TextTemplateCard.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/WeChatWorkTemplateCardMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/WeChatWorkTemplateCardMessage.cs
similarity index 100%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/Templates/WeChatWorkTemplateCardMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/Templates/WeChatWorkTemplateCardMessage.cs
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkAppChatMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkAppChatMessage.cs
similarity index 96%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkAppChatMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkAppChatMessage.cs
index b88c0750b..d842baee4 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkAppChatMessage.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkAppChatMessage.cs
@@ -2,7 +2,7 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;
-namespace LINGYUN.Abp.WeChat.Work.Message;
+namespace LINGYUN.Abp.WeChat.Work.Messages;
///
/// 企业微信群聊消息
///
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessage.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessage.cs
similarity index 97%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessage.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessage.cs
index b3c4550e0..9fce54397 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessage.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessage.cs
@@ -2,7 +2,7 @@
using Newtonsoft.Json;
using System.Text.Json.Serialization;
-namespace LINGYUN.Abp.WeChat.Work.Message;
+namespace LINGYUN.Abp.WeChat.Work.Messages;
///
/// 企业微信消息
///
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageManager.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageManager.cs
similarity index 97%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageManager.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageManager.cs
index 1a8fdbb2e..e7d46b47e 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageManager.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageManager.cs
@@ -7,7 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
-namespace LINGYUN.Abp.WeChat.Work.Message;
+namespace LINGYUN.Abp.WeChat.Work.Messages;
public class WeChatWorkMessageManager : IWeChatWorkMessageManager, ISingletonDependency
{
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageSender.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs
similarity index 98%
rename from aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageSender.cs
rename to aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs
index c08727721..8867d9744 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Message/WeChatWorkMessageSender.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Messages/WeChatWorkMessageSender.cs
@@ -11,7 +11,7 @@ using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Features;
-namespace LINGYUN.Abp.WeChat.Work.Message;
+namespace LINGYUN.Abp.WeChat.Work.Messages;
[RequiresFeature(WeChatWorkFeatureNames.Enable)]
public class WeChatWorkMessageSender : IWeChatWorkMessageSender, ISingletonDependency
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/AbpWeChatWorkCryptoException.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/AbpWeChatWorkCryptoException.cs
deleted file mode 100644
index 51e99a5c4..000000000
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/AbpWeChatWorkCryptoException.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Runtime.Serialization;
-
-namespace LINGYUN.Abp.WeChat.Work.Security;
-public class AbpWeChatWorkCryptoException : AbpWeChatWorkException
-{
- public AbpWeChatWorkCryptoException()
- {
- }
-
- public AbpWeChatWorkCryptoException(
- SerializationInfo serializationInfo,
- StreamingContext context) : base(serializationInfo, context)
- {
- }
-
- public AbpWeChatWorkCryptoException(
- string agentId,
- string message = null,
- string details = null,
- Exception innerException = null)
- : this(agentId, "WeChatWork:100400", message, details, innerException)
- {
- }
-
- public AbpWeChatWorkCryptoException(
- string agentId,
- string code = null,
- string message = null,
- string details = null,
- Exception innerException = null)
- : base(code, message, details, innerException)
- {
- WithData("AgentId", agentId);
- }
-}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/IWeChatWorkCryptoService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/IWeChatWorkCryptoService.cs
deleted file mode 100644
index 918652a63..000000000
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/IWeChatWorkCryptoService.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using LINGYUN.Abp.WeChat.Work.Security.Models;
-
-namespace LINGYUN.Abp.WeChat.Work.Security;
-///
-/// 企业微信加解密接口
-///
-public interface IWeChatWorkCryptoService
-{
- ///
- /// 校验
- ///
- ///
- ///
- ///
- string Validation(WeChatWorkCryptoEchoData data);
- ///
- /// 解密
- ///
- ///
- ///
- ///
- string Decrypt(WeChatWorkCryptoDecryptData data);
- ///
- /// 加密
- ///
- ///
- ///
- ///
- string Encrypt(WeChatWorkCryptoData data);
-}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoDecryptData.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoDecryptData.cs
deleted file mode 100644
index 95b67da67..000000000
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoDecryptData.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace LINGYUN.Abp.WeChat.Work.Security.Models;
-public class WeChatWorkCryptoDecryptData : WeChatWorkCryptoData
-{
- public string PostData { get; }
- public WeChatWorkCryptoDecryptData(
- string postData,
- string receiveId,
- string token,
- string encodingAESKey,
- string msgSignature,
- string timeStamp,
- string nonce) : base(receiveId, token, encodingAESKey, msgSignature, timeStamp, nonce)
- {
- PostData = postData;
- }
-}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoEchoData.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoEchoData.cs
deleted file mode 100644
index e9a32bd86..000000000
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/Models/WeChatWorkCryptoEchoData.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace LINGYUN.Abp.WeChat.Work.Security.Models;
-public class WeChatWorkCryptoEchoData : WeChatWorkCryptoData
-{
- public string EchoStr { get; }
- public WeChatWorkCryptoEchoData(
- string echoStr,
- string receiveId,
- string token,
- string encodingAESKey,
- string msgSignature,
- string timeStamp,
- string nonce) : base(receiveId, token, encodingAESKey, msgSignature, timeStamp, nonce)
- {
- EchoStr = echoStr;
- }
-}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoService.cs
deleted file mode 100644
index 914a11217..000000000
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/LINGYUN/Abp/WeChat/Work/Security/WeChatWorkCryptoService.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using LINGYUN.Abp.WeChat.Work.Security.Models;
-using LINGYUN.Abp.WeChat.Work.Utils;
-using Volo.Abp.DependencyInjection;
-
-namespace LINGYUN.Abp.WeChat.Work.Security;
-
-public class WeChatWorkCryptoService : IWeChatWorkCryptoService, ISingletonDependency
-{
- public string Decrypt(WeChatWorkCryptoDecryptData data)
- {
- var crypto = new WXBizMsgCrypt(
- data.Token,
- data.EncodingAESKey,
- data.ReceiveId);
-
- var retMsg = "";
- var ret = crypto.DecryptMsg(
- data.MsgSignature,
- data.TimeStamp,
- data.Nonce,
- data.PostData,
- ref retMsg);
-
- if (ret != 0)
- {
- throw new AbpWeChatWorkCryptoException(data.ReceiveId, code: $"WeChatWork:{ret}");
- }
-
- return retMsg;
- }
-
- public string Encrypt(WeChatWorkCryptoData data)
- {
- var crypto = new WXBizMsgCrypt(
- data.Token,
- data.EncodingAESKey,
- data.ReceiveId);
-
- var retMsg = "";
-
- var ret = crypto.EncryptMsg(
- data.MsgSignature,
- data.TimeStamp,
- data.Nonce,
- ref retMsg);
-
- if (ret != 0)
- {
- throw new AbpWeChatWorkCryptoException(data.ReceiveId, code: $"WeChatWork:{ret}");
- }
-
- return retMsg;
- }
-
- public string Validation(WeChatWorkCryptoEchoData data)
- {
- var crypto = new WXBizMsgCrypt(
- data.Token,
- data.EncodingAESKey,
- data.ReceiveId);
-
- var retMsg = "";
-
- var ret = crypto.VerifyURL(
- data.MsgSignature,
- data.TimeStamp,
- data.Nonce,
- data.EchoStr,
- ref retMsg);
-
- if (ret != 0)
- {
- throw new AbpWeChatWorkCryptoException(data.ReceiveId, code: $"WeChatWork:{ret}");
- }
-
- return retMsg;
- }
-}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Message.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Message.cs
index b7396e1a0..56a30109b 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Message.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat.Work/System/Net/Http/HttpClientWeChatWorkRequestExtensions.Message.cs
@@ -1,4 +1,4 @@
-using LINGYUN.Abp.WeChat.Work.Message;
+using LINGYUN.Abp.WeChat.Work.Messages;
using LINGYUN.Abp.WeChat.Work.Message.Request;
using System.Text;
using System.Threading;
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN.Abp.WeChat.csproj b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN.Abp.WeChat.csproj
index 696105297..6c4f0eb30 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN.Abp.WeChat.csproj
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN.Abp.WeChat.csproj
@@ -23,4 +23,8 @@
+
+
+
+
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/AbpWeChatModule.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/AbpWeChatModule.cs
index 6d5858464..5245c8a4b 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/AbpWeChatModule.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/AbpWeChatModule.cs
@@ -1,40 +1,49 @@
-using LINGYUN.Abp.WeChat.Localization;
+using LINGYUN.Abp.WeChat.Common;
+using LINGYUN.Abp.WeChat.Common.Localization;
+using LINGYUN.Abp.WeChat.Localization;
using Microsoft.Extensions.DependencyInjection;
using System;
using Volo.Abp.Caching;
using Volo.Abp.Features;
using Volo.Abp.Localization;
+using Volo.Abp.Localization.ExceptionHandling;
using Volo.Abp.Modularity;
using Volo.Abp.Settings;
using Volo.Abp.VirtualFileSystem;
-namespace LINGYUN.Abp.WeChat
+namespace LINGYUN.Abp.WeChat;
+
+[DependsOn(
+ typeof(AbpCachingModule),
+ typeof(AbpFeaturesModule),
+ typeof(AbpSettingsModule),
+ typeof(AbpWeChatCommonModule))]
+public class AbpWeChatModule : AbpModule
{
- [DependsOn(
- typeof(AbpCachingModule),
- typeof(AbpFeaturesModule),
- typeof(AbpSettingsModule))]
- public class AbpWeChatModule : AbpModule
+ public override void ConfigureServices(ServiceConfigurationContext context)
{
- public override void ConfigureServices(ServiceConfigurationContext context)
+ Configure(options =>
{
- Configure(options =>
- {
- options.FileSets.AddEmbedded();
- });
+ options.FileSets.AddEmbedded();
+ });
+
+ Configure(options =>
+ {
+ options.Resources
+ .Add("zh-Hans")
+ .AddBaseTypes(typeof(WeChatCommonResource))
+ .AddVirtualJson("/LINGYUN/Abp/WeChat/Localization/Resources");
+ });
+
+ Configure(options =>
+ {
+ options.MapCodeNamespace(WeChatErrorCodes.Namespace, typeof(WeChatResource));
+ });
- Configure(options =>
+ context.Services.AddHttpClient(AbpWeChatGlobalConsts.HttpClient,
+ options =>
{
- options.Resources
- .Add("zh-Hans")
- .AddVirtualJson("/LINGYUN/Abp/WeChat/Localization/Resources");
+ options.BaseAddress = new Uri("https://api.weixin.qq.com");
});
-
- context.Services.AddHttpClient(AbpWeChatGlobalConsts.HttpClient,
- options =>
- {
- options.BaseAddress = new Uri("https://api.weixin.qq.com");
- });
- }
}
}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Crypto/IWeChatCryptoService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Crypto/IWeChatCryptoService.cs
deleted file mode 100644
index da38022a5..000000000
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Crypto/IWeChatCryptoService.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace LINGYUN.Abp.WeChat.Crypto
-{
- public interface IWeChatCryptoService
- {
- string Decrypt(string encryptedData, string iv, string sessionKey);
- }
-}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Crypto/WeChatCryptoService.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Crypto/WeChatCryptoService.cs
deleted file mode 100644
index 7bb98265e..000000000
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Crypto/WeChatCryptoService.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Security.Cryptography;
-using System.Text;
-using Volo.Abp.DependencyInjection;
-
-namespace LINGYUN.Abp.WeChat.Crypto
-{
- public class WeChatCryptoService : IWeChatCryptoService, ITransientDependency
- {
- public virtual string Decrypt(string encryptedData, string iv, string sessionKey)
- {
- using var aes = new AesCryptoServiceProvider();
- aes.Mode = CipherMode.CBC;
- aes.BlockSize = 128;
- // 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
- aes.Padding = PaddingMode.PKCS7;
-
- //格式化待处理字符串
- // 对称解密的目标密文为 Base64_Decode(encryptedData)。
- byte[] byte_encryptedData = Convert.FromBase64String(encryptedData);
- // 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。
- byte[] byte_iv = Convert.FromBase64String(iv);
- // 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
- byte[] byte_sessionKey = Convert.FromBase64String(sessionKey);
-
- //根据设置好的数据生成解密器实例
- using var transform = aes.CreateDecryptor(byte_iv, byte_sessionKey);
- //解密
- byte[] final = transform.TransformFinalBlock(byte_encryptedData, 0, byte_encryptedData.Length);
-
- //生成结果
- string result = Encoding.UTF8.GetString(final);
- return result;
- }
- }
-}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/OpenId/WeChatOpenIdResponse.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/OpenId/WeChatOpenIdResponse.cs
index 81261ec9f..e2760383d 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/OpenId/WeChatOpenIdResponse.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/OpenId/WeChatOpenIdResponse.cs
@@ -1,4 +1,5 @@
-using Newtonsoft.Json;
+using LINGYUN.Abp.WeChat.Common;
+using Newtonsoft.Json;
using System;
namespace LINGYUN.Abp.WeChat.OpenId
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Token/WeChatTokenResponse.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Token/WeChatTokenResponse.cs
index 933534984..166b9d518 100644
--- a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Token/WeChatTokenResponse.cs
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/Token/WeChatTokenResponse.cs
@@ -1,5 +1,5 @@
-using Newtonsoft.Json;
-using Volo.Abp;
+using LINGYUN.Abp.WeChat.Common;
+using Newtonsoft.Json;
namespace LINGYUN.Abp.WeChat.Token
{
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/WeChatErrorCodes.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/WeChatErrorCodes.cs
new file mode 100644
index 000000000..b10cfd204
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/WeChatErrorCodes.cs
@@ -0,0 +1,5 @@
+namespace LINGYUN.Abp.WeChat;
+public static class WeChatErrorCodes
+{
+ public const string Namespace = "WeChat";
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/WeChatRequest.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/WeChatRequest.cs
new file mode 100644
index 000000000..b80ab03d7
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/WeChatRequest.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace LINGYUN.Abp.WeChat;
+
+[Serializable]
+public abstract class WeChatRequest
+{
+ public virtual string SerializeToJson()
+ {
+ return WeChatObjectSerializeExtensions.SerializeToJson(this);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/WeChatResponse.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/WeChatResponse.cs
new file mode 100644
index 000000000..3301c9e09
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/LINGYUN/Abp/WeChat/WeChatResponse.cs
@@ -0,0 +1,35 @@
+using LINGYUN.Abp.WeChat.Common;
+using Newtonsoft.Json;
+using System;
+using System.Text.Json.Serialization;
+
+namespace LINGYUN.Abp.WeChat;
+///
+/// 微信请求响应
+///
+[Serializable]
+public class WeChatResponse
+{
+ ///
+ /// 错误码
+ ///
+ [JsonProperty("errcode")]
+ [JsonPropertyName("errcode")]
+ public int ErrorCode { get; set; }
+ ///
+ /// 错误消息
+ ///
+ [JsonProperty("errmsg")]
+ [JsonPropertyName("errmsg")]
+ public string ErrorMessage { get; set; }
+
+ public bool IsSuccessed => ErrorCode == 0;
+
+ public void ThrowIfNotSuccess()
+ {
+ if (ErrorCode != 0)
+ {
+ throw new AbpWeChatException($"WeChat:{ErrorCode}", $"Wechat work request error:{ErrorMessage}");
+ }
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/System/Net/Http/HttpResponseDeserializeExtensions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/System/Net/Http/HttpResponseDeserializeExtensions.cs
new file mode 100644
index 000000000..53ae5baf0
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/System/Net/Http/HttpResponseDeserializeExtensions.cs
@@ -0,0 +1,23 @@
+using LINGYUN.Abp.WeChat;
+using LINGYUN.Abp.WeChat.Common;
+using System.Threading.Tasks;
+
+namespace System.Net.Http;
+public static class HttpResponseDeserializeExtensions
+{
+ public static void ThrowNotSuccessStatusCode(this HttpResponseMessage response)
+ {
+ if (!response.IsSuccessStatusCode)
+ {
+ throw new AbpWeChatException($"Wechat request error: {response.StatusCode} - {response.ReasonPhrase}");
+ }
+ }
+
+ public async static Task DeserializeObjectAsync(this HttpResponseMessage response) where T : WeChatResponse
+ {
+ response.ThrowNotSuccessStatusCode();
+ var responseContent = await response.Content.ReadAsStringAsync();
+
+ return responseContent.DeserializeObject();
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/System/WeChatObjectSerializeExtensions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/System/WeChatObjectSerializeExtensions.cs
new file mode 100644
index 000000000..450e21310
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/System/WeChatObjectSerializeExtensions.cs
@@ -0,0 +1,10 @@
+using Newtonsoft.Json;
+
+namespace System;
+internal static class WeChatObjectSerializeExtensions
+{
+ public static string SerializeToJson(this object @object)
+ {
+ return JsonConvert.SerializeObject(@object);
+ }
+}
diff --git a/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/System/WeChatResponseDeserializeExtensions.cs b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/System/WeChatResponseDeserializeExtensions.cs
new file mode 100644
index 000000000..6d8abda93
--- /dev/null
+++ b/aspnet-core/framework/wechat/LINGYUN.Abp.WeChat/System/WeChatResponseDeserializeExtensions.cs
@@ -0,0 +1,11 @@
+using LINGYUN.Abp.WeChat;
+using Newtonsoft.Json;
+
+namespace System;
+public static class WeChatResponseDeserializeExtensions
+{
+ public static T DeserializeObject(this string responseContent) where T : WeChatResponse
+ {
+ return JsonConvert.DeserializeObject(responseContent);
+ }
+}
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
index baceecefa..b4c65a86e 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/LY.MicroService.Applications.Single.csproj
@@ -92,6 +92,8 @@
+
+
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
index 71779aad2..d74fd53e9 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.Configure.cs
@@ -337,8 +337,9 @@ public partial class MicroServiceApplicationsSingleModule
Configure(options =>
{
options.NodeName = ApplicationName;
- options.JobCleanEnabled = true;
- options.JobFetchEnabled = true;
+ options.JobCleanEnabled = false;
+ options.JobFetchEnabled = false;
+ options.JobCheckEnabled = false;
});
}
@@ -671,6 +672,7 @@ public partial class MicroServiceApplicationsSingleModule
options.IsEnabled = true;
options.IgnoreNamespaces.Add("Elsa");
options.IgnoreNamespaces.Add("LINGYUN.Abp.OssManagement");
+ options.IgnoreNamespaces.Add("LINGYUN.Abp.WeChat");
});
}
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
index 3dc099a12..03ee3168a 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/MicroServiceApplicationsSingleModule.cs
@@ -240,6 +240,8 @@ namespace LY.MicroService.Applications.Single;
typeof(AbpNotificationsWeChatMiniProgramModule),
typeof(AbpWeChatMiniProgramModule),
typeof(AbpWeChatOfficialModule),
+ typeof(AbpWeChatOfficialApplicationModule),
+ typeof(AbpWeChatOfficialHttpApiModule),
typeof(AbpWeChatWorkModule),
typeof(AbpWeChatWorkApplicationModule),
typeof(AbpWeChatWorkHttpApiModule),
diff --git a/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json b/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json
index b95142d78..b9fee327d 100644
--- a/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json
+++ b/aspnet-core/services/LY.MicroService.Applications.Single/Properties/launchSettings.json
@@ -12,7 +12,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
- "applicationUrl": "http://127.0.0.1:30001",
+ "applicationUrl": "http://0.0.0.0:30001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
}