У меня есть служба SignalR, которая использует IHostedService
для доступа к SignalR в Azure. Я пытаюсь реализовать функцию Negotiate, которая возвращает SignalRConnectionInfo
. Проблема в том, что мне нужно передать UserId в ConnectionInfo, но я еще не знаю его при заполнении параметров. Я использую .NET 8 в изолированном режиме и следую этим документам Microsoft.
Функция
[Function("Negotiate")]
public static string Negotiate([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
[SignalRConnectionInfoInput(HubName = "SomeHub", UserId = "????")] string connectionInfo)
{
Guid userId = // Get userId from database
await signalRService.AddUserToGroupAll(userId);
return connectionInfo; // How to get this when i don't know UserId in the parameters yet??
}
СигналRService
public class SignalRService(IConfiguration configuration)
{
private ServiceHubContext _messageHubContext;
public async Task AddUserToGroupAll(Guid userId)
{
await _messageHubContext.Groups.AddToGroupAsync(userId.ToString(), /** groupname **/);
}
#region IHostService Functions
async Task IHostedService.StartAsync(CancellationToken cancellationToken)
{
using ServiceManager serviceManager = new ServiceManagerBuilder()
.WithOptions(o => o.ConnectionString = configuration[ConfigurationConstants.AzureSignalRConnectionString])
.BuildServiceManager();
_messageHubContext = await serviceManager.CreateHubContextAsync("SomeHub", cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await _messageHubContext.DisposeAsync();
}
#endregion
}
Мой вопрос: как мне вернуть SignalRConnectionInfo
в этом случае?
Спасибо!
Если вы хотите согласовать анонимный сеанс, вы можете получить его из SignalRService, поэтому вам не нужно передавать UserId в функцию Negotiate.
[Function("Negotiate")]
public static async Task<IActionResult> Negotiate(
[HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
FunctionContext context)
{
var signalRService = (SignalRService)context.InstanceServices.GetService(typeof(SignalRService));
var connectionInfo = await signalRService.GetSignalRConnectionInfo();
return new OkObjectResult(connectionInfo);
}
Но я не использую анонимность и не использую IActionResult
@Карс Negotiate([HttpTrigger(AuthorizationLevel.Anonymous)]
. Это анонимно и находится в вашем коде. Если вы не хотите использовать IActionResult, просто return connectionInfo;
.
В моем SignalRService нет метода GetSignalRConnectionInfo.
Используйте приведенный ниже код, чтобы вернуть ConnectionInfo
в изолированных функциях Azure.
UserId
— необязательный параметр, как указано в MSDOC, и ConnectionInfo может быть возвращено даже без передачи UserId.public class Function1
{
private readonly ILogger _logger;
public Function1(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger("negotiate");
}
[Function("negotiate")]
public HttpResponseData Negotiate(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req,
[SignalRConnectionInfoInput(HubName = "HubValue", UserId = "")] MyConnectionInfo connectionInfo)
{
_logger.LogInformation($"SignalR Connection URL = '{connectionInfo.Url}'");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString($"Connection URL = '{connectionInfo.Url}'");
return response;
}
}
public class MyConnectionInfo
{
public string Url { get; set; }
public string AccessToken { get; set; }
}
Ответ консоли:
Azure Functions Core Tools
Core Tools Version: 4.0.5801 Commit hash: N/A +5ac2f09758b98257e728dd1b5576ce5ea9ef68ff (64-bit)
Function Runtime Version: 4.34.1.22669
[2024-06-12T12:45:03.702Z] Found C:\Users\uname\Source\Repos\FunctionApp18\FunctionApp18.csproj. Using for user secrets file configuration.
[2024-06-12T12:45:14.003Z] Azure Functions .NET Worker (PID: 12024) initialized in debug mode. Waiting for debugger to attach...
[2024-06-12T12:45:14.144Z] Worker process started and initialized.
Functions:
negotiate: [POST] http://localhost:7065/api/negotiate
For detailed output, run func with --verbose flag.
[2024-06-12T12:45:19.095Z] Host lock lease acquired by instance ID '000000000000000000000000F72731CC'.
[2024-06-12T12:45:20.088Z] Executing 'Functions.negotiate' (Reason='This function was programmatically called via the host APIs.', Id=c31883d3-4125-4cea-9c89-2c6456b76b26)
[2024-06-12T12:45:20.918Z] SignalR Connection URL = 'https://functionapp17.service.signalr.net/client/?hub=hubvalue'
[2024-06-12T12:45:21.022Z] Executed 'Functions.negotiate' (Succeeded, Id=c31883d3-4125-4cea-9c89-2c6456b76b26, Duration=968ms)
Выход:
Спасибо за ответ. это работает, но проблема в том, что мне НУЖНО установить UserId в ConnectionInfo. Но наше приложение настроено так, что я могу получить его только из базы данных, поэтому у меня не будет его в параметрах функции. Как мне таким образом получить UserId в ConnectionInfo?
Не могли бы вы задать новый вопрос, указав полную информацию о вашем требовании?
ServiceHubContext
имеет метод NegotiateAsync
, к которому вы можете перейти NegotiationOptions
. Вы можете установить там UserId
.
Например:
var negotiationResponse = await _serviceHubContext.NegotiateAsync(new NegotiationOptions {
UserId = userId.ToString()
});
var connInfo = new SignalRConnectionInfo {
AccessToken = negotiationResponse.AccessToken,
Url = negotiationResponse.Url
};
И теперь у вас есть согласованная информация с UserId.
Как упоминалось в MSDOC UserId не является обязательным. Изображение