Добавить правила служебной шины Azure через HTTP - PullRequest
0 голосов
/ 12 сентября 2018

Я меняю способ, которым мой код получает сообщения из подписки служебной шины Azure.

Раньше я использовал классы SDK, а теперь перехожу на вызовы REST http.

Чтобы создать правило для подписки и установить фильтр для этого правила, я всегда получаю http 400 в качестве возврата.

Кажется, способ, которым я создаю тело, неверен:

            var rule = $"https://{serviceBusNamespace}.servicebus.windows.net/{topicPath}/subscriptions/{subscriptionName}/rules/{ruleName}";

            var content = new StringContent(@"<RuleDescription xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"" xmlns=""http://schemas.microsoft.com/netservices/2010/10/servicebus/connect"">
             < Filter i: type = ""SqlFilter"" >
              < SqlExpression > type = 'REPLY' AND username = 'blabla@contoso.com' </ SqlExpression >
             </ Filter >
            </ RuleDescription >
            ", Encoding.UTF8, "application/xml");

            var requestResponse = await _httpClient.PutAsync(rule, content, new System.Threading.CancellationToken());

Я также устанавливаю следующие заголовки:

_httpClient.DefaultRequestHeaders.Add("Authorization", _token);
                _httpClient.DefaultRequestHeaders.Add("ContentType", "application/atom+xml");
                _httpClient.DefaultRequestHeaders.Add("Accept", "application/atom+xml");

Есть идеи о том, чего не хватает?

1 Ответ

0 голосов
/ 13 сентября 2018

Согласно информации об ошибке это означает, что параметры запроса ошибочны.Я не знаком с упомянутым API, вы можете поделиться ссылкой, если это возможно.

Но я рекомендую вам использовать Правила - Создать или обновить .Нам легко пользоваться.Для получения дополнительной информации о сервисной шине API, пожалуйста, обратитесь к этому документу .

PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ServiceBus/namespaces/{namespaceName}/topics/{topicName}/subscriptions/{subscriptionName}/rules/{ruleName}?api-version=2017-04-01

Я также делаю демонстрацию для него.

1) Получите токен доступа

private static async Task<string> GetToken(string tenantId, string clientId, string secretKey)
        {
            var context = new AuthenticationContext("https://login.windows.net/" + tenantId);
            ClientCredential clientCredential = new ClientCredential(clientId, secretKey);
            var tokenResponse = await context.AcquireTokenAsync("https://management.azure.com/", clientCredential);
            var accessToken = tokenResponse.AccessToken;
            return accessToken;
        }

2) О том, как получить tenantId, clientId и секретный ключ, см. В этом руководстве .И не забудьте назначить на роль приложения.

var tenantId = "tenantId";
var clientId = "clientId";
var secretkey = "sercret Key";
var subscriptionId = "subscription Id";
var resurceGroup = "resourceGroup";
var nameSpace = "servicebus namespace";
var topicName = "topicName";
var subscription = "service subscription name";
var ruleName = "rule name";
var token = GetToken(tenantId,clientId,secretkey).Result;
using (var httpClient = new HttpClient())
{
   httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
   httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json"));
   var body = "{\"properties\": { \"filterType\": \"SqlFilter\"},\"sqlExpression\": { \"sqlExpression\": \"myproperty=test\"}}";
   HttpContent content = new StringContent(body);
   var url = $"https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resurceGroup}/providers/Microsoft.ServiceBus/namespaces/{nameSpace}/topics/{topicName}/subscriptions/{subscription}/rules/{ruleName}?api-version=2017-04-01";
   var response = httpClient.PutAsync(url, content).Result;
 }

Результат теста

enter image description here

Обновление :

Кажется, способ, которым я создаю тело, неправильный:

Да, вы правы.Согласно вашему упомянутому API-документу , мы могли бы знать, что тело имеет формат xml.Но у вас строка кода xml не в формате xml, вы можете использовать xml validator онлайн.Между символами < / > и тегами не должно быть пробела.Например, < Filter i: type = ""SqlFilter""> должно быть <Filter i: type = ""SqlFilter"">

Но это классический отдых API.

Мы больше не обновляем этот контент регулярно.Обратитесь к Microsoft Product Lifecycle за информацией о том, как этот продукт, услуга, технология или API поддерживаются.

Я рекомендую вам использовать API управления Azure, мы также можем получить токен доступа с api .

public static string GenerateAccessToken(string resource, string tenantId, string clientId,string secretKey)
        {
            var url = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
            var body = $"grant_type=client_credentials&client_id={clientId}&client_secret={secretKey}&resource={resource}";
            HttpClient client = new HttpClient
            {
                BaseAddress = new Uri(url)
            };
            StringContent content = new StringContent(body);
            content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
            var result = client.PostAsync(url, content).Result;
            var json = JObject.Parse (result.Content.ReadAsStringAsync().Result);
            return json["access_token"].ToString();
        }

Если вы все еще хотите использовать classic api , я также делаю демонстрацию.пожалуйста, попробуйте следующий код:

1. Получите код sastoken

public static string GetSasToken(string resourceUri, string keyName, string key, TimeSpan ttl)
  {
         var expiry = GetExpiry(ttl);
         string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
         HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
         var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
         var sasToken = string.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
         HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
         return sasToken;
 }

private static string GetExpiry(TimeSpan ttl)
{
  TimeSpan expirySinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1) + ttl;
   return Convert.ToString((int)expirySinceEpoch.TotalSeconds);
 }

2. Создайте правило с помощью кода c #.

var serviceBusNamespace = "serviceBusNameSpace";
var topicPath = "topicPath";
var subscriptionName = "subscription name";
var ruleName = "testrule2"; // rule name
var sharedAccessKeyName = "xxxSharedAccessKey",
var key = "xxxxxxM2Xf8uTRcphtbY=";
var queueUrl = $"https://{serviceBusNamespace}.servicebus.windows.net/{topicPath}/subscriptions/{subscriptionName}/rules/{ruleName}";
var token = GetSasToken(queueUrl, sharedAccessKeyName,key ,TimeSpan.FromDays(1));
            var body = @"<entry xmlns=""http://www.w3.org/2005/Atom"">
   <content type =""application/xml"" >
   <RuleDescription xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"" xmlns=""http://schemas.microsoft.com/netservices/2010/10/servicebus/connect"">
           <Filter i:type=""SqlFilter"">
               <SqlExpression> type = 'REPLY' AND username = 'blabla@contoso.com' </SqlExpression>
             </Filter>
           </RuleDescription>
         </content>
       </entry>";
            var length = body.Length.ToString();
            var content = new StringContent(body, Encoding.UTF8, "application/xml");
            var _httpClient = new HttpClient();
            _httpClient.DefaultRequestHeaders.Add("Authorization", token);
            _httpClient.DefaultRequestHeaders.Add("ContentType", "application/atom+xml");
            _httpClient.DefaultRequestHeaders.Add("Accept", "application/atom+xml");
            content.Headers.Add("Content-Length", length);
            var requestResponse =  _httpClient.PutAsync(queueUrl, content, new System.Threading.CancellationToken()).Result;

TestРезультат:

enter image description here

...