C# 如何在不调用.Result的情况下使用作为任务注入的类中的函数?
我试图在这里实现lolsharp给出的答案: 它们注入GrpcChannel类型的任务,其中GrpcChannel是一个类:C# 如何在不调用.Result的情况下使用作为任务注入的类中的函数?,c#,.net,multithreading,dependency-injection,blazor,C#,.net,Multithreading,Dependency Injection,Blazor,我试图在这里实现lolsharp给出的答案: 它们注入GrpcChannel类型的任务,其中GrpcChannel是一个类: @inject Task<GrpcChannel> Channel 为了避免在频道上调用.Result,您必须等待它。例如: var通道=等待通道; GetAllResponse GetAllResponse= wait channel.GetAllAsync(新的Google.Protobuf.WellKnownTypes.Empty()); 旁注:正如
@inject Task<GrpcChannel> Channel
为了避免在
频道上调用.Result
,您必须等待它。例如:
var通道=等待通道;
GetAllResponse GetAllResponse=
wait channel.GetAllAsync(新的Google.Protobuf.WellKnownTypes.Empty());
旁注:正如我在评论中提到的,您通常应该避免在对象解析期间执行任何涉及I/O的操作,因为这会使对象解析变得脆弱和不稳定。相反,您应该能够像Mark Seemann所表示的那样,以con-confidence的方式构建对象图。您可以通过将任务隐藏在抽象后面来推迟任务的创建来实现这一点。例如:
公共接口IGrpcChannelProvider
{
任务通道{get;}
}
这允许您将所有注册代码移动到IGrpcChannelProvider
的实现中:
公共密封类GrpcChannelProvider:IGrpcChannelProvider,IDisposable
{
私有只读IConfiguration配置;
专用只读IAccessTokenProvider authenticationService;
专用只读惰性通道;
公共服务提供商(
IConfiguration配置,IAccessTokenProvider authenticationService)
{
this.config=config;
this.authenticationService=authenticationService;
this.channel=new Lazy(this.CreateChannel);
}
公共任务通道=>this.Channel.Value;
公共空间处置()
{
如果(this.channel.IsValueCreated)this.channel.Value.Dispose();
}
//这是您的原始代码
专用异步任务CreateChannel()
{
#如果调试
var baseUri=”http://localhost:8999/";
#否则
var baseUri=“[mysite]”;
#恩迪夫
var httpClient=新的httpClient(新的GrpcWebHandler(GrpcWebMode.GrpcWeb,新的HttpClientHandler());
var tokenResult=wait this.authenticationService.RequestAccessToken();
if(tokenResult.TryGetToken(out-var-token))
{
var credentials=CallCredentials.FromInterceptor((上下文、元数据)=>
{
如果(!string.IsNullOrEmpty(token.Value))
{
Add(“Authorization”、$“Bearer{token.Value}”);
}
返回Task.CompletedTask;
});
var channel=GrpcChannel.ForAddress(baseUri,
新的GRPCC选项
{
HttpClient=HttpClient,
Credentials=ChannelCredentials.Create(新建SslCredentials(),凭据)
});
var客户端=新的GrpcServices.GrpcServicesClient(通道);
返回客户;
}
}
}
此组件可以按如下方式注册:
services.AddSingleton();
或者-如果在应用程序域期间缓存通道会导致安全问题-将组件注册为作用域:
services.addScope();
在视图中,插入此IGrpcChannelProvider
,而不是通道:
@注入IGrpcChannelProvider提供程序
并按如下方式使用:
var channel=wait Provider.channel;
GetAllResponse GetAllResponse=
wait channel.GetAllAsync(新的Google.Protobuf.WellKnownTypes.Empty());
更进一步说,您甚至可能希望阻止对Razor页面内的服务进行任何调用,而是依赖预填充的模型:
@模型AllResponseModel
@model AllResponseModel
GetAllResponse GetAllResponse=Model.AllResponses;
现在您可以将IGrpcChannelProvider
注入RazorAllResponseModel
。这是否回答了您的问题?你能在你正在使用的startup.cs中发布你的依赖关系吗?@hotel不,这就是我的问题所在。第二个答案在解释如何使用该类之前就停止了。@Dan我已经从Program.cs添加了依赖项。请防止在对象解析期间执行任何涉及I/O的操作。这使得决议变得脆弱和不稳定。相反,你应该能够。谢谢。实际上,我一直在努力实现您之前发布的文章中的建议,但这些具体说明肯定会使这项任务更容易。
builder.Services.AddSingleton(async services =>
{
Console.WriteLine("In addsingleton");
var config = services.GetRequiredService<IConfiguration>();
#if DEBUG
var baseUri = "http://localhost:8999/";
#else
var baseUri = "[mysite]";
#endif
Console.WriteLine("About to set new httpclient");
var httpClient = new HttpClient(new
GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));
var scopedFactory =
services.GetRequiredService<IServiceScopeFactory>();
using (var scope = scopedFactory.CreateScope())
{
var authenticationService =
scope.ServiceProvider.GetRequiredService<IAccessTokenProvider>();
var tokenResult = await
authenticationService.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
var credentials = CallCredentials.FromInterceptor((context, metadata) =>
{
if (!string.IsNullOrEmpty(token.Value))
{
metadata.Add("Authorization", $"Bearer
{token.Value}");
}
return Task.CompletedTask;
});
var channel = GrpcChannel.ForAddress(baseUri, new
GrpcChannelOptions { HttpClient = httpClient, Credentials =
ChannelCredentials.Create(new SslCredentials(), credentials) });
var client = new
GrpcServices.GrpcServicesClient(channel);
return client;
}
}