Senparc.Weixin.MP SDK 微信公眾平台開發教程(二十二):在 .NET Core 2.0/3.0 中使用 MessageHandler 中間件
- 2019 年 10 月 15 日
- 筆記
概述
在 《Senparc.Weixin.MP SDK 微信公眾平台開發教程(六):了解MessageHandler》 中我們已經了解了 MessageHandler 的運行原理和使用方法,從我設計了這種處理方式到現在已經 6 年多的時間,這是一種非常穩定而且(在如此複雜環境下)相對易於維護的的設計。
現在 .NET Core 已經進入了一個新的階段,隨着 .NET Core 3.0 的發佈,我決在兼容原有方式不改變的情況下,讓 MessageHandler 可以支持 .NET Core(或者說 .NET Standard 2.0+)的中間件,為開發者提供另外一種使用 SDK 的方式。
新的設計將達到如下目標或新特性:
- 不再依賴 Controller/Action,因此也不再依賴 FixWeixinBugWeixinResult 等一系列因為歷史原因而存在的類和方法。你不必再為處理微信消息創建任何 Controller 或 WebApi;
- 不影響現有的運行效率,甚至更快;
- 默認僅支持異步方法;
- 更輕量、更少的配置代碼
- 高度可用,不閹割任何功能。
準備開發
- 開發環境:Visual Studio 2019 / Visual Studio Code
- .NET 版本:.NET Core 3.0
- 關於 .NET Core 的中間件介紹:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-3.0
開發步驟
第一步:創建一個 .NET Core 3.0 Web 項目(空):
原始的 startup.cs 如下:

1 1 namespace WechatMessageSample 2 2 { 3 3 public class Startup 4 4 { 5 5 // This method gets called by the runtime. Use this method to add services to the container. 6 6 // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 7 7 public void ConfigureServices(IServiceCollection services) 8 8 { 9 9 } 10 10 11 11 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 12 12 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 13 13 { 14 14 if (env.IsDevelopment()) 15 15 { 16 16 app.UseDeveloperExceptionPage(); 17 17 } 18 18 19 19 app.UseRouting(); 20 20 21 21 app.UseEndpoints(endpoints => 22 22 { 23 23 endpoints.MapGet("/", async context => 24 24 { 25 25 await context.Response.WriteAsync("Hello World!"); 26 26 }); 27 27 }); 28 28 } 29 29 } 30 30 }
View Code
第二步:使用 Nuget 添加 Senparc.Weixin SDK:
上圖標註出來的 3 個包分別是:公眾號、小程序和企業微信,本實例主要演示公眾號,其他兩個平台使用方法是一致的,可以舉一反三,不再贅述。
第三步:創建自定義消息處理器(MessageHandler):
1 /// <summary> 2 /// 自定義公眾號消息處理 3 /// </summary> 4 public class CustomMpMessageHandler : Senparc.Weixin.MP.MessageHandlers.MessageHandler<DefaultMpMessageContext> 5 { 6 public CustomMpMessageHandler(Stream inputStream, PostModel postModel, int maxRecordCount = 0, bool onlyAllowEcryptMessage = false, DeveloperInfo developerInfo = null) 7 : base(inputStream, postModel, maxRecordCount, onlyAllowEcryptMessage, developerInfo) 8 { 9 } 10 11 public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage) 12 { 13 throw new NotImplementedException(); 14 } 15 }
一般情況下,此文件是獨立的 .cs 文件,當前實例為了方便展示,一起寫在了 startup.cs 文件中。
以上是一個默認的空的 MessageHandler,還不能正常運行,我們為 DefaultResponseMessage 添加默認的返回消息:
1 public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage) 2 { 3 var responseMessage = base.CreateResponseMessage<ResponseMessageNews>(); 4 responseMessage.Articles.Add(new Article() 5 { 6 Title = "歡迎使用 Senparc.Weixin SDK", 7 Description = "這是一條默認消息", 8 PicUrl = "https://sdk.weixin.senparc.com/images/v2/logo.png", 9 Url = "https://weixin.senparc.com" 10 }); 11 return responseMessage; 12 }
也可以再創建一系列響應規則,例如處理文本信息,並返回一條文本:
1 public override async Task<IResponseMessageBase> OnTextRequestAsync(RequestMessageText requestMessage) 2 { 3 var responseMessage = base.CreateResponseMessage<ResponseMessageText>(); 4 responseMessage.Content = $"您發送了文字:{requestMessage.Content}"; 5 return responseMessage; 6 }
以此類推,可以為每一種類型的消息創建處理過程。
為了方便接下去的中間件對接,再創建一個初始化當前自定義 MessageHandler 示例的委託:
1 public static Func<Stream, PostModel, int, CustomMpMessageHandler> GenerateMessageHandler = (stream, postModel, maxRecordCount) 2 => new CustomMpMessageHandler(stream, postModel, maxRecordCount, false);
上述 CustomMpMessageHandler 構造函數中的最後一個 bool 參數(onlyAllowEcryptMessage),提供了一種加強的安全策略,可以指定是否只允許處理加密消息,開啟之後,試圖使用明文進行消息推送(嗅探)的請求將被拒絕(前提是對方已經拿到了正確的 Token),並終止後續處理流程,確保程序安全。
第四步:修改 startup.cs 進行全局註冊
修改 ConfigureServices() 方法:
1 public Startup(IConfiguration configuration) 2 { 3 Configuration = configuration; 4 } 5 6 public IConfiguration Configuration { get; } 7 8 public void ConfigureServices(IServiceCollection services) 9 { 10 services.AddMemoryCache();//使用本地緩存必須添加(按需) 11 12 services.AddSenparcWeixinServices(Configuration);//Senparc.Weixin 註冊 13 }
修改 Configure() 方法參數:
1 public void Configure(IApplicationBuilder app, IWebHostEnvironment env, 2 IOptions<SenparcSetting> senparcSetting, IOptions<SenparcWeixinSetting> senparcWeixinSetting)
Configure() 方法內追加:
1 app.UseSenparcGlobal(env, senparcSetting.Value, globalRegister => { }) 2 .UseSenparcWeixin(senparcWeixinSetting.Value, weixinRegister => 3 { 4 weixinRegister.RegisterMpAccount(senparcWeixinSetting.Value, "【盛派網絡小助手】公眾號"); 5 });
至此註冊工作已經全部完成!
指定使用 MessageHandler 中間件,只需一行:
app.UseMessageHandlerForMp("/WeixinAsync", CustomMpMessageHandler.GenerateMessageHandler, o => o.AccountSettingFunc = c => senparcWeixinSetting.Value);
第五步:配置 appsetting.json
找到公眾號的相關設置,修改 Token、AppId 等參數。
完成。
使用
使用 Ctrl + F5 打開當前項目,可以看到默認輸出的 Hello World 消息,打開上述設置的 /Weixin
地址:
測試地址:https://sdk.weixin.senparc.com/WeixinAsync
此時我們已經可以開始將站點部署到外網,提供給公眾進行服務,所有的去重、加解密、上下文等過程系統已經全部配備。
測試
Senparc.Weixin SDK 為了方便開發者測試公眾號消息,已經提供了一套模擬器,可以用於發送和接收公眾號消息的測試。
注意:如果測試本地 localhost 的項目,需要在本地運行模擬器,上述模擬器也已經包含在開源 Sample 中,可以下載後在本地運行並使用:
同樣也支持並發測試以及加密模式:
如果同時發送兩條 MsgId 相同的消息,會被自動去重過濾: