PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/aspclassiccompiler/AzureStoreAsp/Assets/StorageClient/StorageAccountInfo.cs

#
C# | 628 lines | 425 code | 53 blank | 150 comment | 109 complexity | 7049f5f024859d54d1e8e259a48159e1 MD5 | raw file
Possible License(s): Apache-2.0, AGPL-3.0
  1. // ----------------------------------------------------------------------------------
  2. // Microsoft Developer & Platform Evangelism
  3. //
  4. // Copyright (c) Microsoft Corporation. All rights reserved.
  5. //
  6. // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
  7. // EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
  8. // OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
  9. // ----------------------------------------------------------------------------------
  10. // The example companies, organizations, products, domain names,
  11. // e-mail addresses, logos, people, places, and events depicted
  12. // herein are fictitious. No association with any real company,
  13. // organization, product, domain name, email address, logo, person,
  14. // places, or events is intended or should be inferred.
  15. // ----------------------------------------------------------------------------------
  16. //
  17. // <copyright file="StorageAccountInfo.cs" company="Microsoft">
  18. // Copyright (c) Microsoft Corporation. All rights reserved.
  19. // </copyright>
  20. //
  21. using System;
  22. using System.Collections.Generic;
  23. using System.Linq;
  24. using System.Text;
  25. using System.Globalization;
  26. using System.Configuration;
  27. using System.Collections.Specialized;
  28. using System.Diagnostics;
  29. using Microsoft.ServiceHosting.ServiceRuntime;
  30. namespace Microsoft.Samples.ServiceHosting.StorageClient
  31. {
  32. /// <summary>
  33. /// Objects of this class encapsulate information about a storage account and endpoint configuration.
  34. /// Associated with a storage account is the account name, the base URI of the account and a shared key.
  35. /// </summary>
  36. public class StorageAccountInfo
  37. {
  38. /// <summary>
  39. /// The default configuration string in configuration files for setting the queue storage endpoint.
  40. /// </summary>
  41. public static readonly string DefaultQueueStorageEndpointConfigurationString = "QueueStorageEndpoint";
  42. /// <summary>
  43. /// The default configuration string in configuration files for setting the blob storage endpoint.
  44. /// </summary>
  45. public static readonly string DefaultBlobStorageEndpointConfigurationString = "BlobStorageEndpoint";
  46. /// <summary>
  47. /// The default configuration string in configuration files for setting the table storage endpoint.
  48. /// </summary>
  49. public static readonly string DefaultTableStorageEndpointConfigurationString = "TableStorageEndpoint";
  50. /// <summary>
  51. /// The default configuration string in configuration files for setting the storage account name.
  52. /// </summary>
  53. public static readonly string DefaultAccountNameConfigurationString = "AccountName";
  54. /// <summary>
  55. /// The default configuration string in configuration files for setting the shared key associated with a storage account.
  56. /// </summary>
  57. public static readonly string DefaultAccountSharedKeyConfigurationString = "AccountSharedKey";
  58. /// <summary>
  59. /// The default configuration string in configuration files for setting the UsePathStyleUris option.
  60. /// </summary>
  61. public static readonly string DefaultUsePathStyleUrisConfigurationString = "UsePathStyleUris";
  62. /// <summary>
  63. /// The default prefix string in application config and Web.config files to indicate that this setting should be looked up
  64. /// in the fabric's configuration system.
  65. /// </summary>
  66. public static readonly string CSConfigStringPrefix = "CSConfigName";
  67. private bool? _usePathStyleUris;
  68. /// <summary>
  69. /// Constructor for creating account info objects.
  70. /// </summary>
  71. /// <param name="baseUri">The account's base URI.</param>
  72. /// <param name="usePathStyleUris">If true, path-style URIs (http://baseuri/accountname/containername/objectname) are used.
  73. /// If false host-style URIs (http://accountname.baseuri/containername/objectname) are used,
  74. /// where baseuri is the URI of the service..
  75. /// If null, the choice is made automatically: path-style URIs if host name part of base URI is an
  76. /// IP addres, host-style otherwise.</param>
  77. /// <param name="accountName">The account name.</param>
  78. /// <param name="base64Key">The account's shared key.</param>
  79. public StorageAccountInfo(Uri baseUri, bool? usePathStyleUris, string accountName, string base64Key)
  80. : this(baseUri, usePathStyleUris, accountName, base64Key, false)
  81. {
  82. }
  83. /// <summary>
  84. /// Constructor for creating account info objects.
  85. /// </summary>
  86. /// <param name="baseUri">The account's base URI.</param>
  87. /// <param name="usePathStyleUris">If true, path-style URIs (http://baseuri/accountname/containername/objectname) are used.
  88. /// If false host-style URIs (http://accountname.baseuri/containername/objectname) are used,
  89. /// where baseuri is the URI of the service.
  90. /// If null, the choice is made automatically: path-style URIs if host name part of base URI is an
  91. /// IP addres, host-style otherwise.</param>
  92. /// <param name="accountName">The account name.</param>
  93. /// <param name="base64Key">The account's shared key.</param>
  94. /// <param name="allowIncompleteSettings">true if it shall be allowed to only set parts of the StorageAccountInfo properties.</param>
  95. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
  96. public StorageAccountInfo(Uri baseUri, bool? usePathStyleUris, string accountName, string base64Key, bool allowIncompleteSettings)
  97. {
  98. if (baseUri == null && !allowIncompleteSettings)
  99. {
  100. throw new ArgumentNullException("baseUri");
  101. }
  102. if (string.IsNullOrEmpty(base64Key) && !allowIncompleteSettings)
  103. {
  104. throw new ArgumentNullException("base64Key");
  105. }
  106. if (baseUri != null)
  107. {
  108. string newAccountName = null;
  109. Uri newBaseUri = null;
  110. if (IsStandardStorageEndpoint(baseUri, out newAccountName, out newBaseUri)) {
  111. if (!string.IsNullOrEmpty(newAccountName) &&
  112. !string.IsNullOrEmpty(accountName) &&
  113. string.Compare(accountName, newAccountName, StringComparison.Ordinal) != 0)
  114. {
  115. throw new ArgumentException("The configured base URI " + baseUri.AbsoluteUri + " for the storage service is incorrect. " +
  116. "The configured account name " + accountName + " must match the account name " + newAccountName +
  117. " as specified in the storage service base URI." +
  118. GeneralAccountConfigurationExceptionString);
  119. }
  120. Debug.Assert((newBaseUri == null && newAccountName == null) || (newBaseUri != null && newAccountName != null));
  121. if (newAccountName != null && newBaseUri != null) {
  122. accountName = newAccountName;
  123. baseUri = newBaseUri;
  124. }
  125. }
  126. }
  127. if (string.IsNullOrEmpty(accountName) && !allowIncompleteSettings)
  128. {
  129. throw new ArgumentNullException("accountName");
  130. }
  131. if (!string.IsNullOrEmpty(accountName) && accountName.ToLowerInvariant() != accountName) {
  132. throw new ArgumentException("The account name must not contain upper-case letters. " +
  133. "The account name is the first part of the URL for accessing the storage services as presented to you by the portal or " +
  134. "the predefined storage account name when using the development storage tool. " +
  135. GeneralAccountConfigurationExceptionString);
  136. }
  137. BaseUri = baseUri;
  138. AccountName = accountName;
  139. Base64Key = base64Key;
  140. if (usePathStyleUris == null && baseUri == null && !allowIncompleteSettings) {
  141. throw new ArgumentException("Cannot determine setting from empty URI.");
  142. }
  143. else if (usePathStyleUris == null)
  144. {
  145. if (baseUri != null)
  146. {
  147. _usePathStyleUris = Utilities.StringIsIPAddress(baseUri.Host);
  148. }
  149. else
  150. {
  151. _usePathStyleUris = null;
  152. }
  153. }
  154. else
  155. {
  156. UsePathStyleUris = usePathStyleUris.Value;
  157. }
  158. }
  159. /// <summary>
  160. /// The base URI of the account.
  161. /// </summary>
  162. public Uri BaseUri
  163. {
  164. get;
  165. set;
  166. }
  167. /// <summary>
  168. /// The account name.
  169. /// </summary>
  170. public string AccountName
  171. {
  172. get;
  173. set;
  174. }
  175. /// <summary>
  176. /// The account's key.
  177. /// </summary>
  178. public string Base64Key
  179. {
  180. get;
  181. set;
  182. }
  183. /// <summary>
  184. /// If set, returns the UsePathStyleUris properties. If the property has not been explicitly set,
  185. /// the implementation tries to derive the correct value from the base URI.
  186. /// </summary>
  187. public bool UsePathStyleUris
  188. {
  189. get
  190. {
  191. if (_usePathStyleUris == null)
  192. {
  193. if (BaseUri == null)
  194. {
  195. return false;
  196. }
  197. else
  198. {
  199. return Utilities.StringIsIPAddress(BaseUri.Host);
  200. }
  201. }
  202. else
  203. {
  204. return _usePathStyleUris.Value;
  205. }
  206. }
  207. set {
  208. _usePathStyleUris = value;
  209. }
  210. }
  211. /// <summary>
  212. /// Retrieves account settings for the queue service from the default settings.
  213. /// </summary>
  214. public static StorageAccountInfo GetDefaultQueueStorageAccountFromConfiguration(bool allowIncompleteSettings)
  215. {
  216. return GetAccountInfoFromConfiguration(DefaultQueueStorageEndpointConfigurationString, allowIncompleteSettings);
  217. }
  218. /// <summary>
  219. /// Retrieves account settings for the queue service from the default settings.
  220. /// Throws an exception in case of incomplete settings.
  221. /// </summary>
  222. public static StorageAccountInfo GetDefaultQueueStorageAccountFromConfiguration()
  223. {
  224. return GetAccountInfoFromConfiguration(DefaultQueueStorageEndpointConfigurationString, false);
  225. }
  226. /// <summary>
  227. /// Retrieves account settings for the table service from the default settings.
  228. /// </summary>
  229. public static StorageAccountInfo GetDefaultTableStorageAccountFromConfiguration(bool allowIncompleteSettings)
  230. {
  231. return GetAccountInfoFromConfiguration(DefaultTableStorageEndpointConfigurationString, allowIncompleteSettings);
  232. }
  233. /// <summary>
  234. /// Retrieves account settings for the table service from the default settings.
  235. /// Throws an exception in case of incomplete settings.
  236. /// </summary>
  237. public static StorageAccountInfo GetDefaultTableStorageAccountFromConfiguration()
  238. {
  239. return GetAccountInfoFromConfiguration(DefaultTableStorageEndpointConfigurationString, false);
  240. }
  241. /// <summary>
  242. /// Retrieves account settings for the blob service from the default settings.
  243. /// </summary>
  244. public static StorageAccountInfo GetDefaultBlobStorageAccountFromConfiguration(bool allowIncompleteSettings)
  245. {
  246. return GetAccountInfoFromConfiguration(DefaultBlobStorageEndpointConfigurationString, allowIncompleteSettings);
  247. }
  248. /// <summary>
  249. /// Retrieves account settings for the blob service from the default settings.
  250. /// Throws an exception in case of incomplete settings.
  251. /// </summary>
  252. public static StorageAccountInfo GetDefaultBlobStorageAccountFromConfiguration()
  253. {
  254. return GetAccountInfoFromConfiguration(DefaultBlobStorageEndpointConfigurationString, false);
  255. }
  256. /// <summary>
  257. /// Gets settings from default configuration names except for the endpoint configuration string.
  258. /// </summary>
  259. public static StorageAccountInfo GetAccountInfoFromConfiguration(string endpointConfiguration, bool allowIncompleteSettings)
  260. {
  261. return GetAccountInfoFromConfiguration(DefaultAccountNameConfigurationString,
  262. DefaultAccountSharedKeyConfigurationString,
  263. endpointConfiguration,
  264. DefaultUsePathStyleUrisConfigurationString,
  265. allowIncompleteSettings);
  266. }
  267. /// <summary>
  268. /// Gets settings from default configuration names except for the endpoint configuration string. Throws an exception
  269. /// in the case of incomplete settings.
  270. /// </summary>
  271. public static StorageAccountInfo GetAccountInfoFromConfiguration(string endpointConfiguration)
  272. {
  273. return GetAccountInfoFromConfiguration(DefaultAccountNameConfigurationString,
  274. DefaultAccountSharedKeyConfigurationString,
  275. endpointConfiguration,
  276. DefaultUsePathStyleUrisConfigurationString,
  277. false);
  278. }
  279. /// <summary>
  280. /// Gets a configuration setting from application settings in the Web.config or App.config file.
  281. /// When running in a hosted environment, configuration settings are read from .cscfg
  282. /// files.
  283. /// </summary>
  284. public static string GetConfigurationSetting(string configurationSetting, string defaultValue, bool throwIfNull)
  285. {
  286. if (string.IsNullOrEmpty(configurationSetting))
  287. {
  288. throw new ArgumentException("configurationSetting cannot be empty or null", "configurationSetting");
  289. }
  290. string ret = null;
  291. // first, try to read from appsettings
  292. ret = TryGetAppSetting(configurationSetting);
  293. // settings in the csc file overload settings in Web.config
  294. if (RoleManager.IsRoleManagerRunning)
  295. {
  296. string cscRet = TryGetConfigurationSetting(configurationSetting);
  297. if (!string.IsNullOrEmpty(cscRet))
  298. {
  299. ret = cscRet;
  300. }
  301. // if there is a csc config name in the app settings, this config name even overloads the
  302. // setting we have right now
  303. string refWebRet = TryGetAppSetting(StorageAccountInfo.CSConfigStringPrefix + configurationSetting);
  304. if (!string.IsNullOrEmpty(refWebRet))
  305. {
  306. cscRet = TryGetConfigurationSetting(refWebRet);
  307. if (!string.IsNullOrEmpty(cscRet))
  308. {
  309. ret = cscRet;
  310. }
  311. }
  312. }
  313. // if we could not retrieve any configuration string set return value to the default value
  314. if (string.IsNullOrEmpty(ret) && defaultValue != null)
  315. {
  316. ret = defaultValue;
  317. }
  318. if (string.IsNullOrEmpty(ret) && throwIfNull)
  319. {
  320. throw new ConfigurationErrorsException(
  321. string.Format(CultureInfo.InvariantCulture, "Cannot find configuration string {0}.", configurationSetting));
  322. }
  323. return ret;
  324. }
  325. /// <summary>
  326. /// Retrieves account information settings from configuration settings. First, the implementation checks for
  327. /// settings in an application config section of an app.config or Web.config file. These values are overwritten
  328. /// if the same settings appear in a .csdef file.
  329. /// The implementation also supports indirect settings. In this case, indirect settings overwrite all other settings.
  330. /// </summary>
  331. /// <param name="accountNameConfiguration">Configuration string for the account name.</param>
  332. /// <param name="accountSharedKeyConfiguration">Configuration string for the key.</param>
  333. /// <param name="endpointConfiguration">Configuration string for the endpoint.</param>
  334. /// <param name="usePathStyleUrisConfiguration">Configuration string for the path style.</param>
  335. /// <param name="allowIncompleteSettings">If false, an exception is thrown if not all settings are available.</param>
  336. /// <returns>StorageAccountInfo object containing the retrieved settings.</returns>
  337. public static StorageAccountInfo GetAccountInfoFromConfiguration(string accountNameConfiguration,
  338. string accountSharedKeyConfiguration,
  339. string endpointConfiguration,
  340. string usePathStyleUrisConfiguration,
  341. bool allowIncompleteSettings)
  342. {
  343. if (string.IsNullOrEmpty(endpointConfiguration))
  344. {
  345. throw new ArgumentException("Endpoint configuration is missing", "endpointConfiguration");
  346. }
  347. string endpoint = null;
  348. string name = null;
  349. string key = null;
  350. string pathStyle = null;
  351. name = TryGetAppSetting(accountNameConfiguration);
  352. key = TryGetAppSetting(accountSharedKeyConfiguration);
  353. endpoint = TryGetAppSetting(endpointConfiguration);
  354. pathStyle = TryGetAppSetting(usePathStyleUrisConfiguration);
  355. // settings in the csc file overload settings in Web.config
  356. if (RoleManager.IsRoleManagerRunning)
  357. {
  358. // get config settings from the csc file
  359. string cscName = TryGetConfigurationSetting(accountNameConfiguration);
  360. if (!string.IsNullOrEmpty(cscName))
  361. {
  362. name = cscName;
  363. }
  364. string cscKey = TryGetConfigurationSetting(accountSharedKeyConfiguration);
  365. if (!string.IsNullOrEmpty(cscKey))
  366. {
  367. key = cscKey;
  368. }
  369. string cscEndpoint = TryGetConfigurationSetting(endpointConfiguration);
  370. if (!string.IsNullOrEmpty(cscEndpoint))
  371. {
  372. endpoint = cscEndpoint;
  373. }
  374. string cscPathStyle = TryGetConfigurationSetting(usePathStyleUrisConfiguration);
  375. if (!string.IsNullOrEmpty(cscPathStyle))
  376. {
  377. pathStyle = cscPathStyle;
  378. }
  379. // the Web.config can have references to csc setting strings
  380. // these count event stronger than the direct settings in the csc file
  381. string refWebName = TryGetAppSetting(CSConfigStringPrefix + accountNameConfiguration);
  382. if (!string.IsNullOrEmpty(refWebName))
  383. {
  384. cscName = TryGetConfigurationSetting(refWebName);
  385. if (!string.IsNullOrEmpty(cscName))
  386. {
  387. name = cscName;
  388. }
  389. }
  390. string refWebKey = TryGetAppSetting(CSConfigStringPrefix + accountSharedKeyConfiguration);
  391. if (!string.IsNullOrEmpty(refWebKey))
  392. {
  393. cscKey = TryGetConfigurationSetting(refWebKey);
  394. if (!string.IsNullOrEmpty(cscKey))
  395. {
  396. key = cscKey;
  397. }
  398. }
  399. string refWebEndpoint = TryGetAppSetting(CSConfigStringPrefix + endpointConfiguration);
  400. if (!string.IsNullOrEmpty(refWebEndpoint))
  401. {
  402. cscEndpoint = TryGetConfigurationSetting(refWebEndpoint);
  403. if (!string.IsNullOrEmpty(cscEndpoint))
  404. {
  405. endpoint = cscEndpoint;
  406. }
  407. }
  408. string refWebPathStyle = TryGetAppSetting(CSConfigStringPrefix + usePathStyleUrisConfiguration);
  409. if (!string.IsNullOrEmpty(refWebPathStyle))
  410. {
  411. cscPathStyle = TryGetConfigurationSetting(refWebPathStyle);
  412. if (!string.IsNullOrEmpty(cscPathStyle))
  413. {
  414. pathStyle = cscPathStyle;
  415. }
  416. }
  417. }
  418. if (string.IsNullOrEmpty(key) && !allowIncompleteSettings)
  419. {
  420. throw new ArgumentException("No account key specified!");
  421. }
  422. if (string.IsNullOrEmpty(endpoint) && !allowIncompleteSettings)
  423. {
  424. throw new ArgumentException("No endpoint specified!");
  425. }
  426. if (string.IsNullOrEmpty(name))
  427. {
  428. // in this case let's try to derive the account name from the Uri
  429. string newAccountName = null;
  430. Uri newBaseUri = null;
  431. if (IsStandardStorageEndpoint(new Uri(endpoint), out newAccountName, out newBaseUri))
  432. {
  433. Debug.Assert((newAccountName != null && newBaseUri != null) || (newAccountName == null && newBaseUri == null));
  434. if (newAccountName != null && newBaseUri != null)
  435. {
  436. endpoint = newBaseUri.AbsoluteUri;
  437. name = newAccountName;
  438. }
  439. }
  440. if (string.IsNullOrEmpty(name) && !allowIncompleteSettings)
  441. {
  442. throw new ArgumentException("No account name specified.");
  443. }
  444. }
  445. bool? usePathStyleUris = null;
  446. if (!string.IsNullOrEmpty(pathStyle))
  447. {
  448. bool b;
  449. if (!bool.TryParse(pathStyle, out b))
  450. {
  451. throw new ConfigurationErrorsException("Cannot parse value of setting UsePathStyleUris as a boolean");
  452. }
  453. usePathStyleUris = b;
  454. }
  455. Uri tmpBaseUri = null;
  456. if (!string.IsNullOrEmpty(endpoint))
  457. {
  458. tmpBaseUri = new Uri(endpoint);
  459. }
  460. return new StorageAccountInfo(tmpBaseUri, usePathStyleUris, name, key, allowIncompleteSettings);
  461. }
  462. /// <summary>
  463. /// Checks whether all essential properties of this object are set. Only then, the account info object
  464. /// should be used in ohter APIs of this library.
  465. /// </summary>
  466. /// <returns></returns>
  467. public bool IsCompleteSetting()
  468. {
  469. return BaseUri != null && Base64Key != null && AccountName != null;
  470. }
  471. /// <summary>
  472. /// Checks whether this StorageAccountInfo object is complete in the sense that all properties are set.
  473. /// </summary>
  474. public void CheckComplete()
  475. {
  476. if (!IsCompleteSetting())
  477. {
  478. throw new ConfigurationErrorsException("Account information incomplete!");
  479. }
  480. }
  481. #region Private methods
  482. private static string TryGetConfigurationSetting(string configName)
  483. {
  484. string ret = null;
  485. try
  486. {
  487. ret = RoleManager.GetConfigurationSetting(configName);
  488. }
  489. catch (RoleException)
  490. {
  491. return null;
  492. }
  493. return ret;
  494. }
  495. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
  496. Justification = "Make sure that nothing prevents us to read from the fabric's configuration envrionment.")]
  497. private static string TryGetAppSetting(string configName)
  498. {
  499. string ret = null;
  500. try
  501. {
  502. ret = ConfigurationSettings.AppSettings[configName];
  503. }
  504. // some exception happened when accessing the app settings section
  505. // most likely this is because there is no app setting file
  506. // we assume that this is because there is no app settings file; this is not an error
  507. // and explicitly all exceptions are captured here
  508. catch (Exception)
  509. {
  510. return null;
  511. }
  512. return ret;
  513. }
  514. private static string GeneralAccountConfigurationExceptionString {
  515. get {
  516. return "If the portal defines http://test.blob.core.windows.net as your blob storage endpoint, the string \"test\" " +
  517. "is your account name, and you can specify http://blob.core.windows.net as the BlobStorageEndpoint in your " +
  518. "service's configuration file(s).";
  519. }
  520. }
  521. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
  522. private static bool IsStandardStorageEndpoint(Uri baseUri, out string newAccountName, out Uri newBaseUri) {
  523. if (baseUri == null) {
  524. throw new ArgumentNullException("baseUri");
  525. }
  526. newAccountName = null;
  527. newBaseUri = null;
  528. string host = baseUri.Host;
  529. if (string.IsNullOrEmpty(host)) {
  530. throw new ArgumentException("The host part of the Uri " + baseUri.AbsoluteUri + " must not be null or empty.");
  531. }
  532. if (host != host.ToLowerInvariant()) {
  533. throw new ArgumentException("The specified host string " + host + " must not contain upper-case letters.");
  534. }
  535. string suffix = null;
  536. if (host.EndsWith(StorageHttpConstants.StandardPortalEndpoints.TableStorageEndpoint, StringComparison.Ordinal)) {
  537. suffix = StorageHttpConstants.StandardPortalEndpoints.TableStorageEndpoint;
  538. }
  539. if (host.EndsWith(StorageHttpConstants.StandardPortalEndpoints.BlobStorageEndpoint, StringComparison.Ordinal))
  540. {
  541. suffix = StorageHttpConstants.StandardPortalEndpoints.BlobStorageEndpoint;
  542. }
  543. if (host.EndsWith(StorageHttpConstants.StandardPortalEndpoints.QueueStorageEndpoint, StringComparison.Ordinal))
  544. {
  545. suffix = StorageHttpConstants.StandardPortalEndpoints.QueueStorageEndpoint;
  546. }
  547. // a URL as presented on the portal was specified, lets find out whether it is in the correct format
  548. if (suffix != null) {
  549. int index = host.IndexOf(suffix, StringComparison.Ordinal);
  550. Debug.Assert(index != -1);
  551. if (index > 0) {
  552. string first = host.Substring(0, index);
  553. Debug.Assert(!string.IsNullOrEmpty(first));
  554. if (first[first.Length-1] != StorageHttpConstants.ConstChars.Dot[0]) {
  555. return false;
  556. }
  557. first = first.Substring(0, first.Length - 1);
  558. if (string.IsNullOrEmpty(first)) {
  559. throw new ArgumentException("The configured base URI " + baseUri.AbsoluteUri + " for the storage service is incorrect. " +
  560. GeneralAccountConfigurationExceptionString);
  561. }
  562. if (first.Contains(StorageHttpConstants.ConstChars.Dot)) {
  563. throw new ArgumentException("The configured base URI " + baseUri.AbsoluteUri + " for the storage service is incorrect. " +
  564. GeneralAccountConfigurationExceptionString);
  565. }
  566. newAccountName = first;
  567. newBaseUri = new Uri(baseUri.Scheme + Uri.SchemeDelimiter + suffix + baseUri.PathAndQuery);
  568. }
  569. return true;
  570. }
  571. return false;
  572. }
  573. #endregion
  574. }
  575. }