使用身份验证托管的Blazor Wasm上出现Azure 500错误 [英] Azure 500 error on a Blazor Wasm Hosted with Authentication
问题描述
我在这里完全不知所措。我有一个Blazor WASM托管运行.net5,它已经部署到Azure应用程序服务。当没有数据库时,部署到Azure是没有问题的。它如预期的那样装载和运行。从那以后,我安装了身份和DBContext。所有内容都在本地构建,并使用本地SQL实例正常运行。
在Azure上,我创建了一个新的SQLServer和一个SQL数据库。在SQL数据库防火墙设置中,我拥有允许Azure服务和资源访问此服务器的规则以及我的客户端IP的规则(不是Azure应用程序的IP)。
对于配置中的应用程序服务,我有一个名为DefaultConnection的ConnectionString(与appsettings.json中的相同),其连接字符串与SQLDatabase提供的源AppConfig类型SqlAzure相同
我正在使用VS2019在服务器上发布项目(启动项目)发布到Azure。我选择的Target是Azure->;Azure App Sevices(Windows)和我的实例名称。配置为版本、目标框架net5.0、部署模式框架相关、目标运行时可移植。
服务依赖项设置为AzureSqlDatabase,它使用ConnectionName DefaultConnection,用户名和密码是在Azure上创建的SQL Server的管理用户密码设置,SaveConnectionStringValue是Azure应用程序设置。(这会自动填充上述应用程序服务配置连接字符串。当我单击发布时,我在输出中看到所有发布都正确:
Publish Succeeded.
Web App was published successfully http://bbqfriend.azurewebsites.net/
========== Build: 1 succeeded, 0 failed, 6 up-to-date, 0 skipped ==========
========== Publish: 1 succeeded, 0 failed, 0 skipped ==========
Installation of Web App Site extension Microsoft.AspNetCore.AzureAppServices.SiteExtension is in progress...
Restarting the Web App...
Successfully installed Web App extension Microsoft.AspNetCore.AzureAppServices.SiteExtension
Successfully restarted Web App.
但是,当页面启动时,它显示500错误。
如果我返回到发布和编辑设置-数据库-DefaultConnection,并选中在运行时使用此连接字符串,选择在ServiceDependency中配置的连接字符串以及EntityFrameworkMigrations DataContext在发布时应用此迁移。当我发布该配置文件时,它将执行迁移以及我在DataContext OnModel创建覆盖中定义的种子protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
#region Identity Seed
modelBuilder.ApplyConfiguration(new ApplicationUserConfiguration());
modelBuilder.ApplyConfiguration(new IdentityRoleConfiguration());
modelBuilder.ApplyConfiguration(new IdentityUserRoleConfiguration());
#endregion
//modelBuilder.ApplyConfiguration(new CountryConfiguration());
}
因此,我知道连接字符串是正确的,并且有一个具有正确模型和种子数据的数据库。为什么我得了500分?!?
这是我在服务器项目中的appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=.;Database={DatabaseName};Trusted_Connection=True;MultipleActiveResultSets=true"
},
"IdentityServer": {
"Clients": {
"XXXX.Client": {
"Profile": "IdentityServerSPA"
}
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.MSSqlServer" ],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.Authorization.DefaultAuthorizationService": "Warning",
"Microsoft.EntityFrameworkCore": "Warning",
"System": "Warning",
"System.Net.Http.HttpClient*": "Warning",
"IdentityServer4": "Warning",
"Serilog.AspNetCore": "Warning"
}
},
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "DefaultConnection",
"sinkOptionsSection": {
"tableName": "Logs"
},
"columnOptionsSection": {
"additionalColumns": [
{
"ColumnName": "InstanceId"
},
{
"ColumnName": "Origin"
},
{
"ColumnName": "SourceContext"
},
{
"ColumnName": "UserId"
},
{
"ColumnName": "Username"
}
],
"excludeAdditionalProperties": true
}
}
}
]
},
"AllowedHosts": "*"
}
以下是服务器项目的Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
//Register the Datacontext and Connection String
services.AddDbContext<DataContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
//Sets up the default Asp.net core Identity Screens - Use Identity Scaffolding to override defaults
services.AddDefaultIdentity<ApplicationUser>( options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireUppercase = true;
options.Password.RequiredUniqueChars = 0;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequiredLength = 8;
options.User.RequireUniqueEmail = true;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<DataContext>();
//Associates the User to Context with Identity
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, DataContext>( options =>
{
options.IdentityResources["openid"].UserClaims.Add(JwtClaimTypes.Role);
options.ApiResources.Single().UserClaims.Add(JwtClaimTypes.Role);
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove(JwtClaimTypes.Role);
//Adds authentication handler
services.AddAuthentication().AddIdentityServerJwt();
//Register Repositories for Dependency Injection
services.AddScoped<ICountryRepository, CountryRepository>();
services.AddControllersWithViews();
services.AddRazorPages();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dataContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//AutoMigrates data
//dataContext.Database.Migrate();
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseSerilogIngestion();
app.UseSerilogRequestLogging();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
以下是服务器项目的Program.cs
public class Program
{
public static void Main(string[] args)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.Enrich.WithProperty("InstanceId", Guid.NewGuid())
.Enrich.WithProperty("Origin", "Server")
.CreateLogger();
try
{
Log.Information("Starting up");
CreateHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application start-up failed");
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
以下是客户端项目的Program.cs
public static async Task Main(string[] args)
{
//Serilog
var levelSwitch = new LoggingLevelSwitch();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(levelSwitch)
.Enrich.WithProperty("InstanceId", Guid.NewGuid())
.Enrich.FromLogContext()
.WriteTo.BrowserHttp(controlLevelSwitch: levelSwitch)
.CreateLogger();
Log.ForContext<Program>().Information("Client has started");
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddLogging(logging =>
{
logging.ClearProviders();
logging.AddSerilog(dispose: true);
});
builder.Services.AddHttpClient("XXX.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddTransient(sp =>
sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("XXXX.ServerAPI"));
builder.Services.AddApiAuthorization()
.AddAccountClaimsPrincipalFactory<RolesClaimsPrincipalFactory>();
//Register Services
var baseAddress = new Uri($"{builder.HostEnvironment.BaseAddress}api/");
void RegisterTypedClient<TClient, TImplementation>(Uri apiBaseUrl)
where TClient : class where TImplementation : class, TClient
{
builder.Services.AddHttpClient<TClient, TImplementation>(client => client.BaseAddress = apiBaseUrl)
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
}
RegisterTypedClient<ICountryService, CountryService>(baseAddress);
await builder.Build().RunAsync();
}
我确实配置了Serilog,它看起来也在工作。以下是我在服务器启动过程中看到的错误消息
System.InvalidOperationException: Startup assembly Microsoft.ApplicationInsights.StartupBootstrapper failed to execute. See the inner exception for more details.
---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.ApplicationInsights.StartupBootstrapper, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'Microsoft.ApplicationInsights.StartupBootstrapper, Culture=neutral, PublicKeyToken=null'
at System.Reflection.RuntimeAssembly.InternalLoad(ObjectHandleOnStack assemblyName, ObjectHandleOnStack requestingAssembly, StackCrawlMarkHandle stackMark, Boolean throwOnFileNotFound, ObjectHandleOnStack assemblyLoadContext, ObjectHandleOnStack retAssembly)
at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, RuntimeAssembly requestingAssembly, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, AssemblyLoadContext assemblyLoadContext)
at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.ExecuteHostingStartups()
--- End of inner exception stack trace ---
和
System.InvalidOperationException: Startup assembly DiagnosticServices.HostingStartup failed to execute. See the inner exception for more details.
---> System.IO.FileNotFoundException: Could not load file or assembly 'DiagnosticServices.HostingStartup, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'DiagnosticServices.HostingStartup, Culture=neutral, PublicKeyToken=null'
at System.Reflection.RuntimeAssembly.InternalLoad(ObjectHandleOnStack assemblyName, ObjectHandleOnStack requestingAssembly, StackCrawlMarkHandle stackMark, Boolean throwOnFileNotFound, ObjectHandleOnStack assemblyLoadContext, ObjectHandleOnStack retAssembly)
at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, RuntimeAssembly requestingAssembly, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, AssemblyLoadContext assemblyLoadContext)
at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.ExecuteHostingStartups()
--- End of inner exception stack trace ---
更新 我能够复制上述错误消息,并通过Serilog将它们记录到数据库中。
因此,我们可以从服务器Program.cs main方法(如上)看到";启动,下一个条目来自EntityFramework模型验证。然后就出现了错误。我可以将命名空间Microsoft.AspNetCore.Hosting.Diagnostics视为异常的来源。
我试图添加Nuget引用,但没有执行任何操作
我尝试添加对已添加服务的引用。AddApplicationInsightsTelemeter();指向服务器Startup.cs ConfigureServices的引用和指向appsettings.json的ApplicationInsights InstrumentationKey(已作为变量存在于Azure中),但这没有任何作用
我添加了对的引用,并添加了
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseAzureAppServices();
});
根据此处https://github.com/dotnet/extensions/issues/2566没有帮助的解决办法
更新第2天
添加更多信息,因为我仍然收到相同的异常。我很好奇这是不是版本之间的兼容性问题。我的应用程序是.net5,并使用.net5早期访问在Azure上运行。
以下是我用于服务器项目的Nuget包
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="5.0.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="5.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="Serilog.AspNetCore.Ingestion" Version="1.0.0-dev-00012" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="5.6.0" />
</ItemGroup>
以下是客户端项目的Nuget包
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" />
<PackageReference Include="Serilog.Sinks.BrowserHttp" Version="1.0.0-dev-00012" />
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
</ItemGroup>
我已经尝试从客户端和服务器项目中删除Serilog。我还是收到了500分。
删除Serilog后,我尝试使用https://github.com/dotnet/extensions/issues/2566中的.UseAzureAppServices(),但也没有成功。
我确实注意到另一条错误消息
2021-01-06 19:00:38.322 +00:00 [Error] Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware: An unhandled exception has occurred while executing the request.
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.Extensions.DependencyInjection.IdentityServerBuilderConfigurationExtensions.<>c.<AddSigningCredentials>b__10_2(IServiceProvider sp)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at ... (removed for post size)
当我将我的站点部署为Blazor WebAssembly托管解决方案时,我已经能够将其隔离为一个问题。我的网站在从Blazor WebAssembly切换到Blazor WebAssembly之前,已经升级到.net5版本。.net5版本能够顺利部署到Azure上。在部署WebAssembly托管版本时,我收到了500个错误。因此,这与将Blazor WebAssembly托管解决方案部署到Azure有关。
我还尝试了创建一个没有身份验证的开箱即用的Blazor WebAssembly托管解决方案,并将其部署到Azure。这项工作没有任何问题。然而,当我创建使用身份验证托管的开箱即用的Blazor WebAssembly(应用程序中存储的单个用户帐户)并将其部署到Azure时,它失败了,错误为500!
推荐答案
使其工作的最简单方法:
将环境变量
ASPNETCORE_ENVIRONMENT
添加/设置为Development
...和您的托管Blazor WASM身份最终将在Azure应用程序服务中运行
如果您不想使用上面的简单方法,请执行以下操作:
- 按照本文生成自签名证书:
(在生成自签名证书部分中) https://gavilan.blog/2020/08/18/blazor-using-a-self-signed-certificate-for-identityserver4-in-azure-app-service/
- 记住您用于生成的证书的密码。
- 将证书放在您的项目中(例如,在服务器项目中)
- 将这些附加到
appsettings.json
文件中:
- 再次发布应用程序。
这篇关于使用身份验证托管的Blazor Wasm上出现Azure 500错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!