| | 1 | | // Copyright (c) Microsoft. All rights reserved. |
| | 2 | | // Licensed under the MIT license. See LICENSE file in the project root for full license information. |
| | 3 | |
|
| | 4 | | namespace Microsoft.Azure.ServiceBus.Management |
| | 5 | | { |
| | 6 | | using System; |
| | 7 | | using System.Collections.Generic; |
| | 8 | | using System.Net; |
| | 9 | | using System.Net.Http; |
| | 10 | | using System.Text; |
| | 11 | | using System.Threading; |
| | 12 | | using System.Threading.Tasks; |
| | 13 | | using System.Xml.Linq; |
| | 14 | | using Microsoft.Azure.ServiceBus.Primitives; |
| | 15 | |
|
| | 16 | | public class ManagementClient |
| | 17 | | { |
| | 18 | | private HttpClient httpClient; |
| | 19 | | private readonly string endpointFQDN; |
| | 20 | | private readonly ITokenProvider tokenProvider; |
| | 21 | | private readonly int port; |
| | 22 | | private readonly string clientId; |
| | 23 | |
|
| | 24 | | /// <summary> |
| | 25 | | /// Initializes a new <see cref="ManagementClient"/> which can be used to perform management opertions on Servic |
| | 26 | | /// </summary> |
| | 27 | | /// <param name="connectionString">Namespace connection string.</param> |
| | 28 | | public ManagementClient(string connectionString) |
| 0 | 29 | | : this(new ServiceBusConnectionStringBuilder(connectionString)) |
| | 30 | | { |
| 0 | 31 | | } |
| | 32 | |
|
| | 33 | | /// <summary> |
| | 34 | | /// Initializes a new <see cref="ManagementClient"/> which can be used to perform management opertions on Servic |
| | 35 | | /// </summary> |
| | 36 | | /// <param name="endpoint">Fully qualified domain name for Service Bus. Most likely, {yournamespace}.servicebus. |
| | 37 | | /// <param name="tokenProvider">Token provider which will generate security tokens for authorization.</param> |
| | 38 | | public ManagementClient(string endpoint, ITokenProvider tokenProvider) |
| 0 | 39 | | : this(new ServiceBusConnectionStringBuilder {Endpoint = endpoint}, tokenProvider) |
| | 40 | | { |
| 0 | 41 | | } |
| | 42 | |
|
| | 43 | | /// <summary> |
| | 44 | | /// Initializes a new <see cref="ManagementClient"/> which can be used to perform management opertions on Servic |
| | 45 | | /// </summary> |
| | 46 | | /// <param name="connectionStringBuilder"><see cref="ServiceBusConnectionStringBuilder"/> having endpoint inform |
| | 47 | | /// <param name="tokenProvider">Token provider which will generate security tokens for authorization.</param> |
| 12 | 48 | | public ManagementClient(ServiceBusConnectionStringBuilder connectionStringBuilder, ITokenProvider tokenProvider |
| | 49 | | { |
| 12 | 50 | | this.httpClient = new HttpClient { Timeout = connectionStringBuilder.OperationTimeout }; |
| 12 | 51 | | this.endpointFQDN = connectionStringBuilder.Endpoint; |
| 12 | 52 | | this.tokenProvider = tokenProvider ?? CreateTokenProvider(connectionStringBuilder); |
| 6 | 53 | | this.port = GetPort(connectionStringBuilder.Endpoint); |
| 6 | 54 | | this.clientId = nameof(ManagementClient) + Guid.NewGuid().ToString("N").Substring(0, 6); |
| | 55 | |
|
| 6 | 56 | | MessagingEventSource.Log.ManagementClientCreated(this.clientId, this.httpClient.Timeout.TotalSeconds, this.t |
| 6 | 57 | | } |
| | 58 | |
|
| | 59 | | public static HttpRequestMessage CloneRequest(HttpRequestMessage req) |
| | 60 | | { |
| 0 | 61 | | HttpRequestMessage clone = new HttpRequestMessage(req.Method, req.RequestUri); |
| | 62 | |
|
| 0 | 63 | | clone.Content = req.Content; |
| 0 | 64 | | clone.Version = req.Version; |
| | 65 | |
|
| 0 | 66 | | foreach (KeyValuePair<string, object> prop in req.Properties) |
| | 67 | | { |
| 0 | 68 | | clone.Properties.Add(prop); |
| | 69 | | } |
| | 70 | |
|
| 0 | 71 | | foreach (KeyValuePair<string, IEnumerable<string>> header in req.Headers) |
| | 72 | | { |
| 0 | 73 | | clone.Headers.TryAddWithoutValidation(header.Key, header.Value); |
| | 74 | | } |
| | 75 | |
|
| 0 | 76 | | return clone; |
| | 77 | | } |
| | 78 | |
|
| | 79 | | /// <summary> |
| | 80 | | /// Gets information related to the currently used namespace. |
| | 81 | | /// </summary> |
| | 82 | | /// <param name="cancellationToken"></param> |
| | 83 | | /// <returns><see cref="NamespaceInfo"/> containing namespace information.</returns> |
| | 84 | | /// <remarks>Works with any claim (Send/Listen/Manage).</remarks> |
| | 85 | | public virtual async Task<NamespaceInfo> GetNamespaceInfoAsync(CancellationToken cancellationToken = default) |
| | 86 | | { |
| 0 | 87 | | var content = await GetEntity("$namespaceinfo", null, false, cancellationToken).ConfigureAwait(false); |
| 0 | 88 | | return NamespaceInfoExtensions.ParseFromContent(content); |
| 0 | 89 | | } |
| | 90 | |
|
| | 91 | | #region DeleteEntity |
| | 92 | |
|
| | 93 | | /// <summary> |
| | 94 | | /// Deletes the queue described by the path relative to the service namespace base address. |
| | 95 | | /// </summary> |
| | 96 | | /// <param name="queuePath">The name of the queue relative to the service namespace base address.</param> |
| | 97 | | /// <param name="cancellationToken"></param> |
| | 98 | | /// <exception cref="ArgumentException"><paramref name="queuePath"/> is empty or null, or path starts or ends wi |
| | 99 | | /// <exception cref="ArgumentOutOfRangeException">The length of path is greater than 260.</exception> |
| | 100 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 101 | | /// <exception cref="MessagingEntityNotFoundException">Queue with this name does not exist.</exception> |
| | 102 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 103 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 104 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 105 | | public virtual Task DeleteQueueAsync(string queuePath, CancellationToken cancellationToken = default) |
| | 106 | | { |
| 0 | 107 | | EntityNameHelper.CheckValidQueueName(queuePath); |
| 0 | 108 | | return DeleteEntity(queuePath, cancellationToken); |
| | 109 | | } |
| | 110 | |
|
| | 111 | | /// <summary> |
| | 112 | | /// Deletes the topic described by the name relative to the service namespace base address. |
| | 113 | | /// </summary> |
| | 114 | | /// <param name="topicPath">The name of the topic relative to the service namespace base address.</param> |
| | 115 | | /// <param name="cancellationToken"></param> |
| | 116 | | /// <exception cref="ArgumentException"><paramref name="topicPath"/> is empty or null, or path starts or ends wi |
| | 117 | | /// <exception cref="ArgumentOutOfRangeException">The length of topic path is greater than 260.</exception> |
| | 118 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 119 | | /// <exception cref="MessagingEntityNotFoundException">Topic with this name does not exist.</exception> |
| | 120 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 121 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 122 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 123 | | public virtual Task DeleteTopicAsync(string topicPath, CancellationToken cancellationToken = default) |
| | 124 | | { |
| 0 | 125 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 126 | | return DeleteEntity(topicPath, cancellationToken); |
| | 127 | | } |
| | 128 | |
|
| | 129 | | /// <summary> |
| | 130 | | /// Deletes the subscription with the specified topic and subscription name. |
| | 131 | | /// </summary> |
| | 132 | | /// <param name="topicPath">The name of the topic relative to the service namespace base address.</param> |
| | 133 | | /// <param name="subscriptionName">The name of the subscription to delete.</param> |
| | 134 | | /// <param name="cancellationToken"></param> |
| | 135 | | /// <exception cref="ArgumentException"><paramref name="topicPath"/> or <paramref name="subscriptionName"/> is e |
| | 136 | | /// <exception cref="ArgumentOutOfRangeException">The length of topic path is greater than 260 or length of subs |
| | 137 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 138 | | /// <exception cref="MessagingEntityNotFoundException">Subscription with this name does not exist.</exception> |
| | 139 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 140 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 141 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 142 | | public virtual Task DeleteSubscriptionAsync(string topicPath, string subscriptionName, CancellationToken cancell |
| | 143 | | { |
| 0 | 144 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 145 | | EntityNameHelper.CheckValidSubscriptionName(subscriptionName); |
| | 146 | |
|
| 0 | 147 | | return DeleteEntity(EntityNameHelper.FormatSubscriptionPath(topicPath, subscriptionName), cancellationToken) |
| | 148 | | } |
| | 149 | |
|
| | 150 | | /// <summary> |
| | 151 | | /// Deletes the rule described by <paramref name="ruleName"/> from <paramref name="subscriptionName"/> under <pa |
| | 152 | | /// </summary> |
| | 153 | | /// <param name="topicPath">The name of the topic relative to the service namespace base address.</param> |
| | 154 | | /// <param name="subscriptionName">The name of the subscription to delete.</param> |
| | 155 | | /// <param name="ruleName">The name of the rule to delete.</param> |
| | 156 | | /// <param name="cancellationToken"></param> |
| | 157 | | /// <exception cref="ArgumentException">Thrown if <paramref name="topicPath"/>, <paramref name="subscriptionName |
| | 158 | | /// <exception cref="ArgumentOutOfRangeException">The length of topic path is greater than 260 or length of subs |
| | 159 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 160 | | /// <exception cref="MessagingEntityNotFoundException">Rule with this name does not exist.</exception> |
| | 161 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 162 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 163 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 164 | | public virtual Task DeleteRuleAsync(string topicPath, string subscriptionName, string ruleName, CancellationToke |
| | 165 | | { |
| 0 | 166 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 167 | | EntityNameHelper.CheckValidSubscriptionName(subscriptionName); |
| 0 | 168 | | EntityNameHelper.CheckValidRuleName(ruleName); |
| | 169 | |
|
| 0 | 170 | | return DeleteEntity(EntityNameHelper.FormatRulePath(topicPath, subscriptionName, ruleName), cancellationToke |
| | 171 | | } |
| | 172 | |
|
| | 173 | | #endregion |
| | 174 | |
|
| | 175 | | #region GetEntity |
| | 176 | |
|
| | 177 | | /// <summary> |
| | 178 | | /// Retrieves a queue from the service namespace. |
| | 179 | | /// </summary> |
| | 180 | | /// <param name="queuePath">The path of the queue relative to service bus namespace.</param> |
| | 181 | | /// <param name="cancellationToken"></param> |
| | 182 | | /// <returns><see cref="QueueDescription"/> containing information about the queue.</returns> |
| | 183 | | /// <exception cref="ArgumentException">Thrown if <paramref name="queuePath"/> is null, white space empty or not |
| | 184 | | /// <exception cref="ArgumentOutOfRangeException">The length of queue path is greater than 260.</exception> |
| | 185 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 186 | | /// <exception cref="MessagingEntityNotFoundException">Queue with this name does not exist.</exception> |
| | 187 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 188 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 189 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 190 | | public virtual async Task<QueueDescription> GetQueueAsync(string queuePath, CancellationToken cancellationToken |
| | 191 | | { |
| 0 | 192 | | EntityNameHelper.CheckValidQueueName(queuePath); |
| | 193 | |
|
| 0 | 194 | | var content = await GetEntity(queuePath, null, false, cancellationToken).ConfigureAwait(false); |
| | 195 | |
|
| 0 | 196 | | return QueueDescriptionExtensions.ParseFromContent(content); |
| 0 | 197 | | } |
| | 198 | |
|
| | 199 | | /// <summary> |
| | 200 | | /// Retrieves a topic from the service namespace. |
| | 201 | | /// </summary> |
| | 202 | | /// <param name="topicPath">The path of the topic relative to service bus namespace.</param> |
| | 203 | | /// <param name="cancellationToken"></param> |
| | 204 | | /// <returns><see cref="TopicDescription"/> containing information about the topic.</returns> |
| | 205 | | /// <exception cref="ArgumentException">Thrown if <paramref name="topicPath"/> is null, white space empty or not |
| | 206 | | /// <exception cref="ArgumentOutOfRangeException">The length of topic path is greater than 260.</exception> |
| | 207 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 208 | | /// <exception cref="MessagingEntityNotFoundException">Topic with this name does not exist.</exception> |
| | 209 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 210 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 211 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 212 | | public virtual async Task<TopicDescription> GetTopicAsync(string topicPath, CancellationToken cancellationToken |
| | 213 | | { |
| 0 | 214 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| | 215 | |
|
| 0 | 216 | | var content = await GetEntity(topicPath, null, false, cancellationToken).ConfigureAwait(false); |
| | 217 | |
|
| 0 | 218 | | return TopicDescriptionExtensions.ParseFromContent(content); |
| 0 | 219 | | } |
| | 220 | |
|
| | 221 | | /// <summary> |
| | 222 | | /// Retrieves a subscription from the service namespace. |
| | 223 | | /// </summary> |
| | 224 | | /// <param name="topicPath">The path of the topic relative to service bus namespace.</param> |
| | 225 | | /// <param name="subscriptionName">The subscription name.</param> |
| | 226 | | /// <param name="cancellationToken"></param> |
| | 227 | | /// <returns><see cref="SubscriptionDescription"/> containing information about the subscription.</returns> |
| | 228 | | /// <exception cref="ArgumentException">Thrown if <paramref name="topicPath"/>, <paramref name="subscriptionName |
| | 229 | | /// <exception cref="ArgumentOutOfRangeException">The length of topic path is greater than 260 or length of subs |
| | 230 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 231 | | /// <exception cref="MessagingEntityNotFoundException">Topic or Subscription with this name does not exist.</exc |
| | 232 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 233 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 234 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 235 | | public virtual async Task<SubscriptionDescription> GetSubscriptionAsync(string topicPath, string subscriptionNam |
| | 236 | | { |
| 0 | 237 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 238 | | EntityNameHelper.CheckValidSubscriptionName(subscriptionName); |
| | 239 | |
|
| 0 | 240 | | var content = await GetEntity(EntityNameHelper.FormatSubscriptionPath(topicPath, subscriptionName), null, fa |
| | 241 | |
|
| 0 | 242 | | return SubscriptionDescriptionExtensions.ParseFromContent(topicPath, content); |
| 0 | 243 | | } |
| | 244 | |
|
| | 245 | | /// <summary> |
| | 246 | | /// Retrieves a rule from the service namespace. |
| | 247 | | /// </summary> |
| | 248 | | /// <param name="topicPath">The path of the topic relative to service bus namespace.</param> |
| | 249 | | /// <param name="subscriptionName">The subscription name the rule belongs to.</param> |
| | 250 | | /// <param name="ruleName">The name of the rule to retrieve.</param> |
| | 251 | | /// <param name="cancellationToken"></param> |
| | 252 | | /// <returns><see cref="RuleDescription"/> containing information about the rule.</returns> |
| | 253 | | /// <exception cref="ArgumentException">Thrown if <paramref name="topicPath"/>, <paramref name="subscriptionName |
| | 254 | | /// <exception cref="ArgumentOutOfRangeException">The length of topic path is greater than 260 or length of subs |
| | 255 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 256 | | /// <exception cref="MessagingEntityNotFoundException">Topic/Subscription/Rule with this name does not exist.</e |
| | 257 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 258 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 259 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 260 | | /// <remarks>Note - Only following data types are deserialized in Filters and Action parameters - string,int,lon |
| | 261 | | /// Other data types would return its string value.</remarks> |
| | 262 | | public virtual async Task<RuleDescription> GetRuleAsync(string topicPath, string subscriptionName, string ruleNa |
| | 263 | | { |
| 0 | 264 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 265 | | EntityNameHelper.CheckValidSubscriptionName(subscriptionName); |
| 0 | 266 | | EntityNameHelper.CheckValidRuleName(ruleName); |
| | 267 | |
|
| 0 | 268 | | var content = await GetEntity(EntityNameHelper.FormatRulePath(topicPath, subscriptionName, ruleName), null, |
| | 269 | |
|
| 0 | 270 | | return RuleDescriptionExtensions.ParseFromContent(content); |
| 0 | 271 | | } |
| | 272 | |
|
| | 273 | | #endregion |
| | 274 | |
|
| | 275 | | #region GetRuntimeInfo |
| | 276 | | /// <summary> |
| | 277 | | /// Retrieves the runtime information of a queue. |
| | 278 | | /// </summary> |
| | 279 | | /// <param name="queuePath">The path of the queue relative to service bus namespace.</param> |
| | 280 | | /// <param name="cancellationToken"></param> |
| | 281 | | /// <returns><see cref="QueueRuntimeInfo"/> containing runtime information about the queue.</returns> |
| | 282 | | /// <exception cref="ArgumentException">Thrown if <paramref name="queuePath"/> is null, white space empty or not |
| | 283 | | /// <exception cref="ArgumentOutOfRangeException">The length of queue path is greater than 260.</exception> |
| | 284 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 285 | | /// <exception cref="MessagingEntityNotFoundException">Queue with this name does not exist.</exception> |
| | 286 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 287 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 288 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 289 | | public virtual async Task<QueueRuntimeInfo> GetQueueRuntimeInfoAsync(string queuePath, CancellationToken cancell |
| | 290 | | { |
| 0 | 291 | | EntityNameHelper.CheckValidQueueName(queuePath); |
| | 292 | |
|
| 0 | 293 | | var content = await GetEntity(queuePath, null, true, cancellationToken).ConfigureAwait(false); |
| | 294 | |
|
| 0 | 295 | | return QueueRuntimeInfoExtensions.ParseFromContent(content); |
| 0 | 296 | | } |
| | 297 | |
|
| | 298 | | /// <summary> |
| | 299 | | /// Retrieves the runtime information of a topic. |
| | 300 | | /// </summary> |
| | 301 | | /// <param name="topicPath">The path of the topic relative to service bus namespace.</param> |
| | 302 | | /// <param name="cancellationToken"></param> |
| | 303 | | /// <returns><see cref="TopicRuntimeInfo"/> containing runtime information about the topic.</returns> |
| | 304 | | /// <exception cref="ArgumentException">Thrown if <paramref name="topicPath"/> is null, white space empty or not |
| | 305 | | /// <exception cref="ArgumentOutOfRangeException">The length of topic path is greater than 260.</exception> |
| | 306 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 307 | | /// <exception cref="MessagingEntityNotFoundException">Topic with this name does not exist.</exception> |
| | 308 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 309 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 310 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 311 | | public virtual async Task<TopicRuntimeInfo> GetTopicRuntimeInfoAsync(string topicPath, CancellationToken cancell |
| | 312 | | { |
| 0 | 313 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| | 314 | |
|
| 0 | 315 | | var content = await GetEntity(topicPath, null, true, cancellationToken).ConfigureAwait(false); |
| | 316 | |
|
| 0 | 317 | | return TopicRuntimeInfoExtensions.ParseFromContent(content); |
| 0 | 318 | | } |
| | 319 | |
|
| | 320 | | /// <summary> |
| | 321 | | /// Retrieves the runtime information of a subscription. |
| | 322 | | /// </summary> |
| | 323 | | /// <param name="topicPath">The path of the topic relative to service bus namespace.</param> |
| | 324 | | /// <param name="subscriptionName">The subscription name.</param> |
| | 325 | | /// <param name="cancellationToken"></param> |
| | 326 | | /// <returns><see cref="SubscriptionRuntimeInfo"/> containing runtime information about the subscription.</retur |
| | 327 | | /// <exception cref="ArgumentException">Thrown if <paramref name="topicPath"/>, <paramref name="subscriptionName |
| | 328 | | /// <exception cref="ArgumentOutOfRangeException">The length of topic path is greater than 260 or length of subs |
| | 329 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 330 | | /// <exception cref="MessagingEntityNotFoundException">Topic or Subscription with this name does not exist.</exc |
| | 331 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 332 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 333 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 334 | | public virtual async Task<SubscriptionRuntimeInfo> GetSubscriptionRuntimeInfoAsync(string topicPath, string subs |
| | 335 | | { |
| 0 | 336 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 337 | | EntityNameHelper.CheckValidSubscriptionName(subscriptionName); |
| | 338 | |
|
| 0 | 339 | | var content = await GetEntity(EntityNameHelper.FormatSubscriptionPath(topicPath, subscriptionName), null, tr |
| | 340 | |
|
| 0 | 341 | | return SubscriptionRuntimeInfoExtensions.ParseFromContent(topicPath, content); |
| 0 | 342 | | } |
| | 343 | |
|
| | 344 | | #endregion |
| | 345 | |
|
| | 346 | | #region GetEntities |
| | 347 | | /// <summary> |
| | 348 | | /// Retrieves the list of queues present in the namespace. |
| | 349 | | /// </summary> |
| | 350 | | /// <param name="count">The number of queues to fetch. Defaults to 100. Maximum value allowed is 100.</param> |
| | 351 | | /// <param name="skip">The number of queues to skip. Defaults to 0. Cannot be negative.</param> |
| | 352 | | /// <param name="cancellationToken"></param> |
| | 353 | | /// <returns><see cref="IList<QueueDescription>"/> containing list of queues.</returns> |
| | 354 | | /// <exception cref="ArgumentOutOfRangeException">If the parameters are out of range.</exception> |
| | 355 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 356 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 357 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 358 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 359 | | /// <remarks>You can simulate pages of list of entities by manipulating <paramref name="count"/> and <paramref n |
| | 360 | | /// skip(0)+count(100) gives first 100 entities. skip(100)+count(100) gives the next 100 entities.</remarks> |
| | 361 | | public virtual async Task<IList<QueueDescription>> GetQueuesAsync(int count = 100, int skip = 0, CancellationTok |
| | 362 | | { |
| 0 | 363 | | if (count > 100 || count < 1) |
| | 364 | | { |
| 0 | 365 | | throw new ArgumentOutOfRangeException(nameof(count), "Value should be between 1 and 100"); |
| | 366 | | } |
| 0 | 367 | | if (skip < 0) |
| | 368 | | { |
| 0 | 369 | | throw new ArgumentOutOfRangeException(nameof(skip), "Value cannot be negative"); |
| | 370 | | } |
| | 371 | |
|
| 0 | 372 | | var content = await GetEntity("$Resources/queues", $"$skip={skip}&$top={count}", false, cancellationToken).C |
| 0 | 373 | | return QueueDescriptionExtensions.ParseCollectionFromContent(content); |
| 0 | 374 | | } |
| | 375 | |
|
| | 376 | | /// <summary> |
| | 377 | | /// Retrieves the list of topics present in the namespace. |
| | 378 | | /// </summary> |
| | 379 | | /// <param name="count">The number of topics to fetch. Defaults to 100. Maximum value allowed is 100.</param> |
| | 380 | | /// <param name="skip">The number of topics to skip. Defaults to 0. Cannot be negative.</param> |
| | 381 | | /// <param name="cancellationToken"></param> |
| | 382 | | /// <returns><see cref="IList<TopicDescription>"/> containing list of topics.</returns> |
| | 383 | | /// <exception cref="ArgumentOutOfRangeException">If the parameters are out of range.</exception> |
| | 384 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 385 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 386 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 387 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 388 | | /// <remarks>You can simulate pages of list of entities by manipulating <paramref name="count"/> and <paramref n |
| | 389 | | /// skip(0)+count(100) gives first 100 entities. skip(100)+count(100) gives the next 100 entities.</remarks> |
| | 390 | | public virtual async Task<IList<TopicDescription>> GetTopicsAsync(int count = 100, int skip = 0, CancellationTok |
| | 391 | | { |
| 0 | 392 | | if (count > 100 || count < 1) |
| | 393 | | { |
| 0 | 394 | | throw new ArgumentOutOfRangeException(nameof(count), "Value should be between 1 and 100"); |
| | 395 | | } |
| 0 | 396 | | if (skip < 0) |
| | 397 | | { |
| 0 | 398 | | throw new ArgumentOutOfRangeException(nameof(skip), "Value cannot be negative"); |
| | 399 | | } |
| | 400 | |
|
| 0 | 401 | | var content = await GetEntity("$Resources/topics", $"$skip={skip}&$top={count}", false, cancellationToken).C |
| 0 | 402 | | return TopicDescriptionExtensions.ParseCollectionFromContent(content); |
| 0 | 403 | | } |
| | 404 | |
|
| | 405 | | /// <summary> |
| | 406 | | /// Retrieves the list of subscriptions present in the topic. |
| | 407 | | /// </summary> |
| | 408 | | /// <param name="topicPath">The topic path under which all the subscriptions need to be retrieved.</param> |
| | 409 | | /// <param name="count">The number of subscriptions to fetch. Defaults to 100. Maximum value allowed is 100.</pa |
| | 410 | | /// <param name="skip">The number of subscriptions to skip. Defaults to 0. Cannot be negative.</param> |
| | 411 | | /// <param name="cancellationToken"></param> |
| | 412 | | /// <returns><see cref="IList<SubscriptionDescription>"/> containing list of subscriptions.</returns> |
| | 413 | | /// <exception cref="ArgumentOutOfRangeException">If the parameters are out of range.</exception> |
| | 414 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 415 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 416 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 417 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 418 | | /// <remarks>You can simulate pages of list of entities by manipulating <paramref name="count"/> and <paramref n |
| | 419 | | /// skip(0)+count(100) gives first 100 entities. skip(100)+count(100) gives the next 100 entities.</remarks> |
| | 420 | | public virtual async Task<IList<SubscriptionDescription>> GetSubscriptionsAsync(string topicPath, int count = 10 |
| | 421 | | { |
| 0 | 422 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 423 | | if (count > 100 || count < 1) |
| | 424 | | { |
| 0 | 425 | | throw new ArgumentOutOfRangeException(nameof(count), "Value should be between 1 and 100"); |
| | 426 | | } |
| 0 | 427 | | if (skip < 0) |
| | 428 | | { |
| 0 | 429 | | throw new ArgumentOutOfRangeException(nameof(skip), "Value cannot be negative"); |
| | 430 | | } |
| | 431 | |
|
| 0 | 432 | | var content = await GetEntity($"{topicPath}/Subscriptions", $"$skip={skip}&$top={count}", false, cancellatio |
| 0 | 433 | | return SubscriptionDescriptionExtensions.ParseCollectionFromContent(topicPath, content); |
| 0 | 434 | | } |
| | 435 | |
|
| | 436 | | /// <summary> |
| | 437 | | /// Retrieves the list of rules for a given subscription in a topic. |
| | 438 | | /// </summary> |
| | 439 | | /// <param name="topicPath">The topic path.</param> |
| | 440 | | /// <param name="subscriptionName"> The subscription for which all the rules need to be retrieved.</param> |
| | 441 | | /// <param name="count">The number of rules to fetch. Defaults to 100. Maximum value allowed is 100.</param> |
| | 442 | | /// <param name="skip">The number of rules to skip. Defaults to 0. Cannot be negative.</param> |
| | 443 | | /// <param name="cancellationToken"></param> |
| | 444 | | /// <returns><see cref="IList<RuleDescription>"/> containing list of rules.</returns> |
| | 445 | | /// <exception cref="ArgumentOutOfRangeException">If the parameters are out of range.</exception> |
| | 446 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 447 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 448 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 449 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 450 | | /// <remarks>You can simulate pages of list of entities by manipulating <paramref name="count"/> and <paramref n |
| | 451 | | /// skip(0)+count(100) gives first 100 entities. skip(100)+count(100) gives the next 100 entities. |
| | 452 | | /// Note - Only following data types are deserialized in Filters and Action parameters - string,int,long,bool,do |
| | 453 | | /// Other data types would return its string value.</remarks> |
| | 454 | | public virtual async Task<IList<RuleDescription>> GetRulesAsync(string topicPath, string subscriptionName, int c |
| | 455 | | { |
| 0 | 456 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 457 | | EntityNameHelper.CheckValidSubscriptionName(subscriptionName); |
| 0 | 458 | | if (count > 100 || count < 1) |
| | 459 | | { |
| 0 | 460 | | throw new ArgumentOutOfRangeException(nameof(count), "Value should be between 1 and 100"); |
| | 461 | | } |
| 0 | 462 | | if (skip < 0) |
| | 463 | | { |
| 0 | 464 | | throw new ArgumentOutOfRangeException(nameof(skip), "Value cannot be negative"); |
| | 465 | | } |
| | 466 | |
|
| 0 | 467 | | var content = await GetEntity($"{topicPath}/Subscriptions/{subscriptionName}/rules", $"$skip={skip}&$top={co |
| 0 | 468 | | return RuleDescriptionExtensions.ParseCollectionFromContent(content); |
| 0 | 469 | | } |
| | 470 | |
|
| | 471 | | #endregion |
| | 472 | |
|
| | 473 | | #region GetEntitesRuntimeInfo |
| | 474 | | /// <summary> |
| | 475 | | /// Retrieves the list of runtime information for queues present in the namespace. |
| | 476 | | /// </summary> |
| | 477 | | /// <param name="count">The number of queues to fetch. Defaults to 100. Maximum value allowed is 100.</param> |
| | 478 | | /// <param name="skip">The number of queues to skip. Defaults to 0. Cannot be negative.</param> |
| | 479 | | /// <param name="cancellationToken"></param> |
| | 480 | | /// <returns><see cref="IList<QueueRuntimeInfo>"/> containing list of queue runtime information.</returns> |
| | 481 | | /// <exception cref="ArgumentOutOfRangeException">If the parameters are out of range.</exception> |
| | 482 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 483 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 484 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 485 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 486 | | /// <remarks>You can simulate pages of list of entities by manipulating <paramref name="count"/> and <paramref n |
| | 487 | | /// skip(0)+count(100) gives first 100 entities. skip(100)+count(100) gives the next 100 entities.</remarks> |
| | 488 | | public virtual async Task<IList<QueueRuntimeInfo>> GetQueuesRuntimeInfoAsync(int count = 100, int skip = 0, Canc |
| | 489 | | { |
| 0 | 490 | | if (count > 100 || count < 1) |
| | 491 | | { |
| 0 | 492 | | throw new ArgumentOutOfRangeException(nameof(count), "Value should be between 1 and 100"); |
| | 493 | | } |
| 0 | 494 | | if (skip < 0) |
| | 495 | | { |
| 0 | 496 | | throw new ArgumentOutOfRangeException(nameof(skip), "Value cannot be negative"); |
| | 497 | | } |
| | 498 | |
|
| 0 | 499 | | var content = await GetEntity("$Resources/queues", $"$skip={skip}&$top={count}", false, cancellationToken).C |
| 0 | 500 | | return QueueRuntimeInfoExtensions.ParseCollectionFromContent(content); |
| 0 | 501 | | } |
| | 502 | |
|
| | 503 | | /// <summary> |
| | 504 | | /// Retrieves the list of runtime information for topics present in the namespace. |
| | 505 | | /// </summary> |
| | 506 | | /// <param name="count">The number of topics to fetch. Defaults to 100. Maximum value allowed is 100.</param> |
| | 507 | | /// <param name="skip">The number of topics to skip. Defaults to 0. Cannot be negative.</param> |
| | 508 | | /// <param name="cancellationToken"></param> |
| | 509 | | /// <returns><see cref="IList<TopicRuntimeInfo>"/> containing list of topics.</returns> |
| | 510 | | /// <exception cref="ArgumentOutOfRangeException">If the parameters are out of range.</exception> |
| | 511 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 512 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 513 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 514 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 515 | | /// <remarks>You can simulate pages of list of entities by manipulating <paramref name="count"/> and <paramref n |
| | 516 | | /// skip(0)+count(100) gives first 100 entities. skip(100)+count(100) gives the next 100 entities.</remarks> |
| | 517 | | public virtual async Task<IList<TopicRuntimeInfo>> GetTopicsRuntimeInfoAsync(int count = 100, int skip = 0, Canc |
| | 518 | | { |
| 0 | 519 | | if (count > 100 || count < 1) |
| | 520 | | { |
| 0 | 521 | | throw new ArgumentOutOfRangeException(nameof(count), "Value should be between 1 and 100"); |
| | 522 | | } |
| 0 | 523 | | if (skip < 0) |
| | 524 | | { |
| 0 | 525 | | throw new ArgumentOutOfRangeException(nameof(skip), "Value cannot be negative"); |
| | 526 | | } |
| | 527 | |
|
| 0 | 528 | | var content = await GetEntity("$Resources/topics", $"$skip={skip}&$top={count}", false, cancellationToken). |
| | 529 | |
|
| 0 | 530 | | return TopicRuntimeInfoExtensions.ParseCollectionFromContent(content); |
| 0 | 531 | | } |
| | 532 | |
|
| | 533 | | /// <summary> |
| | 534 | | /// Retrieves the list of runtime information for subscriptions present in the namespace. |
| | 535 | | /// </summary> |
| | 536 | | /// <param name="topicPath">The path of the topic relative to service bus namespace.</param> |
| | 537 | | /// <param name="count">The number of subscriptions to fetch. Defaults to 100. Maximum value allowed is 100.</pa |
| | 538 | | /// <param name="skip">The number of subscriptions to skip. Defaults to 0. Cannot be negative.</param> |
| | 539 | | /// <param name="cancellationToken"></param> |
| | 540 | | /// <returns><see cref="IList<SubscriptionRuntimeInfo>"/> containing list of topics.</returns> |
| | 541 | | /// <exception cref="ArgumentOutOfRangeException">If the parameters are out of range.</exception> |
| | 542 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 543 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 544 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 545 | | /// <exception cref="ServiceBusException">An internal error or an unexpected exception occured.</exception> |
| | 546 | | /// <remarks>You can simulate pages of list of entities by manipulating <paramref name="count"/> and <paramref n |
| | 547 | | /// skip(0)+count(100) gives first 100 entities. skip(100)+count(100) gives the next 100 entities.</remarks> |
| | 548 | | public virtual async Task<IList<SubscriptionRuntimeInfo>> GetSubscriptionsRuntimeInfoAsync(string topicPath, int |
| | 549 | | { |
| 0 | 550 | | if (count > 100 || count < 1) |
| | 551 | | { |
| 0 | 552 | | throw new ArgumentOutOfRangeException(nameof(count), "Value should be between 1 and 100"); |
| | 553 | | } |
| 0 | 554 | | if (skip < 0) |
| | 555 | | { |
| 0 | 556 | | throw new ArgumentOutOfRangeException(nameof(skip), "Value cannot be negative"); |
| | 557 | | } |
| | 558 | |
|
| 0 | 559 | | var content = await GetEntity($"{topicPath}/Subscriptions", $"$skip={skip}&$top={count}", false, cancellati |
| | 560 | |
|
| 0 | 561 | | return SubscriptionRuntimeInfoExtensions.ParseCollectionFromContent(topicPath, content); |
| 0 | 562 | | } |
| | 563 | |
|
| | 564 | | #endregion |
| | 565 | |
|
| | 566 | | #region CreateEntity |
| | 567 | |
|
| | 568 | | /// <summary> |
| | 569 | | /// Creates a new queue in the service namespace with the given name. |
| | 570 | | /// </summary> |
| | 571 | | /// <remarks>Throws if a queue already exists. <see cref="QueueDescription"/> for default values of queue proper |
| | 572 | | /// <param name="queuePath">The name of the queue relative to the service namespace base address.</param> |
| | 573 | | /// <param name="cancellationToken"></param> |
| | 574 | | /// <returns>The <see cref="QueueDescription"/> of the newly created queue.</returns> |
| | 575 | | /// <exception cref="ArgumentNullException">Queue name is null or empty.</exception> |
| | 576 | | /// <exception cref="ArgumentOutOfRangeException">The length of <paramref name="queuePath"/> is greater than 260 |
| | 577 | | /// <exception cref="MessagingEntityAlreadyExistsException">An entity with the same name exists under the same s |
| | 578 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 579 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 580 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 581 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 582 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 583 | | public virtual Task<QueueDescription> CreateQueueAsync(string queuePath, CancellationToken cancellationToken = d |
| | 584 | | { |
| 0 | 585 | | return this.CreateQueueAsync(new QueueDescription(queuePath), cancellationToken); |
| | 586 | | } |
| | 587 | |
|
| | 588 | | /// <summary> |
| | 589 | | /// Creates a new queue in the service namespace with the given name. |
| | 590 | | /// </summary> |
| | 591 | | /// <remarks>Throws if a queue already exists.</remarks> |
| | 592 | | /// <param name="queueDescription">A <see cref="QueueDescription"/> object describing the attributes with which |
| | 593 | | /// <param name="cancellationToken"></param> |
| | 594 | | /// <returns>The <see cref="QueueDescription"/> of the newly created queue.</returns> |
| | 595 | | /// <exception cref="ArgumentNullException">Queue name is null or empty.</exception> |
| | 596 | | /// <exception cref="MessagingEntityAlreadyExistsException">A queue with the same nameexists under the same serv |
| | 597 | | /// <exception cref="ServiceBusTimeoutException">The operation times out.</exception> |
| | 598 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 599 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 600 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 601 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 602 | | public virtual async Task<QueueDescription> CreateQueueAsync(QueueDescription queueDescription, CancellationToke |
| | 603 | | { |
| 0 | 604 | | queueDescription = queueDescription ?? throw new ArgumentNullException(nameof(queueDescription)); |
| 0 | 605 | | queueDescription.NormalizeDescription(this.endpointFQDN); |
| 0 | 606 | | var atomRequest = queueDescription.Serialize().ToString(); |
| 0 | 607 | | var content = await PutEntity( |
| 0 | 608 | | queueDescription.Path, |
| 0 | 609 | | atomRequest, |
| 0 | 610 | | false, |
| 0 | 611 | | queueDescription.ForwardTo, |
| 0 | 612 | | queueDescription.ForwardDeadLetteredMessagesTo, |
| 0 | 613 | | cancellationToken).ConfigureAwait(false); |
| 0 | 614 | | return QueueDescriptionExtensions.ParseFromContent(content); |
| 0 | 615 | | } |
| | 616 | |
|
| | 617 | | /// <summary> |
| | 618 | | /// Creates a new topic in the service namespace with the given name. |
| | 619 | | /// </summary> |
| | 620 | | /// <remarks>Throws if a topic already exists. <see cref="TopicDescription"/> for default values of topic proper |
| | 621 | | /// <param name="topicPath">The name of the topic relative to the service namespace base address.</param> |
| | 622 | | /// <param name="cancellationToken"></param> |
| | 623 | | /// <returns>The <see cref="TopicDescription"/> of the newly created topic.</returns> |
| | 624 | | /// <exception cref="ArgumentNullException">Topic name is null or empty.</exception> |
| | 625 | | /// <exception cref="ArgumentOutOfRangeException">The length of <paramref name="topicPath"/> is greater than 260 |
| | 626 | | /// <exception cref="MessagingEntityAlreadyExistsException">A topic with the same name exists under the same ser |
| | 627 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 628 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 629 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 630 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 631 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 632 | | public virtual Task<TopicDescription> CreateTopicAsync(string topicPath, CancellationToken cancellationToken = d |
| | 633 | | { |
| 0 | 634 | | return this.CreateTopicAsync(new TopicDescription(topicPath), cancellationToken); |
| | 635 | | } |
| | 636 | |
|
| | 637 | | /// <summary> |
| | 638 | | /// Creates a new topic in the service namespace with the given name. |
| | 639 | | /// </summary> |
| | 640 | | /// <remarks>Throws if a topic already exists. <see cref="TopicDescription"/> for default values of topic proper |
| | 641 | | /// <param name="topicDescription">A <see cref="TopicDescription"/> object describing the attributes with which |
| | 642 | | /// <param name="cancellationToken"></param> |
| | 643 | | /// <returns>The <see cref="TopicDescription"/> of the newly created topic.</returns> |
| | 644 | | /// <exception cref="ArgumentNullException">Topic description is null.</exception> |
| | 645 | | /// <exception cref="MessagingEntityAlreadyExistsException">A topic with the same name exists under the same ser |
| | 646 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 647 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 648 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 649 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 650 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 651 | | public virtual async Task<TopicDescription> CreateTopicAsync(TopicDescription topicDescription, CancellationToke |
| | 652 | | { |
| 0 | 653 | | topicDescription = topicDescription ?? throw new ArgumentNullException(nameof(topicDescription)); |
| 0 | 654 | | var atomRequest = topicDescription.Serialize().ToString(); |
| | 655 | |
|
| 0 | 656 | | var content = await PutEntity(topicDescription.Path, atomRequest, false, null, null, cancellationToken).Conf |
| | 657 | |
|
| 0 | 658 | | return TopicDescriptionExtensions.ParseFromContent(content); |
| 0 | 659 | | } |
| | 660 | |
|
| | 661 | | /// <summary> |
| | 662 | | /// Creates a new subscription within a topic in the service namespace with the given name. |
| | 663 | | /// </summary> |
| | 664 | | /// <remarks>Throws if a subscription already exists. <see cref="SubscriptionDescription"/> for default values o |
| | 665 | | /// Be default, A "pass-through" filter is created for this subscription, which means it will allow all messages |
| | 666 | | /// <see cref="CreateSubscriptionAsync(SubscriptionDescription, RuleDescription, CancellationToken)"/> for creat |
| | 667 | | /// <param name="topicPath">The path of the topic relative to the service namespace base address.</param> |
| | 668 | | /// <param name="subscriptionName">The name of the subscription.</param> |
| | 669 | | /// <param name="cancellationToken"></param> |
| | 670 | | /// <returns>The <see cref="SubscriptionDescription"/> of the newly created subscription.</returns> |
| | 671 | | /// <exception cref="ArgumentNullException">Topic path or subscription name is null or empty.</exception> |
| | 672 | | /// <exception cref="ArgumentOutOfRangeException">The length of <paramref name="topicPath"/> is greater than 260 |
| | 673 | | /// <exception cref="MessagingEntityAlreadyExistsException">A subscription with the same name exists under the s |
| | 674 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 675 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 676 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 677 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 678 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 679 | | public virtual Task<SubscriptionDescription> CreateSubscriptionAsync(string topicPath, string subscriptionName, |
| | 680 | | { |
| 0 | 681 | | return this.CreateSubscriptionAsync(new SubscriptionDescription(topicPath, subscriptionName), cancellationTo |
| | 682 | | } |
| | 683 | |
|
| | 684 | | /// <summary> |
| | 685 | | /// Creates a new subscription within a topic in the service namespace with the given name. |
| | 686 | | /// </summary> |
| | 687 | | /// <remarks>Throws if a subscription already exists. |
| | 688 | | /// Be default, A "pass-through" filter is created for this subscription, which means it will allow all messages |
| | 689 | | /// <see cref="CreateSubscriptionAsync(SubscriptionDescription, RuleDescription, CancellationToken)"/> for creat |
| | 690 | | /// <param name="subscriptionDescription">A <see cref="SubscriptionDescription"/> object describing the attribut |
| | 691 | | /// <param name="cancellationToken"></param> |
| | 692 | | /// <returns>The <see cref="SubscriptionDescription"/> of the newly created subscription.</returns> |
| | 693 | | /// <exception cref="ArgumentNullException">Subscription description is null.</exception> |
| | 694 | | /// <exception cref="MessagingEntityAlreadyExistsException">A subscription with the same name exists under the s |
| | 695 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 696 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 697 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 698 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 699 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 700 | | public virtual Task<SubscriptionDescription> CreateSubscriptionAsync(SubscriptionDescription subscriptionDescrip |
| | 701 | | { |
| 0 | 702 | | subscriptionDescription = subscriptionDescription ?? throw new ArgumentNullException(nameof(subscriptionDesc |
| 0 | 703 | | return this.CreateSubscriptionAsync(subscriptionDescription, null, cancellationToken); |
| | 704 | | } |
| | 705 | |
|
| | 706 | | /// <summary> |
| | 707 | | /// Creates a new subscription within a topic with the provided default rule. |
| | 708 | | /// </summary> |
| | 709 | | /// <remarks>Throws if a subscription already exists. </remarks> |
| | 710 | | /// <param name="subscriptionDescription">A <see cref="SubscriptionDescription"/> object describing the attribut |
| | 711 | | /// <param name="defaultRule"> A <see cref="RuleDescription"/> object describing the default rule. If null, then |
| | 712 | | /// <param name="cancellationToken"></param> |
| | 713 | | /// <returns>The <see cref="SubscriptionDescription"/> of the newly created subscription.</returns> |
| | 714 | | /// <exception cref="ArgumentNullException">Subscription description is null.</exception> |
| | 715 | | /// <exception cref="MessagingEntityAlreadyExistsException">A subscription with the same name exists under the s |
| | 716 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 717 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 718 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 719 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 720 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 721 | | public virtual async Task<SubscriptionDescription> CreateSubscriptionAsync(SubscriptionDescription subscriptionD |
| | 722 | | { |
| 0 | 723 | | subscriptionDescription = subscriptionDescription ?? throw new ArgumentNullException(nameof(subscriptionDesc |
| 0 | 724 | | subscriptionDescription.NormalizeDescription(this.endpointFQDN); |
| 0 | 725 | | subscriptionDescription.DefaultRuleDescription = defaultRule; |
| 0 | 726 | | var atomRequest = subscriptionDescription.Serialize().ToString(); |
| 0 | 727 | | var content = await PutEntity( |
| 0 | 728 | | EntityNameHelper.FormatSubscriptionPath(subscriptionDescription.TopicPath, subscriptionDescription.Subsc |
| 0 | 729 | | atomRequest, |
| 0 | 730 | | false, |
| 0 | 731 | | subscriptionDescription.ForwardTo, |
| 0 | 732 | | subscriptionDescription.ForwardDeadLetteredMessagesTo, |
| 0 | 733 | | cancellationToken).ConfigureAwait(false); |
| 0 | 734 | | return SubscriptionDescriptionExtensions.ParseFromContent(subscriptionDescription.TopicPath, content); |
| 0 | 735 | | } |
| | 736 | |
|
| | 737 | | /// <summary> |
| | 738 | | /// Adds a new rule to the subscription under given topic. |
| | 739 | | /// </summary> |
| | 740 | | /// <param name="topicPath">The topic path relative to the service namespace base address.</param> |
| | 741 | | /// <param name="subscriptionName">The name of the subscription.</param> |
| | 742 | | /// <param name="ruleDescription">A <see cref="RuleDescription"/> object describing the attributes with which th |
| | 743 | | /// <param name="cancellationToken"></param> |
| | 744 | | /// <exception cref="ArgumentNullException">Subscription or rule description is null.</exception> |
| | 745 | | /// <exception cref="MessagingEntityAlreadyExistsException">A subscription with the same name exists under the s |
| | 746 | | /// <exception cref="ServiceBusTimeoutException">The operation times out. The timeout period is initialized thro |
| | 747 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 748 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 749 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 750 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 751 | | /// <returns><see cref="RuleDescription"/> of the recently created rule.</returns> |
| | 752 | | public virtual async Task<RuleDescription> CreateRuleAsync(string topicPath, string subscriptionName, RuleDescri |
| | 753 | | { |
| 0 | 754 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 755 | | EntityNameHelper.CheckValidSubscriptionName(subscriptionName); |
| 0 | 756 | | ruleDescription = ruleDescription ?? throw new ArgumentNullException(nameof(ruleDescription)); |
| | 757 | |
|
| 0 | 758 | | var atomRequest = ruleDescription.Serialize().ToString(); |
| | 759 | |
|
| 0 | 760 | | var content = await PutEntity( |
| 0 | 761 | | EntityNameHelper.FormatRulePath(topicPath, subscriptionName, ruleDescription.Name), |
| 0 | 762 | | atomRequest, |
| 0 | 763 | | false, |
| 0 | 764 | | null, |
| 0 | 765 | | null, |
| 0 | 766 | | cancellationToken).ConfigureAwait(false); |
| | 767 | |
|
| 0 | 768 | | return RuleDescriptionExtensions.ParseFromContent(content); |
| 0 | 769 | | } |
| | 770 | |
|
| | 771 | | #endregion CreateEntity |
| | 772 | |
|
| | 773 | | #region UpdateEntity |
| | 774 | | /// <summary> |
| | 775 | | /// Updates an existing queue. |
| | 776 | | /// </summary> |
| | 777 | | /// <param name="queueDescription">A <see cref="QueueDescription"/> object describing the attributes with which |
| | 778 | | /// <param name="cancellationToken"></param> |
| | 779 | | /// <returns>The <see cref="QueueDescription"/> of the updated queue.</returns> |
| | 780 | | /// <exception cref="ArgumentNullException">Queue descriptor is null.</exception> |
| | 781 | | /// <exception cref="MessagingEntityNotFoundException">Described queue was not found.</exception> |
| | 782 | | /// <exception cref="ServiceBusTimeoutException">The operation times out.</exception> |
| | 783 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 784 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 785 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 786 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 787 | | public virtual async Task<QueueDescription> UpdateQueueAsync(QueueDescription queueDescription, CancellationToke |
| | 788 | | { |
| 0 | 789 | | queueDescription = queueDescription ?? throw new ArgumentNullException(nameof(queueDescription)); |
| 0 | 790 | | queueDescription.NormalizeDescription(this.endpointFQDN); |
| | 791 | |
|
| 0 | 792 | | var atomRequest = queueDescription.Serialize().ToString(); |
| | 793 | |
|
| 0 | 794 | | var content = await PutEntity( |
| 0 | 795 | | queueDescription.Path, |
| 0 | 796 | | atomRequest, |
| 0 | 797 | | true, |
| 0 | 798 | | queueDescription.ForwardTo, |
| 0 | 799 | | queueDescription.ForwardDeadLetteredMessagesTo, |
| 0 | 800 | | cancellationToken).ConfigureAwait(false); |
| | 801 | |
|
| 0 | 802 | | return QueueDescriptionExtensions.ParseFromContent(content); |
| 0 | 803 | | } |
| | 804 | |
|
| | 805 | | /// <summary> |
| | 806 | | /// Updates an existing topic. |
| | 807 | | /// </summary> |
| | 808 | | /// <param name="topicDescription">A <see cref="TopicDescription"/> object describing the attributes with which |
| | 809 | | /// <param name="cancellationToken"></param> |
| | 810 | | /// <returns>The <see cref="TopicDescription"/> of the updated topic.</returns> |
| | 811 | | /// <exception cref="ArgumentNullException">Topic descriptor is null.</exception> |
| | 812 | | /// <exception cref="MessagingEntityNotFoundException">Described topic was not found.</exception> |
| | 813 | | /// <exception cref="ServiceBusTimeoutException">The operation times out.</exception> |
| | 814 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 815 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 816 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 817 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 818 | | public virtual async Task<TopicDescription> UpdateTopicAsync(TopicDescription topicDescription, CancellationToke |
| | 819 | | { |
| 0 | 820 | | topicDescription = topicDescription ?? throw new ArgumentNullException(nameof(topicDescription)); |
| 0 | 821 | | var atomRequest = topicDescription.Serialize().ToString(); |
| | 822 | |
|
| 0 | 823 | | var content = await PutEntity(topicDescription.Path, atomRequest, true, null, null, cancellationToken).Confi |
| | 824 | |
|
| 0 | 825 | | return TopicDescriptionExtensions.ParseFromContent(content); |
| 0 | 826 | | } |
| | 827 | |
|
| | 828 | | /// <summary> |
| | 829 | | /// Updates an existing subscription under a topic. |
| | 830 | | /// </summary> |
| | 831 | | /// <param name="subscriptionDescription">A <see cref="SubscriptionDescription"/> object describing the attribut |
| | 832 | | /// <param name="cancellationToken"></param> |
| | 833 | | /// <returns>The <see cref="SubscriptionDescription"/> of the updated subscription.</returns> |
| | 834 | | /// <exception cref="ArgumentNullException">subscription descriptor is null.</exception> |
| | 835 | | /// <exception cref="MessagingEntityNotFoundException">Described subscription was not found.</exception> |
| | 836 | | /// <exception cref="ServiceBusTimeoutException">The operation times out.</exception> |
| | 837 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 838 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 839 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 840 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 841 | | public virtual async Task<SubscriptionDescription> UpdateSubscriptionAsync(SubscriptionDescription subscriptionD |
| | 842 | | { |
| 0 | 843 | | subscriptionDescription = subscriptionDescription ?? throw new ArgumentNullException(nameof(subscriptionDesc |
| 0 | 844 | | subscriptionDescription.NormalizeDescription(this.endpointFQDN); |
| 0 | 845 | | var atomRequest = subscriptionDescription.Serialize().ToString(); |
| 0 | 846 | | var content = await PutEntity( |
| 0 | 847 | | EntityNameHelper.FormatSubscriptionPath(subscriptionDescription.TopicPath, subscriptionDescription.Subsc |
| 0 | 848 | | atomRequest, |
| 0 | 849 | | true, |
| 0 | 850 | | subscriptionDescription.ForwardTo, |
| 0 | 851 | | subscriptionDescription.ForwardDeadLetteredMessagesTo, |
| 0 | 852 | | cancellationToken).ConfigureAwait(false); |
| 0 | 853 | | return SubscriptionDescriptionExtensions.ParseFromContent(subscriptionDescription.TopicPath, content); |
| 0 | 854 | | } |
| | 855 | |
|
| | 856 | | /// <summary> |
| | 857 | | /// Updates an existing rule for a topic-subscription. |
| | 858 | | /// </summary> |
| | 859 | | /// <param name="topicPath">Path of the topic.</param> |
| | 860 | | /// <param name="subscriptionName">Name of the subscription.</param> |
| | 861 | | /// <param name="ruleDescription">A <see cref="RuleDescription"/> object describing the attributes with which th |
| | 862 | | /// <param name="cancellationToken"></param> |
| | 863 | | /// <returns>The <see cref="RuleDescription"/> of the updated rule.</returns> |
| | 864 | | /// <exception cref="ArgumentNullException">rule descriptor is null.</exception> |
| | 865 | | /// <exception cref="MessagingEntityNotFoundException">Described topic/subscription/rule was not found.</excepti |
| | 866 | | /// <exception cref="ServiceBusTimeoutException">The operation times out.</exception> |
| | 867 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 868 | | /// <exception cref="QuotaExceededException">Either the specified size in the description is not supported or th |
| | 869 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 870 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 871 | | public virtual async Task<RuleDescription> UpdateRuleAsync(string topicPath, string subscriptionName, RuleDescri |
| | 872 | | { |
| 0 | 873 | | ruleDescription = ruleDescription ?? throw new ArgumentNullException(nameof(ruleDescription)); |
| 0 | 874 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 875 | | EntityNameHelper.CheckValidSubscriptionName(subscriptionName); |
| | 876 | |
|
| 0 | 877 | | var atomRequest = ruleDescription.Serialize().ToString(); |
| 0 | 878 | | var content = await PutEntity( |
| 0 | 879 | | EntityNameHelper.FormatRulePath(topicPath, subscriptionName, ruleDescription.Name), |
| 0 | 880 | | atomRequest, |
| 0 | 881 | | true, |
| 0 | 882 | | null, null, |
| 0 | 883 | | cancellationToken).ConfigureAwait(false); |
| | 884 | |
|
| 0 | 885 | | return RuleDescriptionExtensions.ParseFromContent(content); |
| 0 | 886 | | } |
| | 887 | |
|
| | 888 | | #endregion |
| | 889 | |
|
| | 890 | | #region Exists |
| | 891 | | /// <summary> |
| | 892 | | /// Checks whether a given queue exists or not. |
| | 893 | | /// </summary> |
| | 894 | | /// <param name="queuePath">Path of the queue entity to check.</param> |
| | 895 | | /// <param name="cancellationToken"></param> |
| | 896 | | /// <returns>True if queue exists, false otherwise.</returns> |
| | 897 | | /// <exception cref="ArgumentException">Queue path provided is not valid.</exception> |
| | 898 | | /// <exception cref="ServiceBusTimeoutException">The operation times out.</exception> |
| | 899 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 900 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 901 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 902 | | public virtual async Task<bool> QueueExistsAsync(string queuePath, CancellationToken cancellationToken = default |
| | 903 | | { |
| 0 | 904 | | EntityNameHelper.CheckValidQueueName(queuePath); |
| | 905 | |
|
| | 906 | | try |
| | 907 | | { |
| | 908 | | // TODO: Optimize by removing deserialization costs. |
| 0 | 909 | | var qd = await GetQueueAsync(queuePath, cancellationToken).ConfigureAwait(false); |
| 0 | 910 | | } |
| 0 | 911 | | catch (MessagingEntityNotFoundException) |
| | 912 | | { |
| 0 | 913 | | return false; |
| | 914 | | } |
| | 915 | |
|
| 0 | 916 | | return true; |
| 0 | 917 | | } |
| | 918 | |
|
| | 919 | | /// <summary> |
| | 920 | | /// Checks whether a given topic exists or not. |
| | 921 | | /// </summary> |
| | 922 | | /// <param name="topicPath">Path of the topic entity to check.</param> |
| | 923 | | /// <param name="cancellationToken"></param> |
| | 924 | | /// <returns>True if topic exists, false otherwise.</returns> |
| | 925 | | /// <exception cref="ArgumentException">topic path provided is not valid.</exception> |
| | 926 | | /// <exception cref="ServiceBusTimeoutException">The operation times out.</exception> |
| | 927 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 928 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 929 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 930 | | public virtual async Task<bool> TopicExistsAsync(string topicPath, CancellationToken cancellationToken = default |
| | 931 | | { |
| 0 | 932 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| | 933 | |
|
| | 934 | | try |
| | 935 | | { |
| | 936 | | // TODO: Optimize by removing deserialization costs. |
| 0 | 937 | | var td = await GetTopicAsync(topicPath, cancellationToken).ConfigureAwait(false); |
| 0 | 938 | | } |
| 0 | 939 | | catch (MessagingEntityNotFoundException) |
| | 940 | | { |
| 0 | 941 | | return false; |
| | 942 | | } |
| | 943 | |
|
| 0 | 944 | | return true; |
| 0 | 945 | | } |
| | 946 | |
|
| | 947 | | /// <summary> |
| | 948 | | /// Checks whether a given subscription exists or not. |
| | 949 | | /// </summary> |
| | 950 | | /// <param name="topicPath">Path of the topic.</param> |
| | 951 | | /// <param name="subscriptionName">Name of the subscription to check.</param> |
| | 952 | | /// <param name="cancellationToken"></param> |
| | 953 | | /// <returns>True if subscription exists, false otherwise.</returns> |
| | 954 | | /// <exception cref="ArgumentException">topic or subscription path provided is not valid.</exception> |
| | 955 | | /// <exception cref="ServiceBusTimeoutException">The operation times out.</exception> |
| | 956 | | /// <exception cref="UnauthorizedAccessException">No sufficient permission to perform this operation. You should |
| | 957 | | /// <exception cref="ServerBusyException">The server is busy. You should wait before you retry the operation.</e |
| | 958 | | /// <exception cref="ServiceBusException">An internal error or unexpected exception occurs.</exception> |
| | 959 | | public virtual async Task<bool> SubscriptionExistsAsync(string topicPath, string subscriptionName, CancellationT |
| | 960 | | { |
| 0 | 961 | | EntityNameHelper.CheckValidTopicName(topicPath); |
| 0 | 962 | | EntityNameHelper.CheckValidSubscriptionName(subscriptionName); |
| | 963 | |
|
| | 964 | | try |
| | 965 | | { |
| | 966 | | // TODO: Optimize by removing deserialization costs. |
| 0 | 967 | | var sd = await GetSubscriptionAsync(topicPath, subscriptionName, cancellationToken).ConfigureAwait(false |
| 0 | 968 | | } |
| 0 | 969 | | catch (MessagingEntityNotFoundException) |
| | 970 | | { |
| 0 | 971 | | return false; |
| | 972 | | } |
| | 973 | |
|
| 0 | 974 | | return true; |
| 0 | 975 | | } |
| | 976 | |
|
| | 977 | | public Task CloseAsync() |
| | 978 | | { |
| 0 | 979 | | httpClient?.Dispose(); |
| 0 | 980 | | httpClient = null; |
| | 981 | |
|
| 0 | 982 | | return Task.CompletedTask; |
| | 983 | | } |
| | 984 | |
|
| | 985 | | #endregion |
| | 986 | |
|
| | 987 | | private static int GetPort(string endpoint) |
| | 988 | | { |
| | 989 | | // used for internal testing |
| 6 | 990 | | if (endpoint.EndsWith("onebox.windows-int.net", StringComparison.InvariantCultureIgnoreCase)) |
| | 991 | | { |
| 0 | 992 | | return 4446; |
| | 993 | | } |
| | 994 | |
|
| 6 | 995 | | return -1; |
| | 996 | | } |
| | 997 | |
|
| | 998 | | private static async Task<Exception> ValidateHttpResponse(HttpResponseMessage response) |
| | 999 | | { |
| 0 | 1000 | | if (response.IsSuccessStatusCode) |
| | 1001 | | { |
| 0 | 1002 | | return null; |
| | 1003 | | } |
| | 1004 | |
|
| 0 | 1005 | | var exceptionMessage = await (response.Content?.ReadAsStringAsync() ?? Task.FromResult(string.Empty)); |
| 0 | 1006 | | exceptionMessage = ParseDetailIfAvailable(exceptionMessage) ?? response.ReasonPhrase; |
| | 1007 | |
|
| 0 | 1008 | | if (response.StatusCode == HttpStatusCode.Unauthorized) |
| | 1009 | | { |
| 0 | 1010 | | return new UnauthorizedException(exceptionMessage); |
| | 1011 | | } |
| | 1012 | |
|
| 0 | 1013 | | if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.NoContent) |
| | 1014 | | { |
| 0 | 1015 | | return new MessagingEntityNotFoundException(exceptionMessage); |
| | 1016 | | } |
| | 1017 | |
|
| 0 | 1018 | | if (response.StatusCode == HttpStatusCode.Conflict) |
| | 1019 | | { |
| 0 | 1020 | | if (response.RequestMessage.Method.Equals(HttpMethod.Delete)) |
| | 1021 | | { |
| 0 | 1022 | | return new ServiceBusException(true, exceptionMessage); |
| | 1023 | | } |
| | 1024 | |
|
| 0 | 1025 | | if (response.RequestMessage.Method.Equals(HttpMethod.Put) && response.RequestMessage.Headers.IfMatch.Cou |
| | 1026 | | { |
| | 1027 | | // response.RequestMessage.Headers.IfMatch.Count > 0 is true for UpdateEntity scenario |
| 0 | 1028 | | return new ServiceBusException(true, exceptionMessage); |
| | 1029 | | } |
| | 1030 | |
|
| 0 | 1031 | | if (exceptionMessage.Contains(ManagementClientConstants.ConflictOperationInProgressSubCode)) |
| | 1032 | | { |
| 0 | 1033 | | return new ServiceBusException(true, exceptionMessage); |
| | 1034 | | } |
| | 1035 | |
|
| 0 | 1036 | | return new MessagingEntityAlreadyExistsException(exceptionMessage); |
| | 1037 | | } |
| | 1038 | |
|
| 0 | 1039 | | if (response.StatusCode == HttpStatusCode.Forbidden) |
| | 1040 | | { |
| 0 | 1041 | | if (exceptionMessage.Contains(ManagementClientConstants.ForbiddenInvalidOperationSubCode)) |
| | 1042 | | { |
| 0 | 1043 | | return new InvalidOperationException(exceptionMessage); |
| | 1044 | | } |
| | 1045 | |
|
| 0 | 1046 | | return new QuotaExceededException(exceptionMessage); |
| | 1047 | | } |
| | 1048 | |
|
| 0 | 1049 | | if (response.StatusCode == HttpStatusCode.BadRequest) |
| | 1050 | | { |
| 0 | 1051 | | return new ServiceBusException(false, new ArgumentException(exceptionMessage)); |
| | 1052 | | } |
| | 1053 | |
|
| 0 | 1054 | | if (response.StatusCode == HttpStatusCode.ServiceUnavailable) |
| | 1055 | | { |
| 0 | 1056 | | return new ServerBusyException(exceptionMessage); |
| | 1057 | | } |
| | 1058 | |
|
| 0 | 1059 | | return new ServiceBusException(true, exceptionMessage + "; response status code: " + response.StatusCode); |
| 0 | 1060 | | } |
| | 1061 | |
|
| | 1062 | | private static string ParseDetailIfAvailable(string content) |
| | 1063 | | { |
| 0 | 1064 | | if (string.IsNullOrWhiteSpace(content)) |
| | 1065 | | { |
| 0 | 1066 | | return null; |
| | 1067 | | } |
| | 1068 | |
|
| | 1069 | | try |
| | 1070 | | { |
| 0 | 1071 | | var errorContentXml = XElement.Parse(content); |
| 0 | 1072 | | var detail = errorContentXml.Element("Detail"); |
| | 1073 | |
|
| 0 | 1074 | | return detail?.Value ?? content; |
| | 1075 | | } |
| 0 | 1076 | | catch (Exception) |
| | 1077 | | { |
| 0 | 1078 | | return content; |
| | 1079 | | } |
| 0 | 1080 | | } |
| | 1081 | |
|
| | 1082 | | private static ITokenProvider CreateTokenProvider(ServiceBusConnectionStringBuilder builder) |
| | 1083 | | { |
| 12 | 1084 | | if (builder.SasToken != null) |
| | 1085 | | { |
| 0 | 1086 | | return new SharedAccessSignatureTokenProvider(builder.SasToken); |
| | 1087 | | } |
| 12 | 1088 | | else if (builder.SasKeyName != null && builder.SasKey != null) |
| | 1089 | | { |
| 0 | 1090 | | return new SharedAccessSignatureTokenProvider(builder.SasKeyName, builder.SasKey); |
| | 1091 | | } |
| 12 | 1092 | | else if (builder.Authentication.Equals(ServiceBusConnectionStringBuilder.AuthenticationType.ManagedIdentity) |
| | 1093 | | { |
| 6 | 1094 | | return new ManagedIdentityTokenProvider(); |
| | 1095 | | } |
| | 1096 | |
|
| 6 | 1097 | | throw new ArgumentException("Could not create token provider. Either ITokenProvider has to be passed into co |
| | 1098 | | } |
| | 1099 | |
|
| | 1100 | | private Task<string> GetToken(Uri requestUri) |
| | 1101 | | { |
| 0 | 1102 | | return this.GetToken(requestUri.GetLeftPart(UriPartial.Path)); |
| | 1103 | | } |
| | 1104 | |
|
| | 1105 | | private async Task<string> GetToken(string requestUri) |
| | 1106 | | { |
| 0 | 1107 | | var token = await this.tokenProvider.GetTokenAsync(requestUri, TimeSpan.FromHours(1)).ConfigureAwait(false); |
| 0 | 1108 | | return token.TokenValue; |
| 0 | 1109 | | } |
| | 1110 | |
|
| | 1111 | | private async Task<string> GetEntity(string path, string query, bool enrich, CancellationToken cancellationToken |
| | 1112 | | { |
| 0 | 1113 | | MessagingEventSource.Log.ManagementOperationStart(this.clientId, nameof(GetEntity), $"path:{path},query:{que |
| | 1114 | |
|
| 0 | 1115 | | var queryString = $"{ManagementClientConstants.apiVersionQuery}&enrich={enrich}"; |
| 0 | 1116 | | if (query != null) |
| | 1117 | | { |
| 0 | 1118 | | queryString = queryString + "&" + query; |
| | 1119 | | } |
| 0 | 1120 | | var uri = new UriBuilder(this.endpointFQDN) |
| 0 | 1121 | | { |
| 0 | 1122 | | Path = path, |
| 0 | 1123 | | Scheme = Uri.UriSchemeHttps, |
| 0 | 1124 | | Port = this.port, |
| 0 | 1125 | | Query = queryString |
| 0 | 1126 | | }.Uri; |
| | 1127 | |
|
| 0 | 1128 | | var request = new HttpRequestMessage(HttpMethod.Get, uri); |
| 0 | 1129 | | HttpResponseMessage response = await SendHttpRequest(request, cancellationToken).ConfigureAwait(false); |
| 0 | 1130 | | var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); |
| | 1131 | |
|
| 0 | 1132 | | MessagingEventSource.Log.ManagementOperationEnd(this.clientId, nameof(GetEntity), $"path:{path},query:{query |
| 0 | 1133 | | return result; |
| 0 | 1134 | | } |
| | 1135 | |
|
| | 1136 | | private async Task<string> PutEntity(string path, string requestBody, bool isUpdate, string forwardTo, string fw |
| | 1137 | | { |
| 0 | 1138 | | MessagingEventSource.Log.ManagementOperationStart(this.clientId, nameof(PutEntity), $"path:{path},isUpdate:{ |
| | 1139 | |
|
| 0 | 1140 | | var uri = new UriBuilder(this.endpointFQDN) |
| 0 | 1141 | | { |
| 0 | 1142 | | Path = path, |
| 0 | 1143 | | Port = this.port, |
| 0 | 1144 | | Scheme = Uri.UriSchemeHttps, |
| 0 | 1145 | | Query = $"{ManagementClientConstants.apiVersionQuery}" |
| 0 | 1146 | | }.Uri; |
| | 1147 | |
|
| 0 | 1148 | | var request = new HttpRequestMessage(HttpMethod.Put, uri); |
| 0 | 1149 | | request.Content = new StringContent( |
| 0 | 1150 | | requestBody, |
| 0 | 1151 | | Encoding.UTF8, |
| 0 | 1152 | | ManagementClientConstants.AtomContentType |
| 0 | 1153 | | ); |
| | 1154 | |
|
| 0 | 1155 | | if (isUpdate) |
| | 1156 | | { |
| 0 | 1157 | | request.Headers.Add("If-Match", "*"); |
| | 1158 | | } |
| | 1159 | |
|
| 0 | 1160 | | if (!string.IsNullOrWhiteSpace(forwardTo)) |
| | 1161 | | { |
| 0 | 1162 | | var token = await this.GetToken(forwardTo).ConfigureAwait(false); |
| 0 | 1163 | | request.Headers.Add(ManagementClientConstants.ServiceBusSupplementartyAuthorizationHeaderName, token); |
| | 1164 | | } |
| | 1165 | |
|
| 0 | 1166 | | if (!string.IsNullOrWhiteSpace(fwdDeadLetterTo)) |
| | 1167 | | { |
| 0 | 1168 | | var token = await this.GetToken(fwdDeadLetterTo).ConfigureAwait(false); |
| 0 | 1169 | | request.Headers.Add(ManagementClientConstants.ServiceBusDlqSupplementaryAuthorizationHeaderName, token); |
| | 1170 | | } |
| | 1171 | |
|
| 0 | 1172 | | HttpResponseMessage response = await SendHttpRequest(request, cancellationToken).ConfigureAwait(false); |
| 0 | 1173 | | var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); |
| | 1174 | |
|
| 0 | 1175 | | MessagingEventSource.Log.ManagementOperationEnd(this.clientId, nameof(PutEntity), $"path:{path},isUpdate:{is |
| 0 | 1176 | | return result; |
| 0 | 1177 | | } |
| | 1178 | |
|
| | 1179 | | private async Task DeleteEntity(string path, CancellationToken cancellationToken) |
| | 1180 | | { |
| 0 | 1181 | | MessagingEventSource.Log.ManagementOperationStart(this.clientId, nameof(DeleteEntity), path); |
| | 1182 | |
|
| 0 | 1183 | | var uri = new UriBuilder(this.endpointFQDN) |
| 0 | 1184 | | { |
| 0 | 1185 | | Path = path, |
| 0 | 1186 | | Scheme = Uri.UriSchemeHttps, |
| 0 | 1187 | | Port = this.port, |
| 0 | 1188 | | Query = ManagementClientConstants.apiVersionQuery |
| 0 | 1189 | | }.Uri; |
| | 1190 | |
|
| 0 | 1191 | | var request = new HttpRequestMessage(HttpMethod.Delete, uri); |
| 0 | 1192 | | await SendHttpRequest(request, cancellationToken).ConfigureAwait(false); |
| 0 | 1193 | | MessagingEventSource.Log.ManagementOperationEnd(this.clientId, nameof(DeleteEntity), path); |
| 0 | 1194 | | } |
| | 1195 | |
|
| | 1196 | | private async Task<HttpResponseMessage> SendHttpRequest(HttpRequestMessage request, CancellationToken cancellati |
| | 1197 | | { |
| 0 | 1198 | | if (request.Headers.Authorization == null) |
| | 1199 | | { |
| | 1200 | | // First attempt. |
| 0 | 1201 | | var token = await this.GetToken(request.RequestUri).ConfigureAwait(false); |
| 0 | 1202 | | request.Headers.Add("Authorization", token); |
| 0 | 1203 | | request.Headers.Add("UserAgent", $"SERVICEBUS/{ManagementClientConstants.ApiVersion}(api-origin={ClientI |
| | 1204 | | } |
| | 1205 | | else |
| | 1206 | | { |
| | 1207 | | // This is a retried request. |
| 0 | 1208 | | request = CloneRequest(request); |
| | 1209 | | } |
| | 1210 | |
|
| | 1211 | | HttpResponseMessage response; |
| | 1212 | | try |
| | 1213 | | { |
| 0 | 1214 | | response = await this.httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false); |
| 0 | 1215 | | } |
| 0 | 1216 | | catch (HttpRequestException exception) |
| | 1217 | | { |
| 0 | 1218 | | MessagingEventSource.Log.ManagementOperationException(this.clientId, nameof(SendHttpRequest), exception) |
| 0 | 1219 | | throw new ServiceBusException(true, exception); |
| | 1220 | | } |
| | 1221 | |
|
| 0 | 1222 | | var exceptionReturned = await ValidateHttpResponse(response).ConfigureAwait(false); |
| 0 | 1223 | | if (exceptionReturned == null) |
| | 1224 | | { |
| 0 | 1225 | | return response; |
| | 1226 | | } |
| | 1227 | | else |
| | 1228 | | { |
| 0 | 1229 | | MessagingEventSource.Log.ManagementOperationException(this.clientId, nameof(SendHttpRequest), exceptionR |
| 0 | 1230 | | throw exceptionReturned; |
| | 1231 | | } |
| 0 | 1232 | | } |
| | 1233 | | } |
| | 1234 | | } |