У меня есть концентратор signalR, который не может вызвать функцию, которая получает мне роли моих пользователей из моей базы данных.
Вот мой стартап ...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Contract.Extensions;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using SharedKernel;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Contract.API.Extensions;
using Contract.Data;
using Microsoft.EntityFrameworkCore;
using Contract.Factories;
using AutoMapper;
using Contract.API.Hubs;
namespace Contract.API
{
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.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var connection = Configuration.GetConnectionString("ContractContext");
services.AddAutoMapper();
services.AddMvc();
services.AddSignalR();
services.AddContexts(connection);
services.ConfigureSwaggerServices();
services.RegisterServices();
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddAzureAdBearer(options => Configuration.Bind("AzureAd", options));
var builder = EventExtensions.RegisterEvents();
builder.Populate(services);
var container = builder.Build();
DomainEvents.Container = new NetEventContainer(container);
return container.Resolve<IServiceProvider>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, Db.ContractContext context)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
context.Database.Migrate();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseCors(builder =>
{
builder
.WithOrigins("http://localhost:57704", "http://localhost:4200")
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.ConfigureSwaggerApp();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMiddleware<SignalRMiddleware>();
app.UseWebSockets();
app.UseAuthentication();
app.UseSignalR(routes =>
{
routes.MapHub<ContractHub>("/contractHub");
});
app.UseMvc();
}
}
}
Вот мой хаб ...
using Contract.API.ViewModels;
using Contract.Data.Query.User;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Contract.API.Hubs
{
[Authorize]
public class ContractHub : Hub
{
private readonly IUserInfoQuery _userInfoQuery;
private static List<ActiveSignalRUser> activeUsers = new List<ActiveSignalRUser>();
public ContractHub(IUserInfoQuery userInfoQuery)
{
_userInfoQuery = userInfoQuery;
}
public async Task AddToActiveUsers(ActiveSignalRUser user)
{
UserInfo appUser = _userInfoQuery.GetUserInfo();
var sameContractUsers = new List<ActiveSignalRUser>();
if (appUser.CanWrite == true)
{
var message = $"{user.UserName} has logged onto this contract. Please coordinate with them in order to prevent duplicate/overridden work flow";
// alert Group that User has loggged on
await Clients.Group(user.ContractNumber).SendAsync("notifyGroup", message);
// add user to group named after contractNumber
await Groups.AddToGroupAsync(Context.ConnectionId, user.ContractNumber);
// add user to active global users
user.ConnectionId = Context.ConnectionId;
activeUsers.Add(user);
var count = activeUsers.Where(a => a.ContractNumber == user.ContractNumber).Count();
if (count > 1 && count < 3)
{
// send message about previous users
message = $"{activeUsers[0].UserName} is already accessing this contract. Please coordinate with them in order to prevent duplicate/overridden work.";
await Clients.Caller.SendAsync("notifyCaller", message);
}
else if (count > 2)
{
message = $"{activeUsers[0].UserName} and others are already accessing this contract. Please coordinate with them in order to prevent duplicate/overriden work";
await Clients.Caller.SendAsync("notifyCaller", message);
}
}
}
public override Task OnDisconnectedAsync(Exception exception)
{
activeUsers.Remove(activeUsers.Where(a => a.ConnectionId == Context.ConnectionId).FirstOrDefault());
return null;
}
}
}
и вот мое промежуточное ПО ...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Contract.API.Hubs
{
public class SignalRMiddleware
{
private readonly RequestDelegate _next;
public SignalRMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
var request = httpContext.Request;
// web sockets cannot pass headers so we must take the access token from query param and
// add it to the header before authentication middleware runs
if (request.Path.StartsWithSegments("/contractHub", StringComparison.OrdinalIgnoreCase) &&
request.Query.TryGetValue("access_token", out var accessToken))
{
request.Headers.Add("Authorization", $"Bearer {accessToken}");
}
await _next(httpContext);
}
}
}
Код добавляется в концентратор в строке 25 с исключением ссылки Null. (UserInfo appUser = _userInfoQuery.GetUserInfo ();) Вот код этой функции только для обеспечения полного охвата ...
public UserInfo GetUserInfo()
{
var userName = _requestContext.Requestor.Identity.Name;
var displayName = _requestContext.Requestor.Claims.Where(f => f.Type == "name").Select(s => s.Value).FirstOrDefault() ?? _requestContext.Requestor.Identity.Name;
var dbUser = _contractContext.Users
.Include(i => i.Roles)
.Include(i => i.FirewallWhiteList)
.Include(i => i.AssignedStatus)
.FirstOrDefault(f => f.UserName == userName);
return new UserInfo(userName, displayName, dbUser);
}
Я перепробовал все, что смог найти. пожалуйста, помогите!