為何要用中間件來實作音頻處理的監聽服務
當然也可以使用Startup來進行服務的自啟動,或者也可以使用quartz定時排程任務來啟動音頻服務,大家随意。
筆者認為使用中間件的目的,是為了分離應用和服務,也是一種解耦手段。
我們知道,在NETCORE中的中間件,有點類似像AOP的一種實作形式,他的調用方式是通過Request=>Middleware=>next=>custom logic=>Response。我們可以用來做日志記錄、權限驗證、事物處理,多個中間件形成一個處理管道,甚至可以實作自定義的MVC和依賴注入。
建立一個中間件
為了便于區分,我們擴充一個名為“MediaHandlers”的IApplicationBuilder
1 public static class MediaHandlers
2 {
3 public static IApplicationBuilder UseMediaAudioHandlerMiddleware(this IApplicationBuilder builder,
4 MediaAudioOptions options)
5 {
6 if (builder == null)
7 throw new ArgumentNullException(nameof(builder));
8
9 return builder.UseMiddleware<MediaAudioMiddleware>(options);
10 }
11 }
再建立一個名為“MediaAudioMiddleware”的中間件,其實就是一個實作類,但需要傳遞對象RequestDelegate做請求代理。
并且,我們将在中間件中實作依賴注入,而中間件的依賴注入卻無法通過構造函數的方式進行注入,需要通過Invoke來實作依賴注入,完整代碼如下:
1 public async Task Invoke(HttpContext context,
2 IDataOpService iDataOpService,
3 ICacheAsyncService iCacheAsyncService,
4 IMsgBusService imsgBusService,
5 IHostingEnvironment iHostingEnvironment)
6 {
7 _dataOpService = iDataOpService;
8 _iMsgBusService = imsgBusService;
9 _iCacheAsyncService = iCacheAsyncService;
10 _ihostingEnvironment = iHostingEnvironment;
11
12 await _next(context);
13 }
跟之前的控制器注入的内容類型是一樣的。然後我們再來看看構造函數中需要實作的一些事情:
public MediaAudioMiddleware(RequestDelegate next, MediaAudioOptions options)
{
_next = next;
Task.Factory.StartNew(() =>
{
Thread.Sleep(3 * 1000);
//...需要自定義啟動的方法
});
}
構造函數中預設必須傳遞RequestDelegate類型參數,用于委托執行Request之後Response之前的代理。
将需要啟動的服務已子任務(子線程)的方式交給Task工廠進行自行管理,再次分離了主管道請求應用。
但是,預設這個中間件是不會自動啟動的。。。因為沒有建立一個請求管道。
強制建立一個請求管道
筆者的思路是,通過httpclient請求主管道中的一個任意的API接口(比如你自定義實作的伺服器資訊接口),進而強制實作該請求管道的所有事情,比如循環,比如監聽等等。參考如下:
1 using (var httpClient = new HttpClient())
2 {
3 httpClient.BaseAddress = new Uri($"{General.LocalHostUrl}/Info");
4 var r = httpClient.GetAsync(httpClient.BaseAddress).Result;
5 if (!r.ToString().Contains("200")) return;
6 Console.WriteLine("MediaAudioMiddleware Running");
7 var mediaHandler = new AudioHandlerWorkUnit(iDataOpService: _dataOpService,
8 iCacheAsyncService: _iCacheAsyncService,
9 imsgBusService: _iMsgBusService,
10 iHostingEnvironment: _ihostingEnvironment,
11 millsSeconds: options.MillsSeconds
12 );
13 mediaHandler.DoStart();
14 }
當然,需要在指令參數中(或前置參數中限制該管道隻建立一次),也許筆者的實作方式欠妥,如果你有更好的方法,歡迎交流。
感謝閱讀