Iva*_*ono 6 refit asp.net-core blazor blazor-server-side
我正在重构我的代码以使用Refit来调用 WebApi 服务。接口已设置,我还创建了一个委托处理程序:
public class AuthHandler : DelegatingHandler
{
private readonly TokenProvider tokenProvider;
private readonly ISessionStorageService sessionStorage;
public AuthHandler (
TokenProvider tokenProvider,
ISessionStorageService sessionStorage)
{
this.tokenProvider = tokenProvider ?? throw new ArgumentNullException(nameof(tokenProvider));
this.sessionStorage = sessionStorage ?? throw new ArgumentNullException(nameof(sessionStorage));
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken ct)
{
var someToken = await sessionStorage.GetItemAsync<string>("sometoken");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenProvider.AccessToken);
request.Headers.Add("someToken", someToken);
return await base.SendAsync(request, ct).ConfigureAwait(false);
}
}
Run Code Online (Sandbox Code Playgroud)
并在Startup.cs:
services.AddBlazoredSessionStorage();
services.AddScoped<TokenProvider>();
services.AddScoped<AuthHandler>();
services.AddRefitClient<IApiService>().ConfigureHttpClient(options =>
{
options.BaseAddress = new Uri(Configuration["Server:Url"]);
options.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}).AddHttpMessageHandler<AuthHandler>();
Run Code Online (Sandbox Code Playgroud)
我有一个剃刀组件,我想使用上面的服务,所以我注入了服务并执行了以下操作:
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var list = await myService.GetListAsync();
}
}
}
Run Code Online (Sandbox Code Playgroud)
另外,在_Host.cshtml:
<environment include="Staging,Production">
<component render-mode="ServerPrerendered" type="typeof(App)" param-InitialState="tokens" />
</environment>
<environment include="Development">
<component render-mode="Server" type="typeof(App)" param-InitialState="tokens" />
</environment>
Run Code Online (Sandbox Code Playgroud)
但是我得到以下异常:
System.InvalidOperationException:此时无法发出 JavaScript 互操作调用。这是因为该组件是静态渲染的。启用预渲染后,只能在 OnAfterRenderAsync 生命周期方法期间执行 JavaScript 互操作调用。
因此,为了确定我是否有值,我在调用 api 之前添加了以下内容:
var someToken = await sessionStorage.GetItemAsync<string>("sometoken");
var accessToken = tokenProvider.AccessToken;
Run Code Online (Sandbox Code Playgroud)
我确实在两个变量中都有值。
那么为什么我无法从委托处理程序访问会话存储呢?为什么令牌提供程序实例已实例化,但属性全部为空(也在处理程序中)?
编辑
我只需要一个地方来保存我的代币。无论是令牌提供程序还是会话存储,只要它能在 blazor 页面/组件和其他服务中工作即可。
更新1
人们可以跳过 DI 并像这样创建服务:
var service = RestService.For<IMyService>(new HttpClient(new AuthHandler(tokenProvider, sessionStorage))
{
BaseAddress = new Uri(myUrl)
}
);
Run Code Online (Sandbox Code Playgroud)
这将按预期工作。不过,使用 DI 会好得多。问题可能出在 Blazor 或 Refit 中。
小智 -1
我想我已经找到了解决问题的有效方法。
我没有依赖HttpClientFactoryRefit 使用的逻辑,而是创建了自己的 DI 逻辑。
以前的:
Uri apiBaseUri = dataAccessLayerConfiguration.API.BaseUrl;
foreach (Type repositoryType in repositoryTypes)
{
services
.AddRefitClient(repositoryType)
.ConfigureHttpClient((httpClient) => httpClient.BaseAddress = apiBaseUri)
.AddHttpMessageHandler<RequestHeaderHandler>();
}
Run Code Online (Sandbox Code Playgroud)
当前的:
foreach (Type repositoryType in repositoryTypes)
{
services.AddTransient(
repositoryType,
(provider) =>
{
return
RepositoryFactory.Create(
repositoryType,
configuration,
provider.GetRequiredService<ITokenCacheProvider>(),
() => provider.GetRequiredService<ICurrentUser>());
});
}
Run Code Online (Sandbox Code Playgroud)
我使用的 RepositoryFactory 为每个 API 接口创建 HttpClient:
return
RestService.For<TRepository>(
new HttpClient(
new RequestHeaderHandler(tokenCacheProvider, fetchCurrentUserDelegate)
{
InnerHandler = new HttpClientHandler()
},
true)
{
BaseAddress = configuration.DataAccessLayer.API.BaseUrl
});
Run Code Online (Sandbox Code Playgroud)
我目前在该方法的布局代码中获取当前用户OnParametersSet()。我还没有完全满意,但目前对我来说已经足够了。但是,重要的是,在创建 HttpClient 时不要直接注入用户对象,而只注入一个委托(或 )Func<>,然后在需要时解析用户对象。
这样我就能够解决 Refit/HttpClientFactory 的范围问题,但仍然继续使用依赖注入。它可能不是适合每个人的百分百解决方案,但足以为您自己的项目找到正确的方向。
| 归档时间: |
|
| 查看次数: |
1998 次 |
| 最近记录: |