­

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 的方式。

  新的設計將達到如下目標或新特性:

  1. 不再依賴 Controller/Action,因此也不再依賴 FixWeixinBugWeixinResult 等一系列因為歷史原因而存在的類和方法。你不必再為處理微信消息創建任何 Controller 或 WebApi;
  2. 不影響現有的運行效率,甚至更快;
  3. 默認僅支持異步方法;
  4. 更輕量、更少的配置代碼
  5. 高度可用,不閹割任何功能。

準備開發

開發步驟

第一步:創建一個 .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

  參考:appsetting.json

  找到公眾號的相關設置,修改 Token、AppId 等參數。

 

完成。

 

使用

  使用 Ctrl + F5 打開當前項目,可以看到默認輸出的 Hello World 消息,打開上述設置的 /Weixin 地址:

 

測試地址:https://sdk.weixin.senparc.com/WeixinAsync

  此時我們已經可以開始將站點部署到外網,提供給公眾進行服務,所有的去重、加解密、上下文等過程系統已經全部配備。

測試

  Senparc.Weixin SDK 為了方便開發者測試公眾號消息,已經提供了一套模擬器,可以用於發送和接收公眾號消息的測試。

  注意:如果測試本地 localhost 的項目,需要在本地運行模擬器,上述模擬器也已經包含在開源 Sample 中,可以下載後在本地運行並使用:

  同樣也支持並發測試以及加密模式:

  如果同時發送兩條 MsgId 相同的消息,會被自動去重過濾: