LayIM.AspNetCore Middleware 開發日記(二)預備知識介紹
前言
開發一個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
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseHelloWorld(); }
看一下運行效果:
那麽這個就是RequestDelegate的用法,那麽我們可以看到,在HelloWorldMiddleware中有一個類型為RequestDelegate的next變量。這樣就使得調用鏈串聯起來。我們通過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"), });
可以看到,FileProvider是EmbeddedFileProvider,其中傳入了兩個參數,一個是程序集,一個是靜態資源的命名空間。
不過當我們添加靜態文件之後需要註意的是,要將文件生成操作屬性設置成為嵌入的資源,否則訪問不到。(不過還有使用配置文件的做法)
那麽這樣的話,我們訪問一下靜態資源,效果如下:
那麽動態資源和靜態資源都可以訪問了,那麽我們就可以進行下一步的工作了。
總結
本文簡單介紹了中間件的基礎知識和使用方式、嵌入資源的訪問以及依賴註入的簡單使用,之所以說是預備知識,是因為在後續的開發過程中都會使用到。
博客預告:LayIM.AspNetCore Middleware 開發日記(三)基礎框架搭建
項目地址:https://github.com/fanpan26/LayIM.AspNetCore (本文代碼對應blog2分支)歡迎小夥伴們star 圍觀 提意見。
LayIM.AspNetCore Middleware 開發日記(二)預備知識介紹