使用REST API将消息发送到.Net Core Core中的Azure服务总线队列

时间:2017-03-26 15:45:31

标签: rest azure asp.net-core servicebus azure-servicebus-queues

我想在.Net Core中向Azure Service Bus Queue发送消息,但WindowsAzure.ServiceBus包与.Net Core不兼容。

有人能告诉我如何使用REST API将消息发送到队列吗?

3 个答案:

答案 0 :(得分:4)

虽然current client不兼容.NET Core,但正在进行中的new client是100%兼容的。预发布包将于4月3日开始提供,并且可以跟踪状态here。您可以下载课程代码并在今天进行编译,并注意API将随着团队试图充实设计细节而改变。

答案 1 :(得分:2)

  

有人能告诉我如何使用REST API将消息发送到队列吗?

正如他在评论中提到的4c74356b41,我们可以通过this REST API向Azure Service Bus队列发送消息:

POST http{s}://{serviceNamespace}.servicebus.windows.net/{queuePath|topicPath}/messages

这是一个例子

enter image description here

在上述请求中,我提供了共享访问签名(令牌),以生成共享访问签名(令牌),请参阅this article

答案 2 :(得分:0)

感谢Fred的回答,我已经扩展到包括如何发布签名认证标题。

public class AzureServiceBusSettings
{
    public string BaseUrl { get; set; }
    public string SharedAccessKey { get; set; }
    public string SharedAccessKeyName { get; set; }
}

public interface IServiceBus
{
    /// <summary>
    /// Publish domain events to domain topic.
    /// </summary>
    Task PublishAsync<T>(T @event)

    /// <summary>
    /// Send commands to command queue.
    /// </summary>
    Task SendAsync<T>(T command)
}

public class ServiceBus : IServiceBus
{
    private readonly AzureServiceBusSettings _settings;

    public ServiceBus(IOptions<AzureServiceBusSettings> azureServiceBusSettings)
    {
        _settings = azureServiceBusSettings.Value;
    }

    /// <summary>
    /// Publish domain events to domain topic.
    /// </summary>
    public async Task PublishAsync<T>(T @event)
    {
        await SendInternalAsync(@event, "domain");
    }

    /// <summary>
    /// Send commands to command queue.
    /// </summary>
    public async Task SendAsync<T>(T command)
    {
        await SendInternalAsync(command, "commands");
    }

    private async Task SendInternalAsync<T>(T command, string queueName)
    {
        var json = JsonConvert.SerializeObject(command);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        using (var httpClient = new HttpClient())
        {
            httpClient.BaseAddress = new Uri(_settings.BaseUrl);

            try
            {
                var url = $"/{queueName}/messages";

                httpClient.DefaultRequestHeaders.Authorization =
                    new AuthenticationHeaderValue("SharedAccessSignature", GetSasToken(queueName));

                var response = await httpClient.PostAsync(url, content);

                // Success returns 201 Created.
                if (!response.IsSuccessStatusCode)
                {
                    // Handle this.
                }
            }
            catch (Exception ex)
            {
                // Handle this.
                // throw;
            }
        }
    }

    private string GetSasToken(string queueName)
    {
        var url = $"{_settings.BaseUrl}/{queueName}";
        // Expiry minutes should be a setting.
        var expiry = (int)DateTime.UtcNow.AddMinutes(20).Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
        var signature = GetSignature(url, _settings.SharedAccessKey);
        var token = $"sr={WebUtility.UrlEncode(url)}&sig={WebUtility.UrlEncode(signature)}&se={expiry}&skn={_settings.SharedAccessKeyName}";
        return token;
    }

    private static string GetSignature(string url, string key)
    {
        var expiry = (int)DateTime.UtcNow.AddMinutes(20).Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
        var value = WebUtility.UrlEncode(url) + "\n" + expiry;
        var encoding = new UTF8Encoding();
        var keyByte = encoding.GetBytes(key);
        var valueBytes = encoding.GetBytes(value);
        using (var hmacsha256 = new HMACSHA256(keyByte))
        {
            var hashmessage = hmacsha256.ComputeHash(valueBytes);
            var result = Convert.ToBase64String(hashmessage);
            return result;
        }
    }
}

一个简单的xunit测试发布:

public class ServiceBusTests
{
    public class FooCommand : ICommand
    {
        public Guid CommandId { get; set; }
    }

    private Mock<IOptions<AzureServiceBusSettings>> _mockAzureServiceBusOptions;

    private ServiceBus _sut;

    public ServiceBusTests()
    {
        var settings = new AzureServiceBusSettings
        {
            BaseUrl = "https://my-domain.servicebus.windows.net",
            SharedAccessKey = "my-key-goes-here",
            SharedAccessKeyName = "RootManageSharedAccessKey"
        };

        _mockAzureServiceBusOptions = new Mock<IOptions<AzureServiceBusSettings>>();
        _mockAzureServiceBusOptions.SetupGet(o => o.Value).Returns(settings);

        _sut = new ServiceBus(
            _mockAzureServiceBusOptions.Object);
    }

    [Fact]
    public async Task should_send_message()
    {
        // Arrange.
        var command = new FooCommand {CommandId = Guid.NewGuid()};

        // Act.
        await _sut.SendAsync(command);

        // Assert.
        // TODO: Get the command from the queue and assert something.
    }
}