1. 程式人生 > >LayIM.AspNetCore Middleware 開發日記(二)預備知識介紹

LayIM.AspNetCore Middleware 開發日記(二)預備知識介紹

Locator route ppk 我只 netcore blank req rop read

前言

  開發一個AspNetCore的中間件需要理解RequestDelegate。另外,還需要理解.NET Core中的依賴註入。還有一個就是內嵌資源的訪問。例如:EmbeddedFileProvider 的使用。那麽本文就這三點做一個簡單的介紹。理解了這些那麽基本上開發下去就不難了。

RequestDelegate

  對於RequestDelegate的介紹,大家可以看一下這篇文章:https://www.cnblogs.com/artech/p/inside-asp-net-core-pipeline-01.html。

  我這裏就簡單通過代碼過一下,下面是一個簡單的HelloWorld的例子。

  

namespace LayIM.AspNetCore.WebDemo.Middleware
{
    public class HelloWorldMiddleWare
    {
        private readonly RequestDelegate next;
        public HelloWorldMiddleWare(RequestDelegate next)
        {
            this.next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            
await context.Response.WriteAsync("hello world"); } } public static class HelloWorldExtensions { public static void UseHelloWorld(IApplicationBuilder builder) { builder.UseMiddleware<HelloWorldMiddleWare>(); } } }

  然後在Startup中將這個中間件註冊到IApplicationBuilder

中即可。就像 app.UseMvc() 一樣。

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseHelloWorld();
        }

  看一下運行效果:

技術分享圖片

  那麽這個就是RequestDelegate的用法,那麽我們可以看到,在HelloWorldMiddleware中有一個類型為RequestDelegatenext變量。這樣就使得調用鏈串聯起來。我們通過RequestDelegate 就能做一些全局性的工作了,比如請求校驗,篩選,日誌,統計等等,看需求吧。然後在根據情況選擇是否執行 next?.Invoke(context) 方法,將請求流程走下去,直到走完所有流程或者走到某個被攔截掉的流程為止。同樣的道理,在LayIM.AspNetCore 中攔截了開頭為{/layim}的請求。否則繼續 執行其他業務邏輯。示例代碼如下:

 if (context.IsLayIMRequest(options) == false)
     {
         await next?.Invoke(context);
         return;
     }

  雖然沒有加註釋,但是也能看得出來,判斷是否是LayIM的請求,如果不是,直接跳過。

DependencyInjection

  依賴註入相信大家都很熟悉了,要說他有什麽好處,最直觀的一個好處就是解耦。在之前的LayIM_NetClient項目中,我是直接將融雲的實現放到中間件中,這種就是耦合性太高。用戶如果不想使用融雲的話,就沒法用了。那麽在LayIM.AspNetCore 項目中,通過使用依賴註入的方式,將核心接口與實現類分離,達到不用改核心代碼,直接擴展新的實現類即可做到業務實現轉換。這裏我直接用項目中的例子作為介紹:

  在初始化Middleware的時候,系統會自動將IServiceProvider註入到中間件中

 public LayIMMiddleware(RequestDelegate next, LayIMOptions options,IServiceProvider serviceProvider)
        {
            this.next = next;
            this.options = options;
            this.serviceProvider = serviceProvider;
            LayIMServiceLocator.SetServiceProvider(this.serviceProvider);
        }

  我通過LayIMServiceLocator 來保存IServiceProvider的實例,那麽在使用的時候。通過它就可以得到我們想要的服務了。下面是一個獲取Token的例子。在ILayIMServer 接口中定義了如下方法:

 TokenResult GetToken(string userId);

  然後在新的RongCloud項目中實現該方法,並且擴展IServiceCollection

 public class RongCloudServer : ILayIMServer
    {
        private readonly RongCloudConfig config;
        public RongCloudServer(RongCloudConfig config)
        {
            this.config = config;
        }
        public TokenResult GetToken(string userId)
        {
            return new TokenResult
            {
                code = 0,
                msg = "ok",
                token = "123456"
            };
        }
    }
 public static void AddLayIM(this IServiceCollection services, RongCloudConfig config)
        {
            services.AddSingleton(config);
            services.AddSingleton<ILayIMServer, RongCloudServer>();
        }

  那麽,在Demo中我們可以這麽使用了:

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
    
            services.AddLayIM(config =>
            {
                config.AppKey = "123456";
                config.AppSecret = "654321";
            });
        }    

  這裏呢,如果不想使用融雲通訊的話,可以自己去實現ILayIMServer接口,然後做自己的擴展即可。

  核心端依賴於接口,處理邏輯如下:(其他代碼可先忽略,暫時看中間兩行代碼)

 //獲取連接websocket的token
  routes.AddQueryCommand("/token", context =>
  {
    var server = LayIMServiceLocator.GetService<ILayIMServer>();
    return server.GetToken(context.Request.Query["uid"]);
  });

  可以看到,先通過ServiceLocator獲取了ILayIMServer接口,然後調用接口方法即可。這樣就達到了框架代碼與實現代碼解耦的目的。我們看一下效果:

  技術分享圖片

  代碼運行正常,在這裏呢不在演示其他實現。如果不明白的小夥伴可以去下載代碼調試,或者直接私信我即可。

EmbeddedFileProvider

  好文推薦:https://www.cnblogs.com/artech/p/net-core-file-provider-04.html

  大家知道,正如SwaggerUI那樣,為什麽我們配置了,就能訪問到UI界面呢?他的資源文件在哪裏呢?其實這就是內嵌資源起到的作用。想深入理解的小夥伴可以查閱其他資料,這裏我只是簡單介紹如何去實現內嵌資源的訪問。

  其實很簡單,如下幾句代碼就搞定:

  app.UseFileServer(new FileServerOptions
            {
                RequestPath = options.ApiPrefix,
                FileProvider = new EmbeddedFileProvider(assembly, "namespace"),
            });

  可以看到,FileProviderEmbeddedFileProvider,其中傳入了兩個參數,一個是程序集,一個是靜態資源的命名空間。

  不過當我們添加靜態文件之後需要註意的是,要將文件生成操作屬性設置成為嵌入的資源,否則訪問不到。(不過還有使用配置文件的做法)

技術分享圖片

  那麽這樣的話,我們訪問一下靜態資源,效果如下:

  技術分享圖片

  那麽動態資源和靜態資源都可以訪問了,那麽我們就可以進行下一步的工作了。

總結

  本文簡單介紹了中間件的基礎知識和使用方式、嵌入資源的訪問以及依賴註入的簡單使用,之所以說是預備知識,是因為在後續的開發過程中都會使用到。

   博客預告:LayIM.AspNetCore Middleware 開發日記(三)基礎框架搭建

   項目地址:https://github.com/fanpan26/LayIM.AspNetCore (本文代碼對應blog2分支)歡迎小夥伴們star 圍觀 提意見。

LayIM.AspNetCore Middleware 開發日記(二)預備知識介紹