MongoUrlBuilder.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. /* Copyright 2010-2017 MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Linq;
  18. using System.Net;
  19. using System.Text;
  20. using System.Text.RegularExpressions;
  21. using System.Threading;
  22. using MongoDB.Bson;
  23. using MongoDB.Bson.IO;
  24. using MongoDB.Driver.Core.Clusters;
  25. using MongoDB.Driver.Core.Configuration;
  26. using MongoDB.Driver.Core.Misc;
  27. using MongoDB.Shared;
  28. namespace MongoDB.Driver
  29. {
  30. /// <summary>
  31. /// Represents URL-style connection strings.
  32. /// </summary>
  33. #if NET45
  34. [Serializable]
  35. #endif
  36. public class MongoUrlBuilder
  37. {
  38. // private fields
  39. private string _applicationName;
  40. private string _authenticationMechanism;
  41. private Dictionary<string, string> _authenticationMechanismProperties;
  42. private string _authenticationSource;
  43. private ConnectionMode _connectionMode;
  44. private TimeSpan _connectTimeout;
  45. private string _databaseName;
  46. private bool? _fsync;
  47. private GuidRepresentation _guidRepresentation;
  48. private TimeSpan _heartbeatInterval;
  49. private TimeSpan _heartbeatTimeout;
  50. private bool _ipv6;
  51. private bool? _journal;
  52. private TimeSpan _localThreshold;
  53. private TimeSpan _maxConnectionIdleTime;
  54. private TimeSpan _maxConnectionLifeTime;
  55. private int _maxConnectionPoolSize;
  56. private int _minConnectionPoolSize;
  57. private string _password;
  58. private ReadConcernLevel? _readConcernLevel;
  59. private ReadPreference _readPreference;
  60. private string _replicaSetName;
  61. private IEnumerable<MongoServerAddress> _servers;
  62. private TimeSpan _serverSelectionTimeout;
  63. private TimeSpan _socketTimeout;
  64. private string _username;
  65. private bool _useSsl;
  66. private bool _verifySslCertificate;
  67. private WriteConcern.WValue _w;
  68. private double _waitQueueMultiple;
  69. private int _waitQueueSize;
  70. private TimeSpan _waitQueueTimeout;
  71. private TimeSpan? _wTimeout;
  72. // constructors
  73. /// <summary>
  74. /// Creates a new instance of MongoUrlBuilder.
  75. /// </summary>
  76. public MongoUrlBuilder()
  77. {
  78. _applicationName = null;
  79. _authenticationMechanism = MongoDefaults.AuthenticationMechanism;
  80. _authenticationMechanismProperties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
  81. _authenticationSource = null;
  82. _connectionMode = ConnectionMode.Automatic;
  83. _connectTimeout = MongoDefaults.ConnectTimeout;
  84. _databaseName = null;
  85. _fsync = null;
  86. _guidRepresentation = MongoDefaults.GuidRepresentation;
  87. _heartbeatInterval = ServerSettings.DefaultHeartbeatInterval;
  88. _heartbeatTimeout = ServerSettings.DefaultHeartbeatTimeout;
  89. _ipv6 = false;
  90. _journal = null;
  91. _maxConnectionIdleTime = MongoDefaults.MaxConnectionIdleTime;
  92. _maxConnectionLifeTime = MongoDefaults.MaxConnectionLifeTime;
  93. _maxConnectionPoolSize = MongoDefaults.MaxConnectionPoolSize;
  94. _minConnectionPoolSize = MongoDefaults.MinConnectionPoolSize;
  95. _password = null;
  96. _readConcernLevel = null;
  97. _readPreference = null;
  98. _replicaSetName = null;
  99. _localThreshold = MongoDefaults.LocalThreshold;
  100. _servers = new[] { new MongoServerAddress("localhost", 27017) };
  101. _serverSelectionTimeout = MongoDefaults.ServerSelectionTimeout;
  102. _socketTimeout = MongoDefaults.SocketTimeout;
  103. _username = null;
  104. _useSsl = false;
  105. _verifySslCertificate = true;
  106. _w = null;
  107. _waitQueueMultiple = MongoDefaults.WaitQueueMultiple;
  108. _waitQueueSize = MongoDefaults.WaitQueueSize;
  109. _waitQueueTimeout = MongoDefaults.WaitQueueTimeout;
  110. _wTimeout = null;
  111. }
  112. /// <summary>
  113. /// Creates a new instance of MongoUrlBuilder.
  114. /// </summary>
  115. /// <param name="url">The initial settings.</param>
  116. public MongoUrlBuilder(string url)
  117. : this()
  118. {
  119. Parse(url);
  120. }
  121. // public properties
  122. /// <summary>
  123. /// Gets or sets the application name.
  124. /// </summary>
  125. public string ApplicationName
  126. {
  127. get { return _applicationName; }
  128. set { _applicationName = ApplicationNameHelper.EnsureApplicationNameIsValid(value, nameof(value)); }
  129. }
  130. /// <summary>
  131. /// Gets or sets the authentication mechanism.
  132. /// </summary>
  133. public string AuthenticationMechanism
  134. {
  135. get { return _authenticationMechanism; }
  136. set { _authenticationMechanism = value; }
  137. }
  138. /// <summary>
  139. /// Gets or sets the authentication mechanism properties.
  140. /// </summary>
  141. public IEnumerable<KeyValuePair<string, string>> AuthenticationMechanismProperties
  142. {
  143. get { return _authenticationMechanismProperties; }
  144. set
  145. {
  146. if (value == null)
  147. {
  148. throw new ArgumentNullException("value");
  149. }
  150. _authenticationMechanismProperties = value.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
  151. }
  152. }
  153. /// <summary>
  154. /// Gets or sets the authentication source.
  155. /// </summary>
  156. public string AuthenticationSource
  157. {
  158. get { return _authenticationSource; }
  159. set { _authenticationSource = value; }
  160. }
  161. /// <summary>
  162. /// Gets the actual wait queue size (either WaitQueueSize or WaitQueueMultiple x MaxConnectionPoolSize).
  163. /// </summary>
  164. public int ComputedWaitQueueSize
  165. {
  166. get
  167. {
  168. if (_waitQueueMultiple == 0.0)
  169. {
  170. return _waitQueueSize;
  171. }
  172. else
  173. {
  174. return (int)(_waitQueueMultiple * _maxConnectionPoolSize);
  175. }
  176. }
  177. }
  178. /// <summary>
  179. /// Gets or sets the connection mode.
  180. /// </summary>
  181. public ConnectionMode ConnectionMode
  182. {
  183. get { return _connectionMode; }
  184. set { _connectionMode = value; }
  185. }
  186. /// <summary>
  187. /// Gets or sets the connect timeout.
  188. /// </summary>
  189. public TimeSpan ConnectTimeout
  190. {
  191. get { return _connectTimeout; }
  192. set
  193. {
  194. if (value < TimeSpan.Zero)
  195. {
  196. throw new ArgumentOutOfRangeException("value", "ConnectTimeout must be greater than or equal to zero.");
  197. }
  198. _connectTimeout = value;
  199. }
  200. }
  201. /// <summary>
  202. /// Gets or sets the optional database name.
  203. /// </summary>
  204. public string DatabaseName
  205. {
  206. get { return _databaseName; }
  207. set { _databaseName = value; }
  208. }
  209. /// <summary>
  210. /// Gets or sets the FSync component of the write concern.
  211. /// </summary>
  212. public bool? FSync
  213. {
  214. get { return _fsync; }
  215. set
  216. {
  217. _fsync = value;
  218. }
  219. }
  220. /// <summary>
  221. /// Gets or sets the representation to use for Guids.
  222. /// </summary>
  223. public GuidRepresentation GuidRepresentation
  224. {
  225. get { return _guidRepresentation; }
  226. set { _guidRepresentation = value; }
  227. }
  228. /// <summary>
  229. /// Gets or sets the heartbeat interval.
  230. /// </summary>
  231. public TimeSpan HeartbeatInterval
  232. {
  233. get { return _heartbeatInterval; }
  234. set
  235. {
  236. if (value < TimeSpan.Zero)
  237. {
  238. throw new ArgumentOutOfRangeException("value", "HeartbeatInterval must be greater than or equal to zero.");
  239. }
  240. _heartbeatInterval = value;
  241. }
  242. }
  243. /// <summary>
  244. /// Gets or sets the heartbeat timeout.
  245. /// </summary>
  246. public TimeSpan HeartbeatTimeout
  247. {
  248. get { return _heartbeatTimeout; }
  249. set
  250. {
  251. if (value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)
  252. {
  253. throw new ArgumentOutOfRangeException("value", "HeartbeatTimeout must be greater than or equal to zero.");
  254. }
  255. _heartbeatTimeout = value;
  256. }
  257. }
  258. /// <summary>
  259. /// Gets or sets a value indicating whether to use IPv6.
  260. /// </summary>
  261. public bool IPv6
  262. {
  263. get { return _ipv6; }
  264. set { _ipv6 = value; }
  265. }
  266. /// <summary>
  267. /// Gets or sets the Journal component of the write concern.
  268. /// </summary>
  269. public bool? Journal
  270. {
  271. get { return _journal; }
  272. set
  273. {
  274. _journal = value;
  275. }
  276. }
  277. /// <summary>
  278. /// Gets or sets the local threshold.
  279. /// </summary>
  280. public TimeSpan LocalThreshold
  281. {
  282. get { return _localThreshold; }
  283. set
  284. {
  285. if (value < TimeSpan.Zero)
  286. {
  287. throw new ArgumentOutOfRangeException("value", "LocalThreshold must be greater than or equal to zero.");
  288. }
  289. _localThreshold = value;
  290. }
  291. }
  292. /// <summary>
  293. /// Gets or sets the max connection idle time.
  294. /// </summary>
  295. public TimeSpan MaxConnectionIdleTime
  296. {
  297. get { return _maxConnectionIdleTime; }
  298. set
  299. {
  300. if (value < TimeSpan.Zero)
  301. {
  302. throw new ArgumentOutOfRangeException("value", "MaxConnectionIdleTime must be greater than or equal to zero.");
  303. }
  304. _maxConnectionIdleTime = value;
  305. }
  306. }
  307. /// <summary>
  308. /// Gets or sets the max connection life time.
  309. /// </summary>
  310. public TimeSpan MaxConnectionLifeTime
  311. {
  312. get { return _maxConnectionLifeTime; }
  313. set
  314. {
  315. if (value < TimeSpan.Zero)
  316. {
  317. throw new ArgumentOutOfRangeException("value", "MaxConnectionLifeTime must be greater than or equal to zero.");
  318. }
  319. _maxConnectionLifeTime = value;
  320. }
  321. }
  322. /// <summary>
  323. /// Gets or sets the max connection pool size.
  324. /// </summary>
  325. public int MaxConnectionPoolSize
  326. {
  327. get { return _maxConnectionPoolSize; }
  328. set
  329. {
  330. if (value <= 0)
  331. {
  332. throw new ArgumentOutOfRangeException("value", "MaxConnectionPoolSize must be greater than zero.");
  333. }
  334. _maxConnectionPoolSize = value;
  335. }
  336. }
  337. /// <summary>
  338. /// Gets or sets the min connection pool size.
  339. /// </summary>
  340. public int MinConnectionPoolSize
  341. {
  342. get { return _minConnectionPoolSize; }
  343. set
  344. {
  345. if (value < 0)
  346. {
  347. throw new ArgumentOutOfRangeException("value", "MinConnectionPoolSize must be greater than or equal to zero.");
  348. }
  349. _minConnectionPoolSize = value;
  350. }
  351. }
  352. /// <summary>
  353. /// Gets or sets the password.
  354. /// </summary>
  355. public string Password
  356. {
  357. get { return _password; }
  358. set { _password = value; }
  359. }
  360. /// <summary>
  361. /// Gets or sets the read concern level.
  362. /// </summary>
  363. public ReadConcernLevel? ReadConcernLevel
  364. {
  365. get { return _readConcernLevel; }
  366. set { _readConcernLevel = value; }
  367. }
  368. /// <summary>
  369. /// Gets or sets the read preference.
  370. /// </summary>
  371. public ReadPreference ReadPreference
  372. {
  373. get
  374. {
  375. if (_readPreference != null)
  376. {
  377. return _readPreference;
  378. }
  379. else
  380. {
  381. return null;
  382. }
  383. }
  384. set { _readPreference = value; }
  385. }
  386. /// <summary>
  387. /// Gets or sets the name of the replica set.
  388. /// </summary>
  389. public string ReplicaSetName
  390. {
  391. get { return _replicaSetName; }
  392. set { _replicaSetName = value; }
  393. }
  394. /// <summary>
  395. /// Gets or sets the address of the server (see also Servers if using more than one address).
  396. /// </summary>
  397. public MongoServerAddress Server
  398. {
  399. get { return (_servers == null) ? null : _servers.Single(); }
  400. set { _servers = (value == null) ? null : new[] { value }; }
  401. }
  402. /// <summary>
  403. /// Gets or sets the list of server addresses (see also Server if using only one address).
  404. /// </summary>
  405. public IEnumerable<MongoServerAddress> Servers
  406. {
  407. get { return _servers; }
  408. set { _servers = value; }
  409. }
  410. /// <summary>
  411. /// Gets or sets the server selection timeout.
  412. /// </summary>
  413. public TimeSpan ServerSelectionTimeout
  414. {
  415. get { return _serverSelectionTimeout; }
  416. set
  417. {
  418. if (value < TimeSpan.Zero)
  419. {
  420. throw new ArgumentOutOfRangeException("value", "ServerSelectionTimeout must be greater than or equal to zero.");
  421. }
  422. _serverSelectionTimeout = value;
  423. }
  424. }
  425. /// <summary>
  426. /// Gets or sets the socket timeout.
  427. /// </summary>
  428. public TimeSpan SocketTimeout
  429. {
  430. get { return _socketTimeout; }
  431. set
  432. {
  433. if (value < TimeSpan.Zero)
  434. {
  435. throw new ArgumentOutOfRangeException("value", "SocketTimeout must be greater than or equal to zero.");
  436. }
  437. _socketTimeout = value;
  438. }
  439. }
  440. /// <summary>
  441. /// Gets or sets the username.
  442. /// </summary>
  443. public string Username
  444. {
  445. get { return _username; }
  446. set { _username = value; }
  447. }
  448. /// <summary>
  449. /// Gets or sets a value indicating whether to use SSL.
  450. /// </summary>
  451. public bool UseSsl
  452. {
  453. get { return _useSsl; }
  454. set { _useSsl = value; }
  455. }
  456. /// <summary>
  457. /// Gets or sets a value indicating whether to verify an SSL certificate.
  458. /// </summary>
  459. public bool VerifySslCertificate
  460. {
  461. get { return _verifySslCertificate; }
  462. set { _verifySslCertificate = value; }
  463. }
  464. /// <summary>
  465. /// Gets or sets the W component of the write concern.
  466. /// </summary>
  467. public WriteConcern.WValue W
  468. {
  469. get { return _w; }
  470. set
  471. {
  472. _w = value;
  473. }
  474. }
  475. /// <summary>
  476. /// Gets or sets the wait queue multiple (the actual wait queue size will be WaitQueueMultiple x MaxConnectionPoolSize).
  477. /// </summary>
  478. public double WaitQueueMultiple
  479. {
  480. get { return _waitQueueMultiple; }
  481. set
  482. {
  483. if (value <= 0.0)
  484. {
  485. throw new ArgumentOutOfRangeException("value", "WaitQueueMultiple must be greater than zero.");
  486. }
  487. _waitQueueMultiple = value;
  488. _waitQueueSize = 0;
  489. }
  490. }
  491. /// <summary>
  492. /// Gets or sets the wait queue size.
  493. /// </summary>
  494. public int WaitQueueSize
  495. {
  496. get { return _waitQueueSize; }
  497. set
  498. {
  499. if (value <= 0)
  500. {
  501. throw new ArgumentOutOfRangeException("value", "WaitQueueSize must be greater than zero.");
  502. }
  503. _waitQueueSize = value;
  504. _waitQueueMultiple = 0.0;
  505. }
  506. }
  507. /// <summary>
  508. /// Gets or sets the wait queue timeout.
  509. /// </summary>
  510. public TimeSpan WaitQueueTimeout
  511. {
  512. get { return _waitQueueTimeout; }
  513. set
  514. {
  515. if (value < TimeSpan.Zero)
  516. {
  517. throw new ArgumentOutOfRangeException("value", "WaitQueueTimeout must be greater than or equal to zero.");
  518. }
  519. _waitQueueTimeout = value;
  520. }
  521. }
  522. /// <summary>
  523. /// Gets or sets the WTimeout component of the write concern.
  524. /// </summary>
  525. public TimeSpan? WTimeout
  526. {
  527. get { return _wTimeout; }
  528. set
  529. {
  530. if (value != null && value.Value < TimeSpan.Zero)
  531. {
  532. throw new ArgumentOutOfRangeException("value", "WTimeout must be greater than or equal to zero.");
  533. }
  534. _wTimeout = value;
  535. }
  536. }
  537. // public methods
  538. /// <summary>
  539. /// Returns a WriteConcern value based on this instance's settings and a default enabled value.
  540. /// </summary>
  541. /// <param name="enabledDefault">The default enabled value.</param>
  542. /// <returns>A WriteConcern.</returns>
  543. public WriteConcern GetWriteConcern(bool enabledDefault)
  544. {
  545. if (_w == null && !_wTimeout.HasValue && !_fsync.HasValue && !_journal.HasValue)
  546. {
  547. return enabledDefault ? WriteConcern.Acknowledged : WriteConcern.Unacknowledged;
  548. }
  549. return new WriteConcern(_w, _wTimeout, _fsync, _journal);
  550. }
  551. /// <summary>
  552. /// Parses a URL and sets all settings to match the URL.
  553. /// </summary>
  554. /// <param name="url">The URL.</param>
  555. public void Parse(string url)
  556. {
  557. var connectionString = new ConnectionString(url);
  558. _applicationName = connectionString.ApplicationName;
  559. _authenticationMechanism = connectionString.AuthMechanism;
  560. _authenticationMechanismProperties = connectionString.AuthMechanismProperties.ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
  561. _authenticationSource = connectionString.AuthSource;
  562. switch (connectionString.Connect)
  563. {
  564. case ClusterConnectionMode.Direct:
  565. _connectionMode = Driver.ConnectionMode.Direct;
  566. break;
  567. case ClusterConnectionMode.ReplicaSet:
  568. _connectionMode = Driver.ConnectionMode.ReplicaSet;
  569. break;
  570. case ClusterConnectionMode.Sharded:
  571. _connectionMode = Driver.ConnectionMode.ShardRouter;
  572. break;
  573. case ClusterConnectionMode.Standalone:
  574. _connectionMode = Driver.ConnectionMode.Standalone;
  575. break;
  576. default:
  577. _connectionMode = Driver.ConnectionMode.Automatic;
  578. break;
  579. }
  580. _connectTimeout = connectionString.ConnectTimeout.GetValueOrDefault(MongoDefaults.ConnectTimeout);
  581. _databaseName = connectionString.DatabaseName;
  582. _fsync = connectionString.FSync;
  583. _guidRepresentation = connectionString.UuidRepresentation.GetValueOrDefault(MongoDefaults.GuidRepresentation);
  584. _heartbeatInterval = connectionString.HeartbeatInterval ?? ServerSettings.DefaultHeartbeatInterval;
  585. _heartbeatTimeout = connectionString.HeartbeatTimeout ?? ServerSettings.DefaultHeartbeatTimeout;
  586. _ipv6 = connectionString.Ipv6.GetValueOrDefault(false);
  587. _journal = connectionString.Journal;
  588. _maxConnectionIdleTime = connectionString.MaxIdleTime.GetValueOrDefault(MongoDefaults.MaxConnectionIdleTime);
  589. _maxConnectionLifeTime = connectionString.MaxLifeTime.GetValueOrDefault(MongoDefaults.MaxConnectionLifeTime);
  590. _maxConnectionPoolSize = connectionString.MaxPoolSize.GetValueOrDefault(MongoDefaults.MaxConnectionPoolSize);
  591. _minConnectionPoolSize = connectionString.MinPoolSize.GetValueOrDefault(MongoDefaults.MinConnectionPoolSize);
  592. _password = connectionString.Password;
  593. _readConcernLevel = connectionString.ReadConcernLevel;
  594. if (connectionString.ReadPreference.HasValue || connectionString.ReadPreferenceTags != null || connectionString.MaxStaleness.HasValue)
  595. {
  596. if (!connectionString.ReadPreference.HasValue)
  597. {
  598. throw new MongoConfigurationException("readPreference mode is required when using tag sets or max staleness.");
  599. }
  600. _readPreference = new ReadPreference(connectionString.ReadPreference.Value, connectionString.ReadPreferenceTags, connectionString.MaxStaleness);
  601. }
  602. _replicaSetName = connectionString.ReplicaSet;
  603. _localThreshold = connectionString.LocalThreshold.GetValueOrDefault(MongoDefaults.LocalThreshold);
  604. _servers = connectionString.Hosts.Select(endPoint =>
  605. {
  606. DnsEndPoint dnsEndPoint;
  607. IPEndPoint ipEndPoint;
  608. if ((dnsEndPoint = endPoint as DnsEndPoint) != null)
  609. {
  610. return new MongoServerAddress(dnsEndPoint.Host, dnsEndPoint.Port);
  611. }
  612. else if ((ipEndPoint = endPoint as IPEndPoint) != null)
  613. {
  614. var address = ipEndPoint.Address.ToString();
  615. if (ipEndPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
  616. {
  617. address = "[" + address + "]";
  618. }
  619. return new MongoServerAddress(address, ipEndPoint.Port);
  620. }
  621. else
  622. {
  623. throw new NotSupportedException("Only DnsEndPoint and IPEndPoints are supported in the connection string.");
  624. }
  625. });
  626. _serverSelectionTimeout = connectionString.ServerSelectionTimeout.GetValueOrDefault(MongoDefaults.ServerSelectionTimeout);
  627. _socketTimeout = connectionString.SocketTimeout.GetValueOrDefault(MongoDefaults.SocketTimeout);
  628. _username = connectionString.Username;
  629. _useSsl = connectionString.Ssl.GetValueOrDefault(false);
  630. _verifySslCertificate = connectionString.SslVerifyCertificate.GetValueOrDefault(true);
  631. _w = connectionString.W;
  632. if (connectionString.WaitQueueSize != null)
  633. {
  634. _waitQueueSize = connectionString.WaitQueueSize.Value;
  635. _waitQueueMultiple = 0.0;
  636. }
  637. else if (connectionString.WaitQueueMultiple != null)
  638. {
  639. _waitQueueMultiple = connectionString.WaitQueueMultiple.Value;
  640. _waitQueueSize = 0;
  641. }
  642. _waitQueueTimeout = connectionString.WaitQueueTimeout.GetValueOrDefault(MongoDefaults.WaitQueueTimeout);
  643. _wTimeout = connectionString.WTimeout;
  644. }
  645. /// <summary>
  646. /// Creates a new instance of MongoUrl based on the settings in this MongoUrlBuilder.
  647. /// </summary>
  648. /// <returns>A new instance of MongoUrl.</returns>
  649. public MongoUrl ToMongoUrl()
  650. {
  651. return MongoUrl.Create(ToString());
  652. }
  653. /// <summary>
  654. /// Returns the canonical URL based on the settings in this MongoUrlBuilder.
  655. /// </summary>
  656. /// <returns>The canonical URL.</returns>
  657. public override string ToString()
  658. {
  659. StringBuilder url = new StringBuilder();
  660. url.Append("mongodb://");
  661. if (!string.IsNullOrEmpty(_username))
  662. {
  663. url.Append(Uri.EscapeDataString(_username));
  664. if (_password != null)
  665. {
  666. url.AppendFormat(":{0}", Uri.EscapeDataString(_password));
  667. }
  668. url.Append("@");
  669. }
  670. else if (_password != null)
  671. {
  672. // this would be weird and we really shouldn't be here...
  673. url.AppendFormat(":{0}@", _password);
  674. }
  675. if (_servers != null)
  676. {
  677. bool firstServer = true;
  678. foreach (MongoServerAddress server in _servers)
  679. {
  680. if (!firstServer) { url.Append(","); }
  681. if (server.Port == 27017)
  682. {
  683. url.Append(server.Host);
  684. }
  685. else
  686. {
  687. url.AppendFormat("{0}:{1}", server.Host, server.Port);
  688. }
  689. firstServer = false;
  690. }
  691. }
  692. if (_databaseName != null)
  693. {
  694. url.Append("/");
  695. url.Append(_databaseName);
  696. }
  697. var query = new StringBuilder();
  698. if (_authenticationMechanism != null)
  699. {
  700. query.AppendFormat("authMechanism={0};", _authenticationMechanism);
  701. }
  702. if (_authenticationMechanismProperties.Any())
  703. {
  704. query.AppendFormat(
  705. "authMechanismProperties={0};",
  706. string.Join(",", _authenticationMechanismProperties
  707. .Select(x => string.Format("{0}:{1}", x.Key, x.Value)).ToArray()));
  708. }
  709. if (_authenticationSource != null)
  710. {
  711. query.AppendFormat("authSource={0};", _authenticationSource);
  712. }
  713. if (_applicationName != null)
  714. {
  715. query.AppendFormat("appname={0};", _applicationName);
  716. }
  717. if (_ipv6)
  718. {
  719. query.AppendFormat("ipv6=true;");
  720. }
  721. if (_useSsl)
  722. {
  723. query.AppendFormat("ssl=true;");
  724. }
  725. if (!_verifySslCertificate)
  726. {
  727. query.AppendFormat("sslVerifyCertificate=false;");
  728. }
  729. if (_connectionMode != ConnectionMode.Automatic)
  730. {
  731. query.AppendFormat("connect={0};", MongoUtils.ToCamelCase(_connectionMode.ToString()));
  732. }
  733. if (!string.IsNullOrEmpty(_replicaSetName))
  734. {
  735. query.AppendFormat("replicaSet={0};", _replicaSetName);
  736. }
  737. if (_readConcernLevel != null)
  738. {
  739. query.AppendFormat("readConcernLevel={0};", MongoUtils.ToCamelCase(_readConcernLevel.Value.ToString()));
  740. }
  741. if (_readPreference != null)
  742. {
  743. query.AppendFormat("readPreference={0};", MongoUtils.ToCamelCase(_readPreference.ReadPreferenceMode.ToString()));
  744. if (_readPreference.TagSets != null)
  745. {
  746. foreach (var tagSet in _readPreference.TagSets)
  747. {
  748. query.AppendFormat("readPreferenceTags={0};", string.Join(",", tagSet.Tags.Select(t => string.Format("{0}:{1}", t.Name, t.Value)).ToArray()));
  749. }
  750. }
  751. if (_readPreference.MaxStaleness.HasValue)
  752. {
  753. query.AppendFormat("maxStaleness={0};", FormatTimeSpan(_readPreference.MaxStaleness.Value));
  754. }
  755. }
  756. if (_fsync != null)
  757. {
  758. query.AppendFormat("fsync={0};", JsonConvert.ToString(_fsync.Value));
  759. }
  760. if (_journal != null)
  761. {
  762. query.AppendFormat("journal={0};", JsonConvert.ToString(_journal.Value));
  763. }
  764. if (_w != null)
  765. {
  766. query.AppendFormat("w={0};", _w);
  767. }
  768. if (_wTimeout != null)
  769. {
  770. query.AppendFormat("wtimeout={0};", FormatTimeSpan(_wTimeout.Value));
  771. }
  772. if (_connectTimeout != MongoDefaults.ConnectTimeout)
  773. {
  774. query.AppendFormat("connectTimeout={0};", FormatTimeSpan(_connectTimeout));
  775. }
  776. if (_heartbeatInterval != ServerSettings.DefaultHeartbeatInterval)
  777. {
  778. query.AppendFormat("heartbeatInterval={0};", FormatTimeSpan(_heartbeatInterval));
  779. }
  780. if (_heartbeatTimeout != ServerSettings.DefaultHeartbeatTimeout)
  781. {
  782. query.AppendFormat("heartbeatTimeout={0};", FormatTimeSpan(_heartbeatTimeout));
  783. }
  784. if (_maxConnectionIdleTime != MongoDefaults.MaxConnectionIdleTime)
  785. {
  786. query.AppendFormat("maxIdleTime={0};", FormatTimeSpan(_maxConnectionIdleTime));
  787. }
  788. if (_maxConnectionLifeTime != MongoDefaults.MaxConnectionLifeTime)
  789. {
  790. query.AppendFormat("maxLifeTime={0};", FormatTimeSpan(_maxConnectionLifeTime));
  791. }
  792. if (_maxConnectionPoolSize != MongoDefaults.MaxConnectionPoolSize)
  793. {
  794. query.AppendFormat("maxPoolSize={0};", _maxConnectionPoolSize);
  795. }
  796. if (_minConnectionPoolSize != MongoDefaults.MinConnectionPoolSize)
  797. {
  798. query.AppendFormat("minPoolSize={0};", _minConnectionPoolSize);
  799. }
  800. if (_localThreshold != MongoDefaults.LocalThreshold)
  801. {
  802. query.AppendFormat("localThreshold={0};", FormatTimeSpan(_localThreshold));
  803. }
  804. if (_serverSelectionTimeout != MongoDefaults.ServerSelectionTimeout)
  805. {
  806. query.AppendFormat("serverSelectionTimeout={0};", FormatTimeSpan(_serverSelectionTimeout));
  807. }
  808. if (_socketTimeout != MongoDefaults.SocketTimeout)
  809. {
  810. query.AppendFormat("socketTimeout={0};", FormatTimeSpan(_socketTimeout));
  811. }
  812. if (_waitQueueMultiple != 0.0 && _waitQueueMultiple != MongoDefaults.WaitQueueMultiple)
  813. {
  814. query.AppendFormat("waitQueueMultiple={0};", _waitQueueMultiple);
  815. }
  816. if (_waitQueueSize != 0 && _waitQueueSize != MongoDefaults.WaitQueueSize)
  817. {
  818. query.AppendFormat("waitQueueSize={0};", _waitQueueSize);
  819. }
  820. if (_waitQueueTimeout != MongoDefaults.WaitQueueTimeout)
  821. {
  822. query.AppendFormat("waitQueueTimeout={0};", FormatTimeSpan(WaitQueueTimeout));
  823. }
  824. if (_guidRepresentation != MongoDefaults.GuidRepresentation)
  825. {
  826. query.AppendFormat("uuidRepresentation={0};", (_guidRepresentation == GuidRepresentation.CSharpLegacy) ? "csharpLegacy" : MongoUtils.ToCamelCase(_guidRepresentation.ToString()));
  827. }
  828. if (query.Length != 0)
  829. {
  830. query.Length = query.Length - 1; // remove trailing ";"
  831. if (_databaseName == null)
  832. {
  833. url.Append("/");
  834. }
  835. url.Append("?");
  836. url.Append(query.ToString());
  837. }
  838. return url.ToString();
  839. }
  840. // private methods
  841. private bool AnyWriteConcernSettingsAreSet()
  842. {
  843. return _fsync != null || _journal != null || _w != null || _wTimeout != null;
  844. }
  845. private string FormatTimeSpan(TimeSpan value)
  846. {
  847. const int msInOneSecond = 1000; // milliseconds
  848. const int msInOneMinute = 60 * msInOneSecond;
  849. const int msInOneHour = 60 * msInOneMinute;
  850. var ms = (int)value.TotalMilliseconds;
  851. if ((ms % msInOneHour) == 0)
  852. {
  853. return string.Format("{0}h", ms / msInOneHour);
  854. }
  855. else if ((ms % msInOneMinute) == 0 && ms < msInOneHour)
  856. {
  857. return string.Format("{0}m", ms / msInOneMinute);
  858. }
  859. else if ((ms % msInOneSecond) == 0 && ms < msInOneMinute)
  860. {
  861. return string.Format("{0}s", ms / msInOneSecond);
  862. }
  863. else if (ms < 1000)
  864. {
  865. return string.Format("{0}ms", ms);
  866. }
  867. else
  868. {
  869. return value.ToString();
  870. }
  871. }
  872. }
  873. }