Blazor Wasm Aspnetcore主持了JWT授权问题
我首先关注了有关使用 Blazor Web Assembly + asp net core Web api 构建身份 API 身份验证 api 的 YouTube 视频,经过 100 个小时的研究,在尝试使用 [Authorize] 访问 API 时,我仍然无法通过“401”未经授权
我多次关注MSDN并对代码进行了多次修改。我已恢复到指南中演示的原始版本,并且仍在处理 double & 问题。根据所使用的内容对所有内容进行了三次检查。至此,我觉得API Protection现在已经完蛋了呵呵。希望有人能看到我哪里出了问题,因为我现在不知所措。
我应该通过这次尝试获取 WeatherForecast API,但它未经授权。底部错误
客户端代码:
中使用的行
internal readonly static string s_weather = $"{ServerBaseURL}/weatherforecast";
APIEndpoints Program.cs
using Blazored.LocalStorage;
using Client;
using Client.Providers;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddSingleton<HttpClient>();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AppAuthenticationStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider>(provider
=> provider.GetRequiredService<AppAuthenticationStateProvider>());
await builder.Build().RunAsync();
AppAuthenticationStateProvider
using Microsoft.AspNetCore.Components.Authorization;
using Blazored.LocalStorage;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace Client.Providers
{
public class AppAuthenticationStateProvider : AuthenticationStateProvider
{
private readonly ILocalStorageService _localStorageService;
private readonly JwtSecurityTokenHandler jwtSecurityTokenHandler = new();
public AppAuthenticationStateProvider(ILocalStorageService localStorageService)
{
_localStorageService = localStorageService;
}
public async override Task<AuthenticationState> GetAuthenticationStateAsync()
{
try
{
string savedToken = await _localStorageService.GetItemAsync<string>("bearerToken");
if (string.IsNullOrWhiteSpace(savedToken))
{
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
JwtSecurityToken jwtSecurityToken = jwtSecurityTokenHandler.ReadJwtToken(savedToken);
DateTime expiry = jwtSecurityToken.ValidTo;
if (expiry < DateTime.UtcNow)
{
await _localStorageService.RemoveItemAsync("bearerToken");
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
//Get Claims from Token and Build Authenticated User Object
var claims = ParseClaims(jwtSecurityToken);
var user = new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt"));
return new AuthenticationState(user);
}
catch (Exception)
{
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
}
private IList<Claim> ParseClaims(JwtSecurityToken jwtSecurityToken)
{
IList<Claim> claims = jwtSecurityToken.Claims.ToList();
// Value is username
claims.Add(new Claim(ClaimTypes.Name, jwtSecurityToken.Subject));
return claims;
}
internal async Task SignIn()
{
string savedToken = await _localStorageService.GetItemAsync<string>("bearerToken");
JwtSecurityToken jwtSecurityToken = jwtSecurityTokenHandler.ReadJwtToken(savedToken);
var claims = ParseClaims(jwtSecurityToken);
var user = new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt"));
Task<AuthenticationState> autnentcationState = Task.FromResult(new AuthenticationState(user));
NotifyAuthenticationStateChanged(autnentcationState);
}
internal void SignOut()
{
ClaimsPrincipal nobody = new ClaimsPrincipal(new ClaimsIdentity());
Task<AuthenticationState> authenticationState = Task.FromResult(new AuthenticationState(nobody));
NotifyAuthenticationStateChanged(authenticationState);
}
}
}
Login.Razor
@code {
[Inject] HttpClient HttpClient {get; set; }
[Inject] ILocalStorageService LocalStorageService { get; set; }
[Inject] AppAuthenticationStateProvider AuthenticationStateProvider { get; set; }
private User _userTosignin = new();
private bool _signinSuccessful = false;
private bool _attemptTosigninFailed = false;
// private string _attemptTosigninFailedErrorMessage = null;
private async Task signinUser()
{
_attemptTosigninFailed = false;
HttpResponseMessage HttpResponseMessage = await HttpClient.PostAsJsonAsync(APIEndpoints.s_signin, _userTosignin);
if (HttpResponseMessage.IsSuccessStatusCode)
{
string jsonWebToken = await HttpResponseMessage.Content.ReadAsStringAsync();
await LocalStorageService.SetItemAsync("bearerToken", jsonWebToken);
await ((AppAuthenticationStateProvider)AuthenticationStateProvider).SignIn();
HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", jsonWebToken);
_signinSuccessful = true;
}
else
{
_attemptTosigninFailed = true;
}
}
}
FetchData.Razor 代码
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
try
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>(APIEndpoints.s_weather);
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
}
SERVER
Program.cs
using Server.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System.Configuration;
using System.Text.Json.Serialization;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder =>
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
builder.Services.AddDbContext<AppDBContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddDefaultIdentity<IdentityUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<AppDBContext>();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddRouting(options => options.LowercaseUrls = true);
builder.Services.AddControllers();
builder.Services.AddSwaggerGen(
c => {
c.SwaggerDoc("v1", new() { Title = "Server", Version = "v1"});
}
);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
}
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Server v1"));
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
app.MapControllers();
});
app.Run();
Appsettings.json
"AllowedHosts": "*",
"Jwt": {
// Change Characters
"Key": "REDACTED GUID",
"Issuer" : "https://localhost:5003/"
}
WeatherController
using MM.Shared;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Server.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
APPDBCONTEXT
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using MM.Shared.Models;
namespace Server.Data
{
public class AppDBContext : IdentityDbContext
{
public AppDBContext(DbContextOptions<AppDBContext> options) : base(options)
{
}
}
}
SHARED Model
namespace MM.Shared
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}
遇到错误
GET https://localhost:5003/weatherforecast net::ERR_ABORTED 401
_mono_wasm_invoke_js_with_args @ dotnet.6.0.2.6iovc50gwi.js:1
$func219 @ 00970812:0x1a0e2
$func167 @ 00970812:0xcaf7
$func166 @ 00970812:0xba0a
$func2810 @ 00970812:0xabacf
$func1615 @ 00970812:0x6f8eb
$func1613 @ 00970812:0x6f85d
$func966 @ 00970812:0x502dc
$func219 @ 00970812:0x1a0e2
$func167 @ 00970812:0xcaf7
$func166 @ 00970812:0xba0a
$func2810 @ 00970812:0xabacf
$func1615 @ 00970812:0x6f8eb
$func1619 @ 00970812:0x6ff58
$mono_wasm_invoke_method @ 00970812:0x96c9
Module._mono_wasm_invoke_method @ dotnet.6.0.2.6iovc50gwi.js:1
managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet @ managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet:19
beginInvokeDotNetFromJS @ blazor.webassembly.js:1
b @ blazor.webassembly.js:1
e.invokeMethodAsync @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
ve @ blazor.webassembly.js:1
we @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
onGlobalEvent @ blazor.webassembly.js:1
blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Response status code does not indicate success: 401 (Unauthorized).
System.Net.Http.HttpRequestException: Response status code does not indicate success: 401 (Unauthorized).
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__13`1[[MM.Shared.WeatherForecast[], MM.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
at Client.Pages.FetchData.OnInitializedAsync() in \CMS\Pages\FetchData.razor:line 50
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
I started by following a youtube video on building an Identity API Authentication api with Blazor web assembly + asp net core web api, 100 hours of research later and I still cannot get past the "401" Unauthorized when attempting to access API using [Authorize]
I have followed the MSDN multiple times and made many changes to the code. I have reverted back to the original version demonstrated in the guide and still dealing with the issue double & triple-checked everything against what was used. At this point, I feel that API Protection is doomed for now heh. Hopefully, someone can see where I have this wrong because I am at a loss at this point.
I should be getting the WeatherForecast API on this attempt however its unauthorized. error at the bottom
Client code :
Used line in APIEndpoints
internal readonly static string s_weather = quot;{ServerBaseURL}/weatherforecast";
Program.cs
using Blazored.LocalStorage;
using Client;
using Client.Providers;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddSingleton<HttpClient>();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AppAuthenticationStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider>(provider
=> provider.GetRequiredService<AppAuthenticationStateProvider>());
await builder.Build().RunAsync();
AppAuthenticationStateProvider
using Microsoft.AspNetCore.Components.Authorization;
using Blazored.LocalStorage;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace Client.Providers
{
public class AppAuthenticationStateProvider : AuthenticationStateProvider
{
private readonly ILocalStorageService _localStorageService;
private readonly JwtSecurityTokenHandler jwtSecurityTokenHandler = new();
public AppAuthenticationStateProvider(ILocalStorageService localStorageService)
{
_localStorageService = localStorageService;
}
public async override Task<AuthenticationState> GetAuthenticationStateAsync()
{
try
{
string savedToken = await _localStorageService.GetItemAsync<string>("bearerToken");
if (string.IsNullOrWhiteSpace(savedToken))
{
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
JwtSecurityToken jwtSecurityToken = jwtSecurityTokenHandler.ReadJwtToken(savedToken);
DateTime expiry = jwtSecurityToken.ValidTo;
if (expiry < DateTime.UtcNow)
{
await _localStorageService.RemoveItemAsync("bearerToken");
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
//Get Claims from Token and Build Authenticated User Object
var claims = ParseClaims(jwtSecurityToken);
var user = new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt"));
return new AuthenticationState(user);
}
catch (Exception)
{
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
}
private IList<Claim> ParseClaims(JwtSecurityToken jwtSecurityToken)
{
IList<Claim> claims = jwtSecurityToken.Claims.ToList();
// Value is username
claims.Add(new Claim(ClaimTypes.Name, jwtSecurityToken.Subject));
return claims;
}
internal async Task SignIn()
{
string savedToken = await _localStorageService.GetItemAsync<string>("bearerToken");
JwtSecurityToken jwtSecurityToken = jwtSecurityTokenHandler.ReadJwtToken(savedToken);
var claims = ParseClaims(jwtSecurityToken);
var user = new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt"));
Task<AuthenticationState> autnentcationState = Task.FromResult(new AuthenticationState(user));
NotifyAuthenticationStateChanged(autnentcationState);
}
internal void SignOut()
{
ClaimsPrincipal nobody = new ClaimsPrincipal(new ClaimsIdentity());
Task<AuthenticationState> authenticationState = Task.FromResult(new AuthenticationState(nobody));
NotifyAuthenticationStateChanged(authenticationState);
}
}
}
Login.Razor
@code {
[Inject] HttpClient HttpClient {get; set; }
[Inject] ILocalStorageService LocalStorageService { get; set; }
[Inject] AppAuthenticationStateProvider AuthenticationStateProvider { get; set; }
private User _userTosignin = new();
private bool _signinSuccessful = false;
private bool _attemptTosigninFailed = false;
// private string _attemptTosigninFailedErrorMessage = null;
private async Task signinUser()
{
_attemptTosigninFailed = false;
HttpResponseMessage HttpResponseMessage = await HttpClient.PostAsJsonAsync(APIEndpoints.s_signin, _userTosignin);
if (HttpResponseMessage.IsSuccessStatusCode)
{
string jsonWebToken = await HttpResponseMessage.Content.ReadAsStringAsync();
await LocalStorageService.SetItemAsync("bearerToken", jsonWebToken);
await ((AppAuthenticationStateProvider)AuthenticationStateProvider).SignIn();
HttpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", jsonWebToken);
_signinSuccessful = true;
}
else
{
_attemptTosigninFailed = true;
}
}
}
FetchData.Razor code
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
try
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>(APIEndpoints.s_weather);
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
}
SERVER
Program.cs
using Server.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using System.Configuration;
using System.Text.Json.Serialization;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder =>
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
builder.Services.AddDbContext<AppDBContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddDefaultIdentity<IdentityUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<AppDBContext>();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddRouting(options => options.LowercaseUrls = true);
builder.Services.AddControllers();
builder.Services.AddSwaggerGen(
c => {
c.SwaggerDoc("v1", new() { Title = "Server", Version = "v1"});
}
);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
}
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Server v1"));
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
app.MapControllers();
});
app.Run();
Appsettings.json
"AllowedHosts": "*",
"Jwt": {
// Change Characters
"Key": "REDACTED GUID",
"Issuer" : "https://localhost:5003/"
}
WeatherController
using MM.Shared;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Server.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
APPDBCONTEXT
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using MM.Shared.Models;
namespace Server.Data
{
public class AppDBContext : IdentityDbContext
{
public AppDBContext(DbContextOptions<AppDBContext> options) : base(options)
{
}
}
}
SHARED Model
namespace MM.Shared
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}
Error Encountered
GET https://localhost:5003/weatherforecast net::ERR_ABORTED 401
_mono_wasm_invoke_js_with_args @ dotnet.6.0.2.6iovc50gwi.js:1
$func219 @ 00970812:0x1a0e2
$func167 @ 00970812:0xcaf7
$func166 @ 00970812:0xba0a
$func2810 @ 00970812:0xabacf
$func1615 @ 00970812:0x6f8eb
$func1613 @ 00970812:0x6f85d
$func966 @ 00970812:0x502dc
$func219 @ 00970812:0x1a0e2
$func167 @ 00970812:0xcaf7
$func166 @ 00970812:0xba0a
$func2810 @ 00970812:0xabacf
$func1615 @ 00970812:0x6f8eb
$func1619 @ 00970812:0x6ff58
$mono_wasm_invoke_method @ 00970812:0x96c9
Module._mono_wasm_invoke_method @ dotnet.6.0.2.6iovc50gwi.js:1
managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet @ managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet:19
beginInvokeDotNetFromJS @ blazor.webassembly.js:1
b @ blazor.webassembly.js:1
e.invokeMethodAsync @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
ve @ blazor.webassembly.js:1
we @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
onGlobalEvent @ blazor.webassembly.js:1
blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Response status code does not indicate success: 401 (Unauthorized).
System.Net.Http.HttpRequestException: Response status code does not indicate success: 401 (Unauthorized).
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__13`1[[MM.Shared.WeatherForecast[], MM.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
at Client.Pages.FetchData.OnInitializedAsync() in \CMS\Pages\FetchData.razor:line 50
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在fetchdata.Razor中找到了解决方案,我需要以下
found the solution, In FetchData.razor i needed the following