我调用Web API并自动显示和隐藏MudOverlay,而无需为每个API调用编写任何代码,就像这样:
protected override async Task OnInitializedAsync()
{
users = await Http.GetFromJsonAsync<List<GetAllUsersDto>>("User/GetAll");
}
@if (users is not null)
{
@* MudDataGrid 或 MudTable *@
}
创建一个ApiService类,其中包含ApiCount属性,用于保存正在执行的API的计数。我选择使用byte数据类型,因为0到255足够了。
public class ApiService
{
public byte ApiCount { get; set; } = 0;
public event Action ApiCountChanged;
public void IncreaseApiCount()
{
ApiCount++;
ApiCountChanged?.Invoke();
}
public void DecreaseApiCount()
{
ApiCount--;
ApiCountChanged?.Invoke();
}
public bool IsShowOverlay
{
get { return ApiCount > 0 ? true : false; }
set { }
}
}
将ApiService注入到客户端程序的program.cs中。我通过以下foreach循环来注入所有的Service类:
// 单例AppServices
var appServices = typeof(Program).Assembly.GetTypes()
.Where(s => s.Name.EndsWith("Service") && s.IsInterface == false).ToList();
foreach (var appService in appServices)
builder.Services.Add(new ServiceDescriptor(appService, appService, ServiceLifetime.Singleton));
3. 在 MainLayout.razor.cs 中添加 HandleApiCountChanged 事件处理程序的方法:
protected override async Task OnInitializedAsync()
{
ApiService.ApiCountChanged += HandleApiCountChanged;
}
private void HandleApiCountChanged()
{
StateHasChanged();
}
在MainLayout.razor中的标签内添加MudOverlay,其可见性绑定到ApiService.IsShowOverlay布尔方法。
<MudOverlay ZIndex="9999" @bind-Visible="ApiService.IsShowOverlay" DarkBackground="true" AutoClose="false">
将ApiService注入到HttpStatusCodeService客户端API中间件,并在API调用之前和之后使用ApiService的IncreaseApiCount()和DecreaseApiCount()方法。MainLayout读取IsShowOverlay()方法,在所有应用程序API调用中显示和隐藏MudOverlay。
public class HttpStatusCodeService(ISnackbar snackbar, LocalStorageService localStorageService, AuthenticationStateProvider authenticationStateProvider, ApiService apiService) : DelegatingHandler
{
protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// 在发送请求之前
apiService.IncreaseApiCount(); // 增加API计数
if (request.RequestUri.AbsolutePath.ToLower().Contains("loginregister"))
return await base.SendAsync(request, cancellationToken);
var token = await localStorageService.GetItem<string>("token");
if (string.IsNullOrEmpty(token) == false)
request.Headers.Add("Authorization", $"Bearer {token}");
var response = await base.SendAsync(request, cancellationToken);
if (response.IsSuccessStatusCode == false)
{
if (response.StatusCode == HttpStatusCode.Conflict)
snackbar.Add(await response.Content.ReadAsStringAsync(), Severity.Warning);
if (response.StatusCode == HttpStatusCode.InternalServerError)
snackbar.Add("A problem is occured, tell out support team.", Severity.Error);
if (response.StatusCode == HttpStatusCode.Forbidden)
snackbar.Add("You don't have permission.", Severity.Warning);
if (response.StatusCode == HttpStatusCode.Unauthorized)
await (authenticationStateProvider as AuthStateProvider).Logout(forceLoad: true);
}
apiService.DecreaseApiCount();
return response;
}
}
我可以在.NET 8中使用主构造函数功能来实现无需私有只读属性和构造函数的注入。要使用它,您需要将"LangVersion>preview/LangVersion>"添加到客户端csproj文件的PropertyGroup中。
Task.Run
正是我在异步函数中从Entity Framework DBContext返回数据所缺少的。谢谢! - chrisbyte