我有 ASP.NET MVC 应用程序,并且正在使用 SignalR 进行实时出价。我需要通过 JavaScript 和 C#(从我的一个控制器)使用客户端。
这是我的 Startup.cs 文件:
namespace DesignAndBuilding.Web
{
using System.Reflection;
using AutoMapper;
using DesignAndBuilding.Data;
using DesignAndBuilding.Data.Common;
using DesignAndBuilding.Data.Common.Repositories;
using DesignAndBuilding.Data.Models;
using DesignAndBuilding.Data.Repositories;
using DesignAndBuilding.Data.Seeding;
using DesignAndBuilding.Services;
using DesignAndBuilding.Services.Mapping;
using DesignAndBuilding.Services.Messaging;
using DesignAndBuilding.Web.Hubs;
using DesignAndBuilding.Web.ViewModels;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public class Startup
{
private readonly IConfiguration configuration;
public Startup(IConfiguration configuration)
{
this.configuration = configuration;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer(this.configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<ApplicationUser>(IdentityOptionsProvider.GetIdentityOptions)
.AddRoles<ApplicationRole>().AddEntityFrameworkStores<ApplicationDbContext>();
services.AddSignalR(options =>
{
options.EnableDetailedErrors = true;
})
.AddMessagePackProtocol();
services.Configure<CookiePolicyOptions>(
options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAutoMapper(typeof(Startup), typeof(MappingProfile));
services.AddMemoryCache();
services.AddControllersWithViews(
options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
}).AddRazorRuntimeCompilation();
services.AddRazorPages();
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddSingleton(this.configuration);
// Data repositories
services.AddScoped(typeof(IDeletableEntityRepository<>), typeof(EfDeletableEntityRepository<>));
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
services.AddScoped<IDbQueryRunner, DbQueryRunner>();
// Application services
services.AddTransient<IEmailSender, NullMessageSender>();
services.AddTransient<IBuildingsService, BuildingsService>();
services.AddTransient<IUsersService, UsersService>();
services.AddTransient<IAssignmentsService, AssignmentsService>();
services.AddTransient<IBidsService, BidsService>();
services.AddTransient<INotificationsService, NotificationsService>();
services.AddTransient<AuthenticationService>();
// Auto Mapper Configurations
services.AddSingleton(provider => new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingProfile());
}).CreateMapper());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
AutoMapperConfig.RegisterMappings(typeof(ErrorViewModel).GetTypeInfo().Assembly);
// Seed data on application startup
using (var serviceScope = app.ApplicationServices.CreateScope())
{
var dbContext = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
dbContext.Database.Migrate();
new ApplicationDbContextSeeder().SeedAsync(dbContext, serviceScope.ServiceProvider).GetAwaiter().GetResult();
}
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(
endpoints =>
{
endpoints.MapHub<NotificationsHub>("/notificationshub");
endpoints.MapHub<BidsHub>("/bidshub");
endpoints.MapControllerRoute("areaRoute", "{area:exists}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
}
这是我的 JS 客户端:
console.log('Bids script loaded successfully!');
setupConnection = async function start() {
let connection = null;
connection = await new signalR.HubConnectionBuilder()
.withUrl("/bidshub")
.build();
await connection.on('newbidplaced', (obj) => {
console.log(obj);
})
await connection.start()
.catch(err => console.error(err.toString()))
.then(() => {
connection.invoke('NewBid', '1', 'testUser', 5.4);
});
}
setupConnection();
这是我的一个控制器的 C# 客户端:
var connection = new HubConnectionBuilder()
.AddMessagePackProtocol()
.WithUrl($"https://{this.Request.Host}/bidshub", options =>
{
options.UseDefaultCredentials = true;
})
.WithAutomaticReconnect()
.Build();
await connection.StartAsync();
await connection.InvokeAsync("NewBid", strId, user.Id, bidViewModel.BidPrice);
await connection.DisposeAsync();
我的问题是,当我使用 C# 客户端时,SignalR hub 中的 Context.User 始终为 null。但是,当我使用 JS 客户端时,用户已通过身份验证并且 Context.User 不为 null。有什么区别以及可能存在什么问题?
分析代码后,您使用cookie进行身份验证。默认情况下,支持
Javascript clients
(浏览器),但不支持 C# Clients
。
所以你应该获取 cookie 并在 C# 客户端中使用它,如下所示:
var connection = new HubConnectionBuilder()
.WithUrl("https://yourserver.com/bidshub", options =>
{
options.HttpMessageHandlerFactory = _ => new HttpClientHandler
{
CookieContainer = new System.Net.CookieContainer()
};
options.Headers["Cookie"] = cookie;
})
.Build();