來自:李朝強
連結:http://www.cnblogs.com/ibeisha/p/weixinServer.html
寫了一個關於微信公眾號服務的中介軟體,基於.NetCore2.1。服務類庫採用.Net Standard2.0,相容.net 4.6.1。
整體思路是,設計一個中介軟體,提供微信訊息推送服務。目前實現了,接收微信訊息推送後,根據訊息型別,對事件訊息和被動接收訊息分別進行了處理。
在中介軟體和服務之間,建立一個服務提供類,擁有提供訊息的處理邏輯,開發者,可以實現服務提供介面,完成自己的邏輯。下麵,讓我們看看關於中介軟體的程式碼設計:
這裡,我新建了一個名為WeiXinMiddleware的類,程式碼如下:
/// <summary>
///
/// summary>
public class WeiXinMiddleware
{
/// <summary>
///
/// summary>
private RequestDelegate Next = null;
/// <summary>
///
/// summary>
public IConfiguration Configuration { get; }
/// <summary>
///
/// summary>
public OAuth.WeiXinServerOptions ServerOptions { get; set; }
/// <summary>
///
/// summary>
/// <param name=“requestDelegate”>param>
/// <param name=“configuration”>param>
public WeiXinMiddleware(RequestDelegate requestDelegate, IConfiguration configuration, OAuth.WeiXinServerOptions serverOptions)
{
Next = requestDelegate;
Configuration = configuration;
ServerOptions = serverOptions;
}
/// <summary>
///
/// summary>
/// <param name=“context”>param>
/// <returns>returns>
public async Task Invoke(HttpContext context)
{if (context.Request.Path == ServerOptions.NotifyPath)
{
//微信服務
if (ServerOptions.WeiXinServerProvider == null) ServerOptions.WeiXinServerProvider = (OAuth.IWeiXinServerProvider)context.RequestServices.GetService(typeof(OAuth.IWeiXinServerProvider));
await ServerOptions.WeiXinServerProvider.Run(context, Configuration);
return;
}
await Next.Invoke(context);
}
}
程式碼其實很簡單,就是在類內部定義一個Invoke任務,再宣告一個Next屬性,用於請求的下一步處理委託。在中介軟體的建構式中,進行了註入,其中有一個
WeiXinServerOptions 類,它便是定義中介軟體所需的配置資訊,也是對外提供的介面,讓我們看看具體的程式碼:
/// <summary>
///
/// summary>
public class WeiXinServerOptions
{
/// <summary>
///
/// summary>
public PathString NotifyPath { get; set; }
/// <summary>
///
/// summary>
private IWeiXinServerProvider _ServerProvider = null;
/// <summary>
///
/// summary>
public IWeiXinServerProvider WeiXinServerProvider
{
get
{
return _ServerProvider;
}
set
{
_ServerProvider = value;
_ServerProvider.ServerOptions = this;
}
}
/// <summary>
///
/// summary>
public Func<HttpContext, Task> OnRecieveAsync { get; set; }
/// <summary>
///
/// summary>
public Func<WeiXinContext, Task> OnScanAsync { get; set; }
/// <summary>
///
/// summary>
public Func<WeiXinContext, Task> OnSubscribeAsync { get; set; }
/// <summary>
///
/// summary>
public Func<WeiXinContext, Task> OnUnsubscribeAsync { get; set; }
/// <summary>
///
/// summary>
public Func<WeiXinContext, Task> OnClickAsync { get; set; }
/// <summary>
///
/// summary>
public Func<WeiXinContext, Task> OnViewAsync { get; set; }
/// <summary>
///
/// summary>
public Func<WeiXinContext, Task> OnLocationAsync { get; set; }
/// <summary>
///
/// summary>
public Func<HttpContext, Task> OnRecieveMessageAsync { get; set; }
}
這個類中,定義了中介軟體要攔截處理的URL,以及時間訊息的處理委託,有了這些委託,我們就可以很靈活的實現在接收到微信推送訊息後的邏輯處理。
這個類中,還定義了一個WeiXinServerProvider屬性,它是介面IWeiXinServerProvider的派生,讓我們看看它定義的成員吧!
public interface IWeiXinServerProvider
{
///
///
///
OAuth.WeiXinServerOptions ServerOptions { get; set; }
///
///
///
///
///
///
///
Task Run(HttpContext context, IConfiguration configuration);
}
很簡單吧,一個屬性,一個執行任務的函式。
上面幾個類是我服務的核心,下麵我又建立了2個擴充套件類,分別為新增中介軟體和IOC註入服務。
/// <summary>
///
/// summary>
public static class WeiXinMiddlewareExtensions
{
/// <summary>
///
/// summary>
/// <param name=“app”>param>
/// <param name=“serverOptions”>param>
public static void UseWeiXinServer(this IApplicationBuilder app, OAuth.WeiXinServerOptions serverOptions)
{
app.UseMiddleware<Middleware.WeiXinMiddleware>(serverOptions);
}
}
下麵是IOC註入的擴充套件方法:
///
///
///
public static class WeiXinServiceCollectionExtensions
{
///
///
///
///
public static void AddWeiXinServer(this IServiceCollection services)
{
services.AddSingleton(typeof(OAuth.IWeiXinServerProvider), typeof(OAuth.WeiXinServer));//單例:IOC註冊服務型別
}
}
完成以上程式碼後,最後讓我們再Start類中,進行服務的配置。
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddWeiXinServer();//IOC註冊服務型別
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
///
///
///
///
///
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(“/Home/Error”);
app.UseHsts();
}
//使用微信中介軟體
app.UseWeiXinServer(new OAuth.WeiXinServerOptions()
{
NotifyPath = new PathString(“/OAuth/WeiXin”),
//WeiXinServerProvider = new OAuth.WeiXinServer(),//此處也可也手動設定,預設透過IOC容器建立WeiXinServer實體。
OnScanAsync = (context) => { return Task.Delay(0); },
OnClickAsync = (context) => { return Task.Delay(0); },
OnSubscribeAsync = (context) => { return Task.Delay(0); },
OnUnsubscribeAsync = (context) => { return Task.Delay(0); },
OnViewAsync = (context) => { return Task.Delay(0); },
OnRecieveMessageAsync = (context) => { return Task.Delay(0); },
});
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: “default”,
template: “{controller=Home}/{action=Index}/{id?}”);
});
}
}
讓我們再看看WeiXinServer類的定義:
///
///
///
public class WeiXinServer : IWeiXinServerProvider
{
///
///
///
public OAuth.WeiXinServerOptions ServerOptions { get; set; }
///
///
///
public WeiXinServer()
{
}
///
///
///
///
///
///
///
public async Task Run(HttpContext context, IConfiguration configuration)
{
if (context.Request.Method.ToUpper() == “GET”)
{
context.Response.ContentType = “text/plain;charset=utf-8”;
context.Response.StatusCode = 200;
//1、驗證簽名
if (WeiXin.Sdk.Common.Util.CheckSignature(context.Request.Query[“nonce”],
context.Request.Query[“timestamp”],
context.Request.Query[“signature”],
configuration.GetSection(“WeiXinOAuth”)[“Token”]))
{
await context.Response.WriteAsync(context.Request.Query[“echostr”]);
return;
}
await context.Response.WriteAsync(“無效簽名!”);
return;
}
await OnRecieve(context);//接收訊息
}
///
///
///
///
///
public virtual Task OnRecieve(HttpContext context)
{
if (ServerOptions.OnRecieveAsync != null) return ServerOptions.OnRecieveAsync(context);
string strRecieveBody = null;//接收訊息
using (System.IO.StreamReader streamReader = new System.IO.StreamReader(context.Request.Body))
{
strRecieveBody = streamReader.ReadToEndAsync().GetAwaiter().GetResult();
}
//序列化
WeiXin.Sdk.Common.Serialization.XmlSerializer xmlSerializer = new WeiXin.Sdk.Common.Serialization.XmlSerializer(typeof(WeiXin.Sdk.Domain.Messages.Message));
var recieve = (WeiXin.Sdk.Domain.Messages.Message)xmlSerializer.Deserialize(strRecieveBody);
//事件訊息
if (recieve.MsgType == WeiXin.Sdk.Common.Constants.SystemConstants.MSG_TYPE.EVENT)
{
var weiXinContext = new WeiXinContext(recieve, context);
var weiXinContext = new WeiXinContext(recieve, context);
var actionName = recieve.Event.ToLower();
actionName = actionName.First().ToString().ToUpper() + actionName.Substring(1);
var action = this.GetType().GetMethod($”On{actionName}“);
if (action != null) return (Task)action.Invoke(this, new object[] { weiXinContext });
}
//被動接收訊息
else
{
return OnRecieveMessage(context);
}
return Task.Delay(0);
}
///
///
///
///
///
public virtual Task OnRecieveMessage(HttpContext context)
{
if (ServerOptions.OnRecieveMessageAsync != null) return ServerOptions.OnRecieveMessageAsync(context);
return Task.Delay(0);
}
///
///
///
///
///
public virtual Task OnScan(WeiXinContext context)
{
if (ServerOptions.OnScanAsync != null) return ServerOptions.OnScanAsync(context);
return Task.Delay(0);
}
///
///
///
///
///
public virtual Task OnSubscribe(WeiXinContext context)
{
if (ServerOptions.OnSubscribeAsync != null) return ServerOptions.OnSubscribeAsync(context);
return Task.Delay(0);
}
///
///
///
///
///
public virtual Task OnUnsubscribe(WeiXinContext context)
{
if (ServerOptions.OnUnsubscribeAsync != null) return ServerOptions.OnUnsubscribeAsync(context);
return Task.Delay(0);
}
///
///
///
///
///
public virtual Task OnClick(WeiXinContext context)
{
if (ServerOptions.OnClickAsync != null) return ServerOptions.OnClickAsync(context);
return Task.Delay(0);
}
///
///
///
///
///
public virtual Task OnView(WeiXinContext context)
{
if (ServerOptions.OnViewAsync != null) return ServerOptions.OnViewAsync(context);
return Task.Delay(0);
}
///
///
///
///
///
public virtual Task OnLocation(WeiXinContext context)
{
if (ServerOptions.OnLocationAsync != null) return ServerOptions.OnLocationAsync(context);
return Task.Delay(0);
}
}
WeiXinServer類中還定義了時間訊息的相關的虛方法,虛方法中,呼叫Options配置中定義的委託,這樣,開發者一方面可以透過繼承WeiXinServer或IWeiXinServerProvider介面,或透過設定Options屬性,來靈活運用,開發者可根據自身需求,完成
對應業務邏輯即可。有了這些設計,我們可以輕鬆配置和完成微信訊息的處理。
以上內容的全部程式碼,可以透過訪問https://gitee.com/lichaoqiang/weixinmd 獲取,不足之處,還望不吝賜教。
●編號146,輸入編號直達本文
●輸入m獲取文章目錄
Web開發
更多推薦《18個技術類公眾微信》
涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。