F# Azure Functions独立进程SignalR协商方法访问异常问题
解决F#继承ServerlessHub时访问NegotiateAsync的FS0491错误
问题原因
F#对protected成员的访问限制比C#更严格:基类的protected成员仅允许在派生类的直接成员方法中通过base调用,无法在嵌套的计算表达式(如task {})或lambda表达式里使用base访问,这就是报错FS0491的核心原因。
解决思路一:封装protected成员调用
在派生类中新增一个辅助方法,直接调用基类的NegotiateAsync,然后在task表达式里通过当前实例调用这个辅助方法:
open System.Net open System.Threading.Tasks open Microsoft.Azure.Functions.Worker open Microsoft.Azure.Functions.Worker.Http open Microsoft.Azure.Functions.Worker.SignalRService open Microsoft.Extensions.Logging type SignalRNegotiateFunction(loggerFactory: ILoggerFactory, hub : ServiceHubContext, serviceProvider: IServiceProvider) = inherit ServerlessHub(serviceProvider: IServiceProvider) let logger = loggerFactory.CreateLogger<SignalRNegotiateFunction>() // 封装基类的protected调用 member private this.Negotiate(options: NegotiationOptions) = base.NegotiateAsync(options) [<Function("SignalRNegotiate")>] member _.Run([<HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "negotiate")>] req: HttpRequestData) : Task<HttpResponseData> = task { let translator = req |> RequestHandler.determineTranslator let! remoteHubConnectionRequest = RequestHandler.decodeAsyncHubConnection translator req let userIdStr = remoteHubConnectionRequest.UserID let attribute = userIdStr |> Negotiator.infoAttributeFromUserIdStr let negoptions = NegotiationOptions(UserId = userIdStr) // 通过当前实例调用封装的方法,替代base直接调用 let! negotiateResponse = this.Negotiate(negoptions) // 后续将negotiateResponse转换为HttpResponseData返回的逻辑 let response = req.CreateResponse(HttpStatusCode.OK) do! response.WriteAsJsonAsync(negotiateResponse) return response }
解决思路二:改用依赖注入直接调用协商服务
绕开继承ServerlessHub的方式,直接注入INegotiationService来处理SignalR协商,更符合依赖注入的设计原则,同时避免F#的继承访问限制:
open System.Net open System.Threading open System.Threading.Tasks open Microsoft.Azure.Functions.Worker open Microsoft.Azure.Functions.Worker.Http open Microsoft.Azure.Functions.Worker.SignalRService open Microsoft.Extensions.Logging type SignalRNegotiateFunction(loggerFactory: ILoggerFactory, negotiationService: INegotiationService) = let logger = loggerFactory.CreateLogger<SignalRNegotiateFunction>() [<Function("SignalRNegotiate")>] member _.Run([<HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "negotiate")>] req: HttpRequestData) : Task<HttpResponseData> = task { let translator = req |> RequestHandler.determineTranslator let! remoteHubConnectionRequest = RequestHandler.decodeAsyncHubConnection translator req let userIdStr = remoteHubConnectionRequest.UserID let attribute = userIdStr |> Negotiator.infoAttributeFromUserIdStr let negoptions = NegotiationOptions(UserId = userIdStr) // 直接使用注入的INegotiationService完成协商 let! negotiateResponse = negotiationService.NegotiateAsync(negoptions, CancellationToken.None) let response = req.CreateResponse(HttpStatusCode.OK) do! response.WriteAsJsonAsync(negotiateResponse) return response }
内容的提问来源于stack exchange,提问作者SteelCityRKP
相关产品推荐
相关产品推荐

