通过 HTTP 添加 Azure 服务总线规则
Add Azure Service Bus Rules via HTTP
我正在更改我的代码从 Azure 服务总线订阅接收消息的方式。
之前我使用的是 SDK 类,现在我正在更改为 http REST 调用。
为了创建订阅规则并为此规则设置过滤器,我总是收到 http 400 作为 return。
看来我创建 body 的方式不正确:
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());
我还设置了以下headers:
_httpClient.DefaultRequestHeaders.Add("Authorization", _token);
_httpClient.DefaultRequestHeaders.Add("ContentType", "application/atom+xml");
_httpClient.DefaultRequestHeaders.Add("Accept", "application/atom+xml");
对缺少的东西有什么想法吗?
根据错误信息来看是请求参数错误。我不熟悉提到的api,如果可能的话,你可以分享link。
但我建议您可以使用 Rules - Create Or Update. It is easy for us to use. For more information about service bus api, please refer to this document。
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, secret key的获取方法请参考tutorial。并且不要忘记为应用程序分配角色。
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;
}
测试结果
更新:
It seems the way I am creating the body is not correct:
是的,你是对的。根据你提到的 API document,我们可以知道 body 是 xml 格式。但是你的xml代码串不是xml格式,你可以用xml在线验证器验证。字符 <
/>
和标签之间不应有 space。例如 < Filter i: type = ""SqlFilter"">
应该是 <Filter i: type = ""SqlFilter"">
但这是一个经典的休息api。
We’re no longer updating this content regularly. Check the Microsoft Product Lifecycle for information about how this product, service, technology, or API is supported.
我建议您可以使用 Azure 管理 API,我们也可以使用 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,我也做个demo。请尝试使用以下代码。
1.Get 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.Create 一个带有 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;
测试结果:
我正在更改我的代码从 Azure 服务总线订阅接收消息的方式。
之前我使用的是 SDK 类,现在我正在更改为 http REST 调用。
为了创建订阅规则并为此规则设置过滤器,我总是收到 http 400 作为 return。
看来我创建 body 的方式不正确:
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());
我还设置了以下headers:
_httpClient.DefaultRequestHeaders.Add("Authorization", _token);
_httpClient.DefaultRequestHeaders.Add("ContentType", "application/atom+xml");
_httpClient.DefaultRequestHeaders.Add("Accept", "application/atom+xml");
对缺少的东西有什么想法吗?
根据错误信息来看是请求参数错误。我不熟悉提到的api,如果可能的话,你可以分享link。
但我建议您可以使用 Rules - Create Or Update. It is easy for us to use. For more information about service bus api, please refer to this document。
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, secret key的获取方法请参考tutorial。并且不要忘记为应用程序分配角色。
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;
}
测试结果
更新:
It seems the way I am creating the body is not correct:
是的,你是对的。根据你提到的 API document,我们可以知道 body 是 xml 格式。但是你的xml代码串不是xml格式,你可以用xml在线验证器验证。字符 <
/>
和标签之间不应有 space。例如 < Filter i: type = ""SqlFilter"">
应该是 <Filter i: type = ""SqlFilter"">
但这是一个经典的休息api。
We’re no longer updating this content regularly. Check the Microsoft Product Lifecycle for information about how this product, service, technology, or API is supported.
我建议您可以使用 Azure 管理 API,我们也可以使用 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,我也做个demo。请尝试使用以下代码。
1.Get 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.Create 一个带有 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;
测试结果: