C# 通过HTTP添加Azure服务总线规则

C# 通过HTTP添加Azure服务总线规则,c#,rest,azure,nservicebus,C#,Rest,Azure,Nservicebus,我正在更改代码从Azure服务总线订阅接收消息的方式 以前我使用SDK类,现在我改为http REST调用 为了为订阅创建规则并在此规则上设置筛选器,我总是接收http 400作为返回 我创造身体的方式似乎不正确: var rule = $"https://{serviceBusNamespace}.servicebus.windows.net/{topicPath}/subscriptions/{subscriptionName}/rules/{ruleName}";

我正在更改代码从Azure服务总线订阅接收消息的方式

以前我使用SDK类,现在我改为http REST调用

为了为订阅创建规则并在此规则上设置筛选器,我总是接收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());

关于缺少什么有什么想法吗?

根据错误信息,这意味着请求参数出错。我不熟悉上面提到的api,如果可能的话,你可以分享这个链接

但是我建议你可以用这个。它对我们来说很容易使用。有关服务总线api的更多信息,请参阅此

我还为它做了一个演示

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;
        }
测试结果

更新

我创造身体的方式似乎不正确:

            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());
是的,你说得对。根据您提到的,我们可以知道主体是xml格式的。但您的xml代码字符串不是xml格式,您可以在线使用xml验证程序。字符
和标记之间应该没有空格。例如
应该是

但它是一个经典的RESTAPI

我们不再定期更新此内容。有关如何支持此产品、服务、技术或API的信息,请查看Microsoft产品生命周期

我建议您可以使用Azure管理API,我们也可以使用获取访问令牌

如果你还想使用,我也会做一个演示。请尝试使用以下代码

1.获取令牌代码

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=“订阅名称”;
var ruleName=“testrule2”;//规则名称
var sharedAccessKeyName=“xxxSharedAccessKey”,
var key=“xxxxxx m2xf8utrcphtby=”;
var queueUrl=$“https://{serviceBusNamespace}.servicebus.windows.net/{topicPath}/subscriptions/{subscriptionName}/rules/{ruleName}”;
var token=GetSasToken(queueUrl,sharedAccessKeyName,key,TimeSpan.FromDays(1));
变量body=@“
类型='REPLY'和用户名='REPLY'blabla@contoso.com' 
";
var length=body.length.ToString();
var content=新的StringContent(body,Encoding.UTF8,“application/xml”);
varu httpClient=新的httpClient();
_httpClient.DefaultRequestHeaders.Add(“授权”,令牌);
_httpClient.DefaultRequestHeaders.Add(“ContentType”、“application/atom+xml”);
_httpClient.DefaultRequestHeaders.Add(“Accept”、“application/atom+xml”);
添加(“内容长度”,长度);
var requestResponse=_httpClient.PutAsync(queueUrl,content,new System.Threading.CancellationToken()).Result;
测试结果:


示例代码不适用于我。为了创建访问令牌,我需要一些.NET 4.0(我的目标.NET framework版本)不支持的类库。我正在使用的API可以在我创建令牌时找到,并且已经用于执行一些与服务总线相关的操作,如发送和接收消息。我现在的问题是设置SQL筛选器。我尝试使用的API包含有关如何创建新规则的信息。使用is:请求主体应该这样创建:我相信我的问题是创建主体请求。
我相信我的问题是创建主体请求。
。是的,你是对的。xml的正文字符串格式不正确。我用演示xml字符串更新答案。我还添加了不使用.net库获取访问令牌的方法。我看到您使用的是经典API。我建议您可以使用。您有关于此SO线程的任何更新吗?如果有用,请将其标记为答案。嗨。我还在努力。很快我会给出更多更新/标记作为答案。谢谢。如果对此有任何疑问,请让我知道。问题是我仍然使用经典的API方法,所以我有一些稳定的东西,可以考虑在下一次改进中使用管理API。目前,我一直使用规则的SqlFilter,无论我做什么,我都会收到所有消息,我应该只收到符合筛选条件的消息……规则筛选器的问题实际上不是问题。根据此线程(),当您创建订阅时,将自动创建一个“接受所有内容”的过滤器。所以我所要做的就是在订阅创建之后删除它。
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;
 }
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();
        }
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);
 }
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;