更新到 .net core 2.2 后信号 r 不工作
Signal r not working after updating to .net core 2.2
我们使用信号 r 来驱动我们的前端进行更新,它一直在 100% 工作,直到我们升级到 .net core 2.2
查看下面的启动,方法确实被调用,正常的后端调用工作没有问题,但是一旦 Signal r 尝试从前端连接,我就会收到 cors 错误。
我试过只允许所有通过 cors,但这也没有用。
protected IServiceProvider ConfigureServicesImplementation(IServiceCollection services)
{
services.Configure<DatabaseConfiguration>(Configuration.GetSection(DatabaseConfigurationName));
services.Configure<TokenProviderConfiguration>(Configuration.GetSection(TokenProviderConfigurationName));
services.AddOptions();
services.AddCors();
services.AddAutoMapper();
services.AddAutofac();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<DatabaseMigrator>();
services.AddScoped<AdminTenantDbInitialiser>();
services.AddScoped<TenantDbInitialiser>();
services.AddScoped<HubBase>();
services.AddScoped<HubService>();
services.AddSignalR()
.AddJsonProtocol(options =>
{
options.PayloadSerializerSettings.Converters.Add(new StringEnumConverter
{
});
});
services.AddDbContext<DefaultDbContext>(options =>
{
options.UseSqlServer(Configuration.GetSection(DatabaseConfigurationName)["ConnectionString"]);
});
services.AddDbContext<TenantDbContext>(options =>
{
options.UseSqlServer(Configuration.GetSection(DatabaseConfigurationName)["TenantManagementConnectionString"]);
});
services.AddMemoryCache();
services.AddHealthChecks();
ConfigureAuthImplementation(services);
ConfigureMvcImplementation(services);
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(Assembly.Load("Digitise.Domain.Services"))
.Where(t => t.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase))
//.InstancePerRequest()
.PropertiesAutowired();
builder.Populate(services);
var container = builder.Build();
return new AutofacServiceProvider(container);
}
private void ConfigureMvcImplementation(IServiceCollection services)
{
var mvc = services.AddMvcCore(options =>
{
options.Filters.Add(new ProducesAttribute("application/json"));
options.Filters.Add(typeof(ValidateModelAttribute));
})
.AddApiExplorer()
.AddAuthorization()
.AddDataAnnotations()
.AddJsonFormatters()
.AddControllersAsServices()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new StringEnumConverter
{
});
});
if (Environment.IsDevelopment())
{
var controllers = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type))
.ToList();
var sp = services.BuildServiceProvider();
foreach (var controllerType in controllers)
{
var controller = sp.GetService(controllerType);
}
}
mvc.AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<UserLoginInputValidator>();
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
fv.ImplicitlyValidateChildProperties = true;
});
}
protected void ConfigureApp(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHostingEnvironment env, IMapper autoMapper, bool addTenantRoute = false)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwaggerUi3(x => { });
//autoMapper.ConfigurationProvider.AssertConfigurationIsValid();
}
else
{
app.UseExceptionHandler("/error");
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
app.UseSignalR(routes =>
{
routes.MapHub<HubBase>("/globalhub");
});
app.UseMvc(routes =>
{
if (addTenantRoute)
{
routes.MapRoute("default", "{controller}/{action}/{tenant?}/{id?}", defaults: new
{
controller = "app",
action = "ping"
});
}
else
{
routes.MapRoute("default", "{controller}/{action}/{id?}", defaults: new
{
controller = "app",
action = "ping"
});
}
routes.MapRoute(name: "ping", template: "app/ping", defaults: new { controller = "App", action = "Ping" });
});
app.UseAuthentication();
}
关于从前端连接请看下面的代码。
public startHubConnection(): void {
if (!this.hubConnection) {
const currentUser = this.authenticationService.getCurrentUser();
this.hubConnection = new HubConnectionBuilder().withUrl(this.url + '/globalhub?Authorization=Bearer ' + currentUser.accessToken).build();
}
this.hubConnection
.start()
.then(() => {
this.isHubConnected = true;
if (this.firstRun) {
this.firstRun = false;
this.manageHubConnections();
}
this.hubReconnectAllowed = true;
this.serverStatusChange.emit(true);
if (this.hubReconnectionId) {
this.isHubConnected = true;
this.notificationService.success('Server online', 'Reconnect with server successfull.');
this.globalService.systemOnline = true;
clearInterval(this.hubReconnectionId);
}
})
.catch(err => console.dir('manual: ' + err));
}
CORS 中间件必须在您的应用程序中任何定义的端点之前,您希望在其中支持跨域请求,因此您应该在 UseSignalR
:
之前调用 UseCors
...
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
app.UseSignalR(routes =>
{
routes.MapHub<HubBase>("/globalhub");
});
...
因此在 2.2 中 .AllowAnyOrigin() + .AllowCredentials() 不再被允许,因为它是不安全的。您需要使用 WithOrigins() 显式设置允许的来源。
感谢 BrennanConroy
解决了问题
我们使用信号 r 来驱动我们的前端进行更新,它一直在 100% 工作,直到我们升级到 .net core 2.2
查看下面的启动,方法确实被调用,正常的后端调用工作没有问题,但是一旦 Signal r 尝试从前端连接,我就会收到 cors 错误。
我试过只允许所有通过 cors,但这也没有用。
protected IServiceProvider ConfigureServicesImplementation(IServiceCollection services)
{
services.Configure<DatabaseConfiguration>(Configuration.GetSection(DatabaseConfigurationName));
services.Configure<TokenProviderConfiguration>(Configuration.GetSection(TokenProviderConfigurationName));
services.AddOptions();
services.AddCors();
services.AddAutoMapper();
services.AddAutofac();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<DatabaseMigrator>();
services.AddScoped<AdminTenantDbInitialiser>();
services.AddScoped<TenantDbInitialiser>();
services.AddScoped<HubBase>();
services.AddScoped<HubService>();
services.AddSignalR()
.AddJsonProtocol(options =>
{
options.PayloadSerializerSettings.Converters.Add(new StringEnumConverter
{
});
});
services.AddDbContext<DefaultDbContext>(options =>
{
options.UseSqlServer(Configuration.GetSection(DatabaseConfigurationName)["ConnectionString"]);
});
services.AddDbContext<TenantDbContext>(options =>
{
options.UseSqlServer(Configuration.GetSection(DatabaseConfigurationName)["TenantManagementConnectionString"]);
});
services.AddMemoryCache();
services.AddHealthChecks();
ConfigureAuthImplementation(services);
ConfigureMvcImplementation(services);
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(Assembly.Load("Digitise.Domain.Services"))
.Where(t => t.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase))
//.InstancePerRequest()
.PropertiesAutowired();
builder.Populate(services);
var container = builder.Build();
return new AutofacServiceProvider(container);
}
private void ConfigureMvcImplementation(IServiceCollection services)
{
var mvc = services.AddMvcCore(options =>
{
options.Filters.Add(new ProducesAttribute("application/json"));
options.Filters.Add(typeof(ValidateModelAttribute));
})
.AddApiExplorer()
.AddAuthorization()
.AddDataAnnotations()
.AddJsonFormatters()
.AddControllersAsServices()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new StringEnumConverter
{
});
});
if (Environment.IsDevelopment())
{
var controllers = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type))
.ToList();
var sp = services.BuildServiceProvider();
foreach (var controllerType in controllers)
{
var controller = sp.GetService(controllerType);
}
}
mvc.AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<UserLoginInputValidator>();
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
fv.ImplicitlyValidateChildProperties = true;
});
}
protected void ConfigureApp(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHostingEnvironment env, IMapper autoMapper, bool addTenantRoute = false)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwaggerUi3(x => { });
//autoMapper.ConfigurationProvider.AssertConfigurationIsValid();
}
else
{
app.UseExceptionHandler("/error");
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
app.UseSignalR(routes =>
{
routes.MapHub<HubBase>("/globalhub");
});
app.UseMvc(routes =>
{
if (addTenantRoute)
{
routes.MapRoute("default", "{controller}/{action}/{tenant?}/{id?}", defaults: new
{
controller = "app",
action = "ping"
});
}
else
{
routes.MapRoute("default", "{controller}/{action}/{id?}", defaults: new
{
controller = "app",
action = "ping"
});
}
routes.MapRoute(name: "ping", template: "app/ping", defaults: new { controller = "App", action = "Ping" });
});
app.UseAuthentication();
}
关于从前端连接请看下面的代码。
public startHubConnection(): void {
if (!this.hubConnection) {
const currentUser = this.authenticationService.getCurrentUser();
this.hubConnection = new HubConnectionBuilder().withUrl(this.url + '/globalhub?Authorization=Bearer ' + currentUser.accessToken).build();
}
this.hubConnection
.start()
.then(() => {
this.isHubConnected = true;
if (this.firstRun) {
this.firstRun = false;
this.manageHubConnections();
}
this.hubReconnectAllowed = true;
this.serverStatusChange.emit(true);
if (this.hubReconnectionId) {
this.isHubConnected = true;
this.notificationService.success('Server online', 'Reconnect with server successfull.');
this.globalService.systemOnline = true;
clearInterval(this.hubReconnectionId);
}
})
.catch(err => console.dir('manual: ' + err));
}
CORS 中间件必须在您的应用程序中任何定义的端点之前,您希望在其中支持跨域请求,因此您应该在 UseSignalR
:
UseCors
...
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
app.UseSignalR(routes =>
{
routes.MapHub<HubBase>("/globalhub");
});
...
因此在 2.2 中 .AllowAnyOrigin() + .AllowCredentials() 不再被允许,因为它是不安全的。您需要使用 WithOrigins() 显式设置允许的来源。 感谢 BrennanConroy
解决了问题