歡迎光臨
每天分享高質量文章

ASP.NET Core 微信服務中間件-.NET Core 2.1

來自:李朝強 

鏈接: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 { getset; }

        /// 


        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        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 { getset; }

        /// 


        /// 
        /// 
        public WeiXinServer()
        
{

        }

        /// 


        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public async Task Run(HttpContext context, IConfiguration configuration)
        
{
            #region 1、驗證簽名
            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;
            }
            #endregion  1、驗證簽名

            #region 2、接收微信訊息
            await OnRecieve(context);//接收訊息
            #endregion 2、接收微信訊息
        }

        #region 虛方法
        /// 


        /// 
        /// 
        /// 
        /// 
        public virtual Task OnRecieve(HttpContext context)
        
{
            if (ServerOptions.OnRecieveAsync != nullreturn 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 != nullreturn (Task)action.Invoke(thisnew object[] { weiXinContext });

            }
            //被動接收訊息
            else
            {
                return OnRecieveMessage(context);
            }
            return Task.Delay(0);
        }

        /// 


        /// 
        /// 
        /// 
        /// 
        public virtual Task OnRecieveMessage(HttpContext context)
        
{
            if (ServerOptions.OnRecieveMessageAsync != nullreturn ServerOptions.OnRecieveMessageAsync(context);
            return Task.Delay(0);
        }

        /// 


        /// 
        /// 
        /// 
        /// 
        public virtual Task OnScan(WeiXinContext context)
        
{
            if (ServerOptions.OnScanAsync != nullreturn ServerOptions.OnScanAsync(context);
            return Task.Delay(0);
        }

        /// 


        /// 
        /// 
        /// 
        /// 
        public virtual Task OnSubscribe(WeiXinContext context)
        
{
            if (ServerOptions.OnSubscribeAsync != nullreturn ServerOptions.OnSubscribeAsync(context);
            return Task.Delay(0);
        }

        /// 


        /// 
        /// 
        /// 
        /// 
        public virtual Task OnUnsubscribe(WeiXinContext context)
        
{
            if (ServerOptions.OnUnsubscribeAsync != nullreturn ServerOptions.OnUnsubscribeAsync(context);
            return Task.Delay(0);
        }

        /// 


        ///  
        /// 
        /// 
        /// 
        public virtual Task OnClick(WeiXinContext context)
        
{
            if (ServerOptions.OnClickAsync != nullreturn ServerOptions.OnClickAsync(context);
            return Task.Delay(0);
        }

        /// 


        /// 
        /// 
        /// 
        /// 
        public virtual Task OnView(WeiXinContext context)
        
{
            if (ServerOptions.OnViewAsync != nullreturn ServerOptions.OnViewAsync(context);
            return Task.Delay(0);
        }

        /// 


        /// 
        /// 
        /// 
        /// 
        public virtual Task OnLocation(WeiXinContext context)
        
{
            if (ServerOptions.OnLocationAsync != nullreturn ServerOptions.OnLocationAsync(context);
            return Task.Delay(0);
        }
        #endregion
    }

WeiXinServer類中還定義了時間訊息的相關的虛方法,虛方法中,呼叫Options配置中定義的委托,這樣,開發者一方面可以通過繼承WeiXinServer或IWeiXinServerProvider接口,或通過設置Options屬性,來靈活運用,開發者可根據自身需求,完成

對應業務邏輯即可。有了這些設計,我們可以輕鬆配置和完成微信訊息的處理。

以上內容的全部代碼,可以通過訪問https://gitee.com/lichaoqiang/weixinmd 獲取,不足之處,還望不吝賜教。


●編號146,輸入編號直達本文

●輸入m獲取文章目錄

推薦↓↓↓

Web開發

更多推薦18個技術類公眾微信

涵蓋:程式人生、演算法與資料結構、黑客技術與網絡安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。

赞(0)

分享創造快樂