Просмотр исходного кода

更新mongo驱动到2.7,以支持MongoDB4.0,客户端需要加上NET452宏

tanghai 7 лет назад
Родитель
Сommit
2edb71b09d
100 измененных файлов с 14069 добавлено и 106 удалено
  1. 63 48
      Client-Server.sln
  2. 3 0
      Server/Hotfix/Server.Hotfix.csproj
  3. 3 3
      Server/Model/Server.Model.csproj
  4. 61 46
      Server/Server.sln
  5. 2 0
      Server/Server.sln.DotSettings.user
  6. 1 1
      Server/ThirdParty/Google.Protobuf/Google.Protobuf.csproj
  7. 84 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs
  8. 361 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Bson/IO/WrappingBsonWriter.cs
  9. 90 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Bson/Serialization/Serializers/ElementAppendingSerializer.cs
  10. 149 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Bson/Serialization/Serializers/ReadOnlyDictionaryInterfaceImplementerSerializer.cs
  11. 104 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamDocument.cs
  12. 76 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamDocumentCollectionNamespaceSerializer.cs
  13. 59 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamDocumentSerializer.cs
  14. 34 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamFullDocumentOptions.cs
  15. 44 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamOperationType.cs
  16. 74 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamOperationTypeSerializer.cs
  17. 87 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamUpdateDescription.cs
  18. 89 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamUpdateDescriptionSerializer.cs
  19. 88 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/SaslMapParser.cs
  20. 805 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/SaslPrepHelper.cs
  21. 129 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/ScramSha256Authenticator.cs
  22. 290 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/ScramShaAuthenticator.cs
  23. 175 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/Vendored/CryptographyHelpers.cs
  24. 172 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/Vendored/HashAlgorithmName.cs
  25. 337 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/Vendored/Rfc2898DeriveBytes.cs
  26. 74 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreServerSession.cs
  27. 137 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreServerSessionPool.cs
  28. 481 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreSession.cs
  29. 72 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreSessionHandle.cs
  30. 70 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreSessionOptions.cs
  31. 86 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreTransaction.cs
  32. 43 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreTransactionState.cs
  33. 36 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/ICoreServerSessionPool.cs
  34. 55 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/ICoreServerSesssion.cs
  35. 176 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/ICoreSession.cs
  36. 48 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/NoCoreServerSession.cs
  37. 144 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/NoCoreSession.cs
  38. 53 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/NonDisposingCoreSessionHandle.cs
  39. 67 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/ReferenceCountedCoreSession.cs
  40. 107 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/WrappingCoreServerSession.cs
  41. 271 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/WrappingCoreSession.cs
  42. 84 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Clusters/ClusterClock.cs
  43. 41 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Clusters/IClusterClock.cs
  44. 61 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Configuration/SdamLoggingSettings.cs
  45. 92 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Connections/IsMasterHelper.cs
  46. 37 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Connections/KeepAliveValues.cs
  47. 158 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Events/Diagnostics/TraceSourceSdamEventSubscriber.cs
  48. 57 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Events/SdamInformationEvent.cs
  49. 69 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Misc/FixedCountBatchableSourceSerializer.cs
  50. 113 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Misc/IBatchableSource.cs
  51. 120 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Misc/SizeLimitingBatchableSourceSerializer.cs
  52. 187 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/ChangeStreamCursor.cs
  53. 383 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/ChangeStreamOperation.cs
  54. 238 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/CountDocumentsOperation.cs
  55. 32 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/DelayedEvaluationWriteConcernSerializer.cs
  56. 231 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/EndTransactionOperation.cs
  57. 41 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/IOperationClock.cs
  58. 70 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/IRetryableOperation.cs
  59. 82 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/OperationClock.cs
  60. 55 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/ReadConcernHelper.cs
  61. 136 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryabilityHelper.cs
  62. 142 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableDeleteCommandOperation.cs
  63. 181 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableInsertCommandOperation.cs
  64. 203 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableUpdateCommandOperation.cs
  65. 276 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableWriteCommandOperationBase.cs
  66. 195 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableWriteContext.cs
  67. 143 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableWriteOperationExecutor.cs
  68. 49 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/WriteConcernHelper.cs
  69. 41 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Servers/ClusterClockAdvancingCoreSession.cs
  70. 339 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs
  71. 405 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingQueryMessageWireProtocol.cs
  72. 129 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/CommandMessage.cs
  73. 69 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/CommandMessageDisposer.cs
  74. 293 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/CommandMessageSection.cs
  75. 66 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/CommandRequestMessage.cs
  76. 65 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/CommandResponseMessage.cs
  77. 450 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs
  78. 73 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandRequestMessageBinaryEncoder.cs
  79. 71 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandResponseMessageBinaryEncoder.cs
  80. 12 8
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/OpMsgFlags.cs
  81. 30 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/CommandResponseMessageEncoderSelector.cs
  82. 28 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/IMessageEncoderPostProcessor.cs
  83. 202 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandMessageJsonEncoder.cs
  84. 71 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandRequestMessageJsonEncoder.cs
  85. 71 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandResponseMessageJsonEncoder.cs
  86. 43 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ServerErrorCode.cs
  87. 98 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/TransactionOptions.cs
  88. 266 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/DelegatingStream.cs
  89. 1027 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSBucket.cs
  90. 270 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSBucketCompat.cs
  91. 289 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSBucketOptions.cs
  92. 67 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSChunkException.cs
  93. 39 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSDownloadByNameOptions.cs
  94. 52 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSDownloadOptions.cs
  95. 68 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSDownloadStream.cs
  96. 210 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSDownloadStreamBase.cs
  97. 58 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSDownloadStreamCompat.cs
  98. 63 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSException.cs
  99. 159 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSFileInfo.cs
  100. 169 0
      Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSFileInfoCompat.cs

+ 63 - 48
Client-Server.sln

@@ -15,14 +15,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server.Model", "Server\Mode
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server.Hotfix", "Server\Hotfix\Server.Hotfix.csproj", "{C305ED5B-8425-47A1-BEE1-85830CADC27A}"
 EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MongodbDriver", "MongodbDriver", "{4940CE10-6652-4AC6-9D30-CF200A217643}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Bson", "Server\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Bson\MongoDB.Bson.csproj", "{BC611535-3BDA-45C5-8765-9E242E312B8F}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Driver", "Server\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver\MongoDB.Driver.csproj", "{6D19C1F8-085C-422E-8DAF-2E49024DB08C}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Driver.Core", "Server\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj", "{831276B2-B7EB-4FD0-93E5-4D2109C78950}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Google.Protobuf", "Server\ThirdParty\Google.Protobuf\Google.Protobuf.csproj", "{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unity.Model", "Unity\Unity.Model.csproj", "{6396AEEA-8EF9-9740-4CEF-891CC997106C}"
@@ -41,6 +33,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Proto2CS", "Tools\Proto2CS\
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileServer", "Tools\FileServer\FileServer.csproj", "{1C2827BF-AA19-402A-BFD1-1C92E6B8FD84}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MongoDBDriver", "MongoDBDriver", "{14963D84-2A63-48CF-AE13-DCF71F1E13A0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Bson", "Server\ThirdParty\MongoDBDriver\MongoDB.Bson\MongoDB.Bson.csproj", "{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Driver", "Server\ThirdParty\MongoDBDriver\MongoDB.Driver\MongoDB.Driver.csproj", "{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Driver.Core", "Server\ThirdParty\MongoDBDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj", "{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Driver.GridFS", "Server\ThirdParty\MongoDBDriver\MongoDB.Driver.GridFS\MongoDB.Driver.GridFS.csproj", "{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -87,42 +89,6 @@ Global
 		{C305ED5B-8425-47A1-BEE1-85830CADC27A}.Release|x64.Build.0 = Release|Any CPU
 		{C305ED5B-8425-47A1-BEE1-85830CADC27A}.Release|x86.ActiveCfg = Release|Any CPU
 		{C305ED5B-8425-47A1-BEE1-85830CADC27A}.Release|x86.Build.0 = Release|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Debug|x64.Build.0 = Debug|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Debug|x86.Build.0 = Debug|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Release|x64.ActiveCfg = Release|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Release|x64.Build.0 = Release|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Release|x86.ActiveCfg = Release|Any CPU
-		{BC611535-3BDA-45C5-8765-9E242E312B8F}.Release|x86.Build.0 = Release|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Debug|x64.Build.0 = Debug|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Debug|x86.Build.0 = Debug|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Release|x64.ActiveCfg = Release|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Release|x64.Build.0 = Release|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Release|x86.ActiveCfg = Release|Any CPU
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C}.Release|x86.Build.0 = Release|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Debug|x64.Build.0 = Debug|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Debug|x86.Build.0 = Debug|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Release|Any CPU.Build.0 = Release|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Release|x64.ActiveCfg = Release|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Release|x64.Build.0 = Release|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Release|x86.ActiveCfg = Release|Any CPU
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950}.Release|x86.Build.0 = Release|Any CPU
 		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -219,6 +185,54 @@ Global
 		{1C2827BF-AA19-402A-BFD1-1C92E6B8FD84}.Release|x64.Build.0 = Release|Any CPU
 		{1C2827BF-AA19-402A-BFD1-1C92E6B8FD84}.Release|x86.ActiveCfg = Release|Any CPU
 		{1C2827BF-AA19-402A-BFD1-1C92E6B8FD84}.Release|x86.Build.0 = Release|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Debug|x64.Build.0 = Debug|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Debug|x86.Build.0 = Debug|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Release|x64.ActiveCfg = Release|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Release|x64.Build.0 = Release|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Release|x86.ActiveCfg = Release|Any CPU
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D}.Release|x86.Build.0 = Release|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Debug|x64.Build.0 = Debug|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Debug|x86.Build.0 = Debug|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Release|x64.ActiveCfg = Release|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Release|x64.Build.0 = Release|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Release|x86.ActiveCfg = Release|Any CPU
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7}.Release|x86.Build.0 = Release|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Debug|x64.Build.0 = Debug|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Debug|x86.Build.0 = Debug|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Release|x64.ActiveCfg = Release|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Release|x64.Build.0 = Release|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Release|x86.ActiveCfg = Release|Any CPU
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA}.Release|x86.Build.0 = Release|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Debug|x64.Build.0 = Debug|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Debug|x86.Build.0 = Debug|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Release|x64.ActiveCfg = Release|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Release|x64.Build.0 = Release|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Release|x86.ActiveCfg = Release|Any CPU
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -228,10 +242,6 @@ Global
 		{69F1AA11-D05A-4843-B0DD-56B5E2E212A8} = {46008B91-6EC0-448B-8D1A-D8C6D2EEBEF4}
 		{EE38E3D2-3D2A-4061-BD50-AE8568126C7D} = {46008B91-6EC0-448B-8D1A-D8C6D2EEBEF4}
 		{C305ED5B-8425-47A1-BEE1-85830CADC27A} = {46008B91-6EC0-448B-8D1A-D8C6D2EEBEF4}
-		{4940CE10-6652-4AC6-9D30-CF200A217643} = {78640FA0-9F11-412D-A639-61F03D02407A}
-		{BC611535-3BDA-45C5-8765-9E242E312B8F} = {4940CE10-6652-4AC6-9D30-CF200A217643}
-		{6D19C1F8-085C-422E-8DAF-2E49024DB08C} = {4940CE10-6652-4AC6-9D30-CF200A217643}
-		{831276B2-B7EB-4FD0-93E5-4D2109C78950} = {4940CE10-6652-4AC6-9D30-CF200A217643}
 		{BC06C46E-79F3-4AB6-800E-FA080CA54A0B} = {78640FA0-9F11-412D-A639-61F03D02407A}
 		{6396AEEA-8EF9-9740-4CEF-891CC997106C} = {914C77C9-212A-4DD0-8D9A-074620E77FAA}
 		{350246F3-F094-675F-855B-FB9B18C2B23E} = {914C77C9-212A-4DD0-8D9A-074620E77FAA}
@@ -240,6 +250,11 @@ Global
 		{CD9683D9-0B4B-42D1-A1E0-1689BEEFD725} = {78640FA0-9F11-412D-A639-61F03D02407A}
 		{CC55624F-D5CB-4705-A879-9FCAEC1FED71} = {4BC66C3C-D55F-4FAA-A2F5-29E8EB1797AE}
 		{1C2827BF-AA19-402A-BFD1-1C92E6B8FD84} = {4BC66C3C-D55F-4FAA-A2F5-29E8EB1797AE}
+		{14963D84-2A63-48CF-AE13-DCF71F1E13A0} = {78640FA0-9F11-412D-A639-61F03D02407A}
+		{341CF1D2-DE35-4E61-AC7E-AA01A8ED452D} = {14963D84-2A63-48CF-AE13-DCF71F1E13A0}
+		{B91E7D43-CCF1-49FC-ACF5-1C88A1C81FA7} = {14963D84-2A63-48CF-AE13-DCF71F1E13A0}
+		{AAF14EDB-BB72-42A9-80AA-3E0E113AC4CA} = {14963D84-2A63-48CF-AE13-DCF71F1E13A0}
+		{2ACC29FB-55CD-4307-B1D1-CC3922BC2CE7} = {14963D84-2A63-48CF-AE13-DCF71F1E13A0}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {EABC01E3-3EB5-47EF-B46E-AAD8BB3585F1}

+ 3 - 0
Server/Hotfix/Server.Hotfix.csproj

@@ -26,6 +26,9 @@
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Model\Server.Model.csproj" />
+    <ProjectReference Include="..\ThirdParty\MongoDBDriver\MongoDB.Bson\MongoDB.Bson.csproj" />
+    <ProjectReference Include="..\ThirdParty\MongoDBDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj" />
+    <ProjectReference Include="..\ThirdParty\MongoDBDriver\MongoDB.Driver\MongoDB.Driver.csproj" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="Module\Http\" />

+ 3 - 3
Server/Model/Server.Model.csproj

@@ -344,9 +344,9 @@
   <ItemGroup>
     <ProjectReference Include="..\ThirdParty\Google.Protobuf\Google.Protobuf.csproj" />
     <ProjectReference Include="..\ThirdParty\KcpLib\KcpLib.csproj" />
-    <ProjectReference Include="..\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Bson\MongoDB.Bson.csproj" />
-    <ProjectReference Include="..\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj" />
-    <ProjectReference Include="..\ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver\MongoDB.Driver.csproj" />
+    <ProjectReference Include="..\ThirdParty\MongoDBDriver\MongoDB.Bson\MongoDB.Bson.csproj" />
+    <ProjectReference Include="..\ThirdParty\MongoDBDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj" />
+    <ProjectReference Include="..\ThirdParty\MongoDBDriver\MongoDB.Driver\MongoDB.Driver.csproj" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="Base\RecyclableMemoryStream\" />

+ 61 - 46
Server/Server.sln

@@ -11,17 +11,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server.Model", "Model\Serve
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ThirdParty", "ThirdParty", "{5D11E730-0CAA-4A47-BA1A-379004F0F6D9}"
 EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MongodbDriver", "MongodbDriver", "{6946DBCF-B81C-4B2A-A7C5-94A337D915C2}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Google.Protobuf", "ThirdParty\Google.Protobuf\Google.Protobuf.csproj", "{02B4D7EC-AC40-4675-963E-53CAB9A86BDE}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Bson", "ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Bson\MongoDB.Bson.csproj", "{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KcpLib", "ThirdParty\KcpLib\KcpLib.csproj", "{2B432E70-FA05-4D99-8241-237B0E4F5D84}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Driver", "ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver\MongoDB.Driver.csproj", "{3FD1D683-59E8-47C4-9436-B3D856EFB094}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Bson", "ThirdParty\MongoDBDriver\MongoDB.Bson\MongoDB.Bson.csproj", "{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MongoDB.Driver.Core", "ThirdParty\MongodbDriver\DotNetCoreDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj", "{46A590DE-EBA3-4928-AB78-5C514D08C9E7}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MongoDBDriver", "MongoDBDriver", "{BEC42614-36FF-4E7C-BB7D-FDBB59485C06}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Google.Protobuf", "ThirdParty\Google.Protobuf\Google.Protobuf.csproj", "{02B4D7EC-AC40-4675-963E-53CAB9A86BDE}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Driver", "ThirdParty\MongoDBDriver\MongoDB.Driver\MongoDB.Driver.csproj", "{5EA0C606-F612-4975-95B9-A20D2BFB16F7}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KcpLib", "ThirdParty\KcpLib\KcpLib.csproj", "{2B432E70-FA05-4D99-8241-237B0E4F5D84}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Driver.Core", "ThirdParty\MongoDBDriver\MongoDB.Driver.Core\MongoDB.Driver.Core.csproj", "{E10D4180-6C14-4EBE-83EA-29FFE64D321C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MongoDB.Driver.GridFS", "ThirdParty\MongoDBDriver\MongoDB.Driver.GridFS\MongoDB.Driver.GridFS.csproj", "{0C335BFA-033C-4C85-B76A-B96065CB69D3}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -69,42 +71,6 @@ Global
 		{85CB09B5-6392-4A13-BAF8-025218BFF496}.Release|x64.Build.0 = Release|Any CPU
 		{85CB09B5-6392-4A13-BAF8-025218BFF496}.Release|x86.ActiveCfg = Release|Any CPU
 		{85CB09B5-6392-4A13-BAF8-025218BFF496}.Release|x86.Build.0 = Release|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Debug|x64.Build.0 = Debug|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Debug|x86.Build.0 = Debug|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Release|Any CPU.Build.0 = Release|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Release|x64.ActiveCfg = Release|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Release|x64.Build.0 = Release|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Release|x86.ActiveCfg = Release|Any CPU
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5}.Release|x86.Build.0 = Release|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Debug|x64.Build.0 = Debug|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Debug|x86.Build.0 = Debug|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Release|Any CPU.Build.0 = Release|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Release|x64.ActiveCfg = Release|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Release|x64.Build.0 = Release|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Release|x86.ActiveCfg = Release|Any CPU
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094}.Release|x86.Build.0 = Release|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Debug|x64.Build.0 = Debug|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Debug|x86.ActiveCfg = Debug|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Debug|x86.Build.0 = Debug|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Release|Any CPU.Build.0 = Release|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Release|x64.ActiveCfg = Release|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Release|x64.Build.0 = Release|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Release|x86.ActiveCfg = Release|Any CPU
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7}.Release|x86.Build.0 = Release|Any CPU
 		{02B4D7EC-AC40-4675-963E-53CAB9A86BDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{02B4D7EC-AC40-4675-963E-53CAB9A86BDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{02B4D7EC-AC40-4675-963E-53CAB9A86BDE}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -129,17 +95,66 @@ Global
 		{2B432E70-FA05-4D99-8241-237B0E4F5D84}.Release|x64.Build.0 = Release|Any CPU
 		{2B432E70-FA05-4D99-8241-237B0E4F5D84}.Release|x86.ActiveCfg = Release|Any CPU
 		{2B432E70-FA05-4D99-8241-237B0E4F5D84}.Release|x86.Build.0 = Release|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Debug|x64.Build.0 = Debug|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Debug|x86.Build.0 = Debug|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Release|x64.ActiveCfg = Release|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Release|x64.Build.0 = Release|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Release|x86.ActiveCfg = Release|Any CPU
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7}.Release|x86.Build.0 = Release|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Debug|x64.Build.0 = Debug|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Debug|x86.Build.0 = Debug|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Release|x64.ActiveCfg = Release|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Release|x64.Build.0 = Release|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Release|x86.ActiveCfg = Release|Any CPU
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7}.Release|x86.Build.0 = Release|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Debug|x64.Build.0 = Debug|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Debug|x86.Build.0 = Debug|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Release|x64.ActiveCfg = Release|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Release|x64.Build.0 = Release|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Release|x86.ActiveCfg = Release|Any CPU
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C}.Release|x86.Build.0 = Release|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Debug|x64.Build.0 = Debug|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Debug|x86.Build.0 = Debug|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Release|x64.ActiveCfg = Release|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Release|x64.Build.0 = Release|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Release|x86.ActiveCfg = Release|Any CPU
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(NestedProjects) = preSolution
-		{6946DBCF-B81C-4B2A-A7C5-94A337D915C2} = {5D11E730-0CAA-4A47-BA1A-379004F0F6D9}
-		{817B2682-29D6-4BAC-9AA7-618DCCD8CBE5} = {6946DBCF-B81C-4B2A-A7C5-94A337D915C2}
-		{3FD1D683-59E8-47C4-9436-B3D856EFB094} = {6946DBCF-B81C-4B2A-A7C5-94A337D915C2}
-		{46A590DE-EBA3-4928-AB78-5C514D08C9E7} = {6946DBCF-B81C-4B2A-A7C5-94A337D915C2}
 		{02B4D7EC-AC40-4675-963E-53CAB9A86BDE} = {5D11E730-0CAA-4A47-BA1A-379004F0F6D9}
 		{2B432E70-FA05-4D99-8241-237B0E4F5D84} = {5D11E730-0CAA-4A47-BA1A-379004F0F6D9}
+		{BEC42614-36FF-4E7C-BB7D-FDBB59485C06} = {5D11E730-0CAA-4A47-BA1A-379004F0F6D9}
+		{78F97DF3-2E7F-4FB5-801D-E9CC4FB859F7} = {BEC42614-36FF-4E7C-BB7D-FDBB59485C06}
+		{5EA0C606-F612-4975-95B9-A20D2BFB16F7} = {BEC42614-36FF-4E7C-BB7D-FDBB59485C06}
+		{E10D4180-6C14-4EBE-83EA-29FFE64D321C} = {BEC42614-36FF-4E7C-BB7D-FDBB59485C06}
+		{0C335BFA-033C-4C85-B76A-B96065CB69D3} = {BEC42614-36FF-4E7C-BB7D-FDBB59485C06}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {EE120158-643A-409C-B8F2-5E654E4D6D70}

+ 2 - 0
Server/Server.sln.DotSettings.user

@@ -0,0 +1,2 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+	<s:String x:Key="/Default/CodeInspection/Highlighting/AnalysisEnabled/@EntryValue">VISIBLE_FILES</s:String></wpf:ResourceDictionary>

+ 1 - 1
Server/ThirdParty/Google.Protobuf/Google.Protobuf.csproj

@@ -69,6 +69,6 @@
     </Compile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\MongodbDriver\DotNetCoreDriver\MongoDB.Bson\MongoDB.Bson.csproj" />
+    <ProjectReference Include="..\MongoDBDriver\MongoDB.Bson\MongoDB.Bson.csproj" />
   </ItemGroup>
 </Project>

+ 84 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs

@@ -0,0 +1,84 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+
+namespace MongoDB.Bson.IO
+{
+    /// <summary>
+    /// A BsonWriter that appends elements to the end of a document.
+    /// </summary>
+    /// <seealso cref="MongoDB.Bson.IO.IBsonWriter" />
+    internal sealed class ElementAppendingBsonWriter : WrappingBsonWriter
+    {
+        // private fields
+        private int _depth;
+        private readonly List<BsonElement> _elements;
+        private readonly Action<BsonWriterSettings> _settingsConfigurator;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ElementAppendingBsonWriter" /> class.
+        /// </summary>
+        /// <param name="wrapped">The wrapped writer.</param>
+        /// <param name="elements">The elements to append.</param>
+        /// <param name="settingsConfigurator">The settings configurator.</param>
+        public ElementAppendingBsonWriter(
+            IBsonWriter wrapped,
+            IEnumerable<BsonElement> elements,
+            Action<BsonWriterSettings> settingsConfigurator)
+            : base(wrapped)
+        {
+            if (elements == null) { throw new ArgumentNullException(nameof(elements)); }
+            _elements = elements.ToList();
+            _settingsConfigurator = settingsConfigurator ?? (s => { });
+        }
+
+        // public methods
+        /// <inheritdoc />
+        public override void WriteEndDocument()
+        {
+            if (--_depth == 0)
+            {
+                Wrapped.PushSettings(_settingsConfigurator);
+                try
+                {
+                    var context = BsonSerializationContext.CreateRoot(Wrapped);
+                    foreach (var element in _elements)
+                    {
+                        Wrapped.WriteName(element.Name);
+                        BsonValueSerializer.Instance.Serialize(context, element.Value);
+                    }
+                }
+                finally
+                {
+                    Wrapped.PopSettings();
+                }
+            }
+            base.WriteEndDocument();
+        }
+
+        /// <inheritdoc />
+        public override void WriteStartDocument()
+        {
+            _depth++;
+            base.WriteStartDocument();
+        }
+    }
+}

+ 361 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Bson/IO/WrappingBsonWriter.cs

@@ -0,0 +1,361 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+
+namespace MongoDB.Bson.IO
+{
+    /// <summary>
+    /// An abstract base class for an IBsonWriter that wraps another IBsonWriter.
+    /// </summary>
+    /// <seealso cref="MongoDB.Bson.IO.IBsonWriter" />
+    public abstract class WrappingBsonWriter : IBsonWriter
+    {
+        // private fields
+        private bool _disposed;
+        private readonly IBsonWriter _wrapped;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="WrappingBsonWriter"/> class.
+        /// </summary>
+        /// <param name="wrapped">The wrapped writer.</param>
+        public WrappingBsonWriter(IBsonWriter wrapped)
+        {
+            if (wrapped == null)
+            {
+                throw new ArgumentNullException(nameof(wrapped));
+            }
+            _wrapped = wrapped;
+        }
+
+        // public properties
+        /// <inheritdoc />
+        public virtual long Position
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.Position;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual int SerializationDepth
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.SerializationDepth;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual BsonWriterSettings Settings
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.Settings;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual BsonWriterState State
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.State;
+            }
+        }
+
+        /// <summary>
+        /// Gets the wrapped writer.
+        /// </summary>
+        /// <value>
+        /// The wrapped writer.
+        /// </value>
+        public IBsonWriter Wrapped
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped;
+            }
+        }
+
+        // public methods
+        /// <inheritdoc />
+        public virtual void Close()
+        {
+            // let subclass decide whether to throw or not if Dispose has been called
+            _wrapped.Close();
+        }
+
+        /// <inheritdoc />
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        /// <inheritdoc />
+        public virtual void Flush()
+        {
+            ThrowIfDisposed();
+            _wrapped.Flush();
+        }
+
+        /// <inheritdoc />
+        public virtual void PopElementNameValidator()
+        {
+            ThrowIfDisposed();
+            _wrapped.PopElementNameValidator();
+        }
+
+        /// <inheritdoc />
+        public virtual void PopSettings()
+        {
+            ThrowIfDisposed();
+            _wrapped.PopSettings();
+        }
+
+        /// <inheritdoc />
+        public virtual void PushElementNameValidator(IElementNameValidator validator)
+        {
+            ThrowIfDisposed();
+            _wrapped.PushElementNameValidator(validator);
+        }
+
+        /// <inheritdoc />
+        public virtual void PushSettings(Action<BsonWriterSettings> configurator)
+        {
+            ThrowIfDisposed();
+            _wrapped.PushSettings(configurator);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteBinaryData(BsonBinaryData binaryData)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteBinaryData(binaryData);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteBoolean(bool value)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteBoolean(value);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteBytes(byte[] bytes)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteBytes(bytes);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteDateTime(long value)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteDateTime(value);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteDecimal128(Decimal128 value)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteDecimal128(value);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteDouble(double value)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteDouble(value);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteEndArray()
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteEndArray();
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteEndDocument()
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteEndDocument();
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteInt32(int value)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteInt32(value);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteInt64(long value)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteInt64(value);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteJavaScript(string code)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteJavaScript(code);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteJavaScriptWithScope(string code)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteJavaScriptWithScope(code);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteMaxKey()
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteMaxKey();
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteMinKey()
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteMinKey();
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteName(string name)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteName(name);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteNull()
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteNull();
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteObjectId(ObjectId objectId)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteObjectId(objectId);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteRawBsonArray(IByteBuffer slice)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteRawBsonArray(slice);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteRawBsonDocument(IByteBuffer slice)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteRawBsonDocument(slice);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteRegularExpression(BsonRegularExpression regex)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteRegularExpression(regex);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteStartArray()
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteStartArray();
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteStartDocument()
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteStartDocument();
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteString(string value)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteString(value);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteSymbol(string value)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteSymbol(value);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteTimestamp(long value)
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteTimestamp(value);
+        }
+
+        /// <inheritdoc />
+        public virtual void WriteUndefined()
+        {
+            ThrowIfDisposed();
+            _wrapped.WriteUndefined();
+        }
+
+        // protected methods
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources.
+        /// </summary>
+        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_disposed)
+            {
+                if (disposing)
+                {
+                    _wrapped.Dispose();
+                }
+                _disposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Throws if disposed.
+        /// </summary>
+        /// <exception cref="ObjectDisposedException"></exception>
+        protected void ThrowIfDisposed()
+        {
+            if (_disposed)
+            {
+                throw new ObjectDisposedException(GetType().FullName);
+            }
+        }
+    }
+}

+ 90 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Bson/Serialization/Serializers/ElementAppendingSerializer.cs

@@ -0,0 +1,90 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MongoDB.Bson.IO;
+
+namespace MongoDB.Bson.Serialization.Serializers
+{
+    /// <summary>
+    /// A serializer that serializes a document and appends elements to the end of it.
+    /// </summary>
+    /// <typeparam name="TDocument">The type of the document.</typeparam>
+    /// <seealso cref="MongoDB.Bson.Serialization.IBsonSerializer{TDocument}" />
+    public class ElementAppendingSerializer<TDocument> : IBsonSerializer<TDocument>
+    {
+        // private fields
+        private readonly IBsonSerializer<TDocument> _documentSerializer;
+        private readonly List<BsonElement> _elements;
+        private readonly Action<BsonWriterSettings> _writerSettingsConfigurator;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ElementAppendingSerializer{TDocument}" /> class.
+        /// </summary>
+        /// <param name="documentSerializer">The document serializer.</param>
+        /// <param name="elements">The elements to append.</param>
+        /// <param name="writerSettingsConfigurator">The writer settings configurator.</param>
+        public ElementAppendingSerializer(
+            IBsonSerializer<TDocument> documentSerializer, 
+            IEnumerable<BsonElement> elements, 
+            Action<BsonWriterSettings> writerSettingsConfigurator = null)
+        {
+            if (documentSerializer == null) { throw new ArgumentNullException(nameof(documentSerializer)); }
+            if (elements == null) { throw new ArgumentNullException(nameof(elements)); }
+            _documentSerializer = documentSerializer;
+            _elements = elements.ToList();
+            _writerSettingsConfigurator = writerSettingsConfigurator; // can be null
+        }
+
+        // public properties
+        /// <inheritdoc />
+        public Type ValueType => typeof(TDocument);
+
+        // public methods
+        /// <inheritdoc />
+        public TDocument Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
+        {
+            throw new NotSupportedException();
+        }
+
+        object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
+        {
+            throw new NotSupportedException();
+        }
+
+        /// <inheritdoc />
+        public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TDocument value)
+        {
+            var writer = context.Writer;
+            var elementAppendingWriter = new ElementAppendingBsonWriter(writer, _elements, _writerSettingsConfigurator);
+            var elementAppendingContext = BsonSerializationContext.CreateRoot(elementAppendingWriter, builder => ConfigureElementAppendingContext(builder, context));
+            _documentSerializer.Serialize(elementAppendingContext, args, value);
+        }
+
+        void IBsonSerializer.Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
+        {
+            Serialize(context, args, (TDocument)value);
+        }
+
+        // private methods
+        private void ConfigureElementAppendingContext(BsonSerializationContext.Builder builder, BsonSerializationContext originalContext)
+        {
+            builder.IsDynamicType = originalContext.IsDynamicType;
+        }
+    }
+}

+ 149 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Bson/Serialization/Serializers/ReadOnlyDictionaryInterfaceImplementerSerializer.cs

@@ -0,0 +1,149 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Reflection;
+using MongoDB.Bson.Serialization.Options;
+
+namespace MongoDB.Bson.Serialization.Serializers
+{
+    /// <summary>
+    /// Represents a serializer for a class that implements <see cref="IDictionary{TKey, TValue}"/>.
+    /// </summary>
+    /// <typeparam name="TDictionary">The type of the dictionary.</typeparam>
+    /// <typeparam name="TKey">The type of the key.</typeparam>
+    /// <typeparam name="TValue">The type of the value.</typeparam>
+    public class ReadOnlyDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> :
+        DictionarySerializerBase<TDictionary, TKey, TValue>,
+        IChildSerializerConfigurable,
+        IDictionaryRepresentationConfigurable<ReadOnlyDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>>
+            where TDictionary : class, IReadOnlyDictionary<TKey, TValue>
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ReadOnlyDictionaryInterfaceImplementerSerializer{TDictionary, TKey, TValue}"/> class.
+        /// </summary>
+        public ReadOnlyDictionaryInterfaceImplementerSerializer()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ReadOnlyDictionaryInterfaceImplementerSerializer{TDictionary, TKey, TValue}"/> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        public ReadOnlyDictionaryInterfaceImplementerSerializer(DictionaryRepresentation dictionaryRepresentation)
+            : base(dictionaryRepresentation)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ReadOnlyDictionaryInterfaceImplementerSerializer{TDictionary, TKey, TValue}"/> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <param name="valueSerializer">The value serializer.</param>
+        public ReadOnlyDictionaryInterfaceImplementerSerializer(DictionaryRepresentation dictionaryRepresentation, IBsonSerializer<TKey> keySerializer, IBsonSerializer<TValue> valueSerializer)
+            : base(dictionaryRepresentation, keySerializer, valueSerializer)
+        {
+        }
+
+        // public methods
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified dictionary representation.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public ReadOnlyDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> WithDictionaryRepresentation(DictionaryRepresentation dictionaryRepresentation)
+        {
+            return dictionaryRepresentation == DictionaryRepresentation 
+                ? this 
+                : new ReadOnlyDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>(dictionaryRepresentation, KeySerializer, ValueSerializer);
+        }
+
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified dictionary representation and key value serializers.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <param name="valueSerializer">The value serializer.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public ReadOnlyDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> WithDictionaryRepresentation(DictionaryRepresentation dictionaryRepresentation, IBsonSerializer<TKey> keySerializer, IBsonSerializer<TValue> valueSerializer)
+        {
+            return dictionaryRepresentation == DictionaryRepresentation && keySerializer == KeySerializer && valueSerializer == ValueSerializer
+                ? this
+                : new ReadOnlyDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>(dictionaryRepresentation, keySerializer, valueSerializer);
+        }
+
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified key serializer.
+        /// </summary>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public ReadOnlyDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> WithKeySerializer(IBsonSerializer<TKey> keySerializer)
+        {
+            return keySerializer == KeySerializer 
+                ? this 
+                : new ReadOnlyDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>(DictionaryRepresentation, keySerializer, ValueSerializer);
+        }
+
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified value serializer.
+        /// </summary>
+        /// <param name="valueSerializer">The value serializer.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public ReadOnlyDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> WithValueSerializer(IBsonSerializer<TValue> valueSerializer)
+        {
+            return valueSerializer == ValueSerializer 
+                ? this 
+                : new ReadOnlyDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>(DictionaryRepresentation, KeySerializer, valueSerializer);
+        }
+
+        // explicit interface implementations
+        IBsonSerializer IChildSerializerConfigurable.ChildSerializer => ValueSerializer;
+        
+        IBsonSerializer IChildSerializerConfigurable.WithChildSerializer(IBsonSerializer childSerializer)
+        {
+            return WithValueSerializer((IBsonSerializer<TValue>)childSerializer);
+        }
+
+        IBsonSerializer IDictionaryRepresentationConfigurable.WithDictionaryRepresentation(DictionaryRepresentation dictionaryRepresentation)
+        {
+            return WithDictionaryRepresentation(dictionaryRepresentation);
+        }
+        
+        /// <inheritdoc/>
+        protected override ICollection<KeyValuePair<TKey, TValue>> CreateAccumulator()
+        {
+            return new Dictionary<TKey, TValue>();
+        }
+
+        /// <inheritdoc/>
+        protected override TDictionary FinalizeAccumulator(ICollection<KeyValuePair<TKey, TValue>> accumulator)
+        {
+            try
+            {
+                return (TDictionary) Activator.CreateInstance(typeof(TDictionary), new object[] {accumulator});
+            }
+            catch (MissingMethodException exception)
+            {
+                throw new MissingMethodException(
+                    $"No suitable constructor found for IReadOnlyDictionary type: '{typeof(TDictionary).FullName}'.",
+                    exception);
+            }
+        }
+    }
+}

+ 104 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamDocument.cs

@@ -0,0 +1,104 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace MongoDB.Driver
+{
+    /// <summary>
+    /// An output document from a $changeStream pipeline stage.
+    /// </summary>
+    /// <typeparam name="TDocument">The type of the document.</typeparam>
+    [BsonSerializer(typeof(ChangeStreamDocumentSerializer<>))]
+    public sealed class ChangeStreamDocument<TDocument> : BsonDocumentBackedClass
+    {
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ChangeStreamDocument{TDocument}"/> class.
+        /// </summary>
+        /// <param name="backingDocument">The backing document.</param>
+        /// <param name="documentSerializer">The document serializer.</param>
+        public ChangeStreamDocument(
+            BsonDocument backingDocument,
+            IBsonSerializer<TDocument> documentSerializer)
+            : base(backingDocument, new ChangeStreamDocumentSerializer<TDocument>(documentSerializer))
+        {
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the backing document.
+        /// </summary>
+        new public BsonDocument BackingDocument => base.BackingDocument;
+
+        /// <summary>
+        /// Gets the cluster time.
+        /// </summary>
+        /// <value>
+        /// The cluster time.
+        /// </value>
+        public BsonTimestamp ClusterTime => GetValue<BsonTimestamp>(nameof(ClusterTime), null);
+
+        /// <summary>
+        /// Gets the namespace of the collection.
+        /// </summary>
+        /// <value>
+        /// The namespace of the collection.
+        /// </value>
+        public CollectionNamespace CollectionNamespace => GetValue<CollectionNamespace>(nameof(CollectionNamespace), null);
+
+        /// <summary>
+        /// Gets the document key.
+        /// </summary>
+        /// <value>
+        /// The document key.
+        /// </value>
+        public BsonDocument DocumentKey => GetValue<BsonDocument>(nameof(DocumentKey), null);
+
+        /// <summary>
+        /// Gets the full document.
+        /// </summary>
+        /// <value>
+        /// The full document.
+        /// </value>
+        public TDocument FullDocument => GetValue<TDocument>(nameof(FullDocument), default(TDocument));
+
+        /// <summary>
+        /// Gets the type of the operation.
+        /// </summary>
+        /// <value>
+        /// The type of the operation.
+        /// </value>
+        public ChangeStreamOperationType OperationType => GetValue<ChangeStreamOperationType>(nameof(OperationType), (ChangeStreamOperationType)(-1));
+
+        /// <summary>
+        /// Gets the resume token.
+        /// </summary>
+        /// <value>
+        /// The resume token.
+        /// </value>
+        public BsonDocument ResumeToken => GetValue<BsonDocument>(nameof(ResumeToken), null);
+
+        /// <summary>
+        /// Gets the update description.
+        /// </summary>
+        /// <value>
+        /// The update description.
+        /// </value>
+        public ChangeStreamUpdateDescription UpdateDescription => GetValue<ChangeStreamUpdateDescription>(nameof(UpdateDescription), null);
+    }
+}

+ 76 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamDocumentCollectionNamespaceSerializer.cs

@@ -0,0 +1,76 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+
+namespace MongoDB.Driver
+{
+    internal class ChangeStreamDocumentCollectionNamespaceSerializer : SealedClassSerializerBase<CollectionNamespace>
+    {
+        #region static
+        // private static fields
+        private static readonly ChangeStreamDocumentCollectionNamespaceSerializer __instance = new ChangeStreamDocumentCollectionNamespaceSerializer();
+
+        // public static properties
+        public static ChangeStreamDocumentCollectionNamespaceSerializer Instance => __instance;
+        #endregion
+
+        // public methods
+        public override CollectionNamespace Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
+        {
+            var reader = context.Reader;
+            string collectionName = null;
+            string databaseName = null;
+
+            reader.ReadStartDocument();
+            while (reader.ReadBsonType() != 0)
+            {
+                var fieldName = reader.ReadName();
+                switch (fieldName)
+                {
+                    case "db":
+                        databaseName = reader.ReadString();
+                        break;
+
+                    case "coll":
+                        collectionName = reader.ReadString();
+                        break;
+
+                    default:
+                        throw new FormatException($"Invalid field name: \"{fieldName}\".");
+                }
+            }
+            reader.ReadEndDocument();
+
+            var databaseNamespace = new DatabaseNamespace(databaseName);
+            return new CollectionNamespace(databaseNamespace, collectionName);
+        }
+
+        protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, CollectionNamespace value)
+        {
+            var writer = context.Writer;
+
+            writer.WriteStartDocument();
+            writer.WriteName("db");
+            writer.WriteString(value.DatabaseNamespace.DatabaseName);
+            writer.WriteName("coll");
+            writer.WriteString(value.CollectionName);
+            writer.WriteEndDocument();
+        }
+    }
+}

+ 59 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamDocumentSerializer.cs

@@ -0,0 +1,59 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver
+{
+
+    /// <summary>
+    /// A serializer for ChangeStreamDocument instances.
+    /// </summary>
+    /// <typeparam name="TDocument">The type of the document.</typeparam>
+    public class ChangeStreamDocumentSerializer<TDocument> : BsonDocumentBackedClassSerializer<ChangeStreamDocument<TDocument>>
+    {
+        // private fields
+        private readonly IBsonSerializer<TDocument> _documentSerializer;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ChangeStreamDocumentSerializer{TDocument}"/> class.
+        /// </summary>
+        /// <param name="documentSerializer">The document serializer.</param>
+        public ChangeStreamDocumentSerializer(
+            IBsonSerializer<TDocument> documentSerializer)
+        {
+            _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer));
+
+            RegisterMember("ClusterTime", "clusterTime", BsonTimestampSerializer.Instance);
+            RegisterMember("CollectionNamespace", "ns", ChangeStreamDocumentCollectionNamespaceSerializer.Instance);
+            RegisterMember("DocumentKey", "documentKey", BsonDocumentSerializer.Instance);
+            RegisterMember("FullDocument", "fullDocument", _documentSerializer);
+            RegisterMember("OperationType", "operationType", ChangeStreamOperationTypeSerializer.Instance);
+            RegisterMember("ResumeToken", "_id", BsonDocumentSerializer.Instance);
+            RegisterMember("UpdateDescription", "updateDescription", ChangeStreamUpdateDescriptionSerializer.Instance);
+        }
+
+        // protected methods
+        /// <inheritdoc />
+        protected override ChangeStreamDocument<TDocument> CreateInstance(BsonDocument backingDocument)
+        {
+            return new ChangeStreamDocument<TDocument>(backingDocument, _documentSerializer);
+        }
+    }
+}

+ 34 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamFullDocumentOptions.cs

@@ -0,0 +1,34 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver
+{
+    /// <summary>
+    /// Change stream FullDocument option.
+    /// </summary>
+    public enum ChangeStreamFullDocumentOption
+    {
+        /// <summary>
+        /// Do not return the full document.
+        /// </summary>
+        Default = 0,
+        /// <summary>
+        /// The change stream for partial updates will include both a delta describing the
+        /// changes to the document as well as a copy of the entire document that was
+        /// changed from some time after the change occurred.
+        /// </summary>
+        UpdateLookup
+    }
+}

+ 44 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamOperationType.cs

@@ -0,0 +1,44 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver
+{
+    /// <summary>
+    /// The operation type of a change stream result.
+    /// </summary>
+    public enum ChangeStreamOperationType
+    {
+        /// <summary>
+        /// An insert operation type.
+        /// </summary>
+        Insert,
+        /// <summary>
+        /// An update operation type.
+        /// </summary>
+        Update,
+        /// <summary>
+        /// A replace operation type.
+        /// </summary>
+        Replace,
+        /// <summary>
+        /// A delete operation type.
+        /// </summary>
+        Delete,
+        /// <summary>
+        /// An invalidate operation type.
+        /// </summary>
+        Invalidate
+    }
+}

+ 74 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamOperationTypeSerializer.cs

@@ -0,0 +1,74 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using System;
+
+namespace MongoDB.Driver
+{
+    /// <summary>
+    /// A serializer for ChangeStreamOperationType values.
+    /// </summary>
+    public class ChangeStreamOperationTypeSerializer : StructSerializerBase<ChangeStreamOperationType>
+    {
+        #region static
+        // private static fields
+        private static readonly ChangeStreamOperationTypeSerializer __instance = new ChangeStreamOperationTypeSerializer();
+
+        // public static properties
+        /// <summary>
+        /// Gets a ChangeStreamOperationTypeSerializer.
+        /// </summary>
+        /// <value>
+        /// A ChangeStreamOperationTypeSerializer.
+        /// </value>
+        public static ChangeStreamOperationTypeSerializer Instance => __instance;
+        #endregion
+
+        /// <inheritdoc />
+        public override ChangeStreamOperationType Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
+        {
+            var reader = context.Reader;
+
+            var stringValue = reader.ReadString();
+            switch (stringValue)
+            {
+                case "delete": return ChangeStreamOperationType.Delete;
+                case "insert": return ChangeStreamOperationType.Insert;
+                case "invalidate": return ChangeStreamOperationType.Invalidate;
+                case "replace": return ChangeStreamOperationType.Replace;
+                case "update": return ChangeStreamOperationType.Update;
+                default: throw new FormatException($"Invalid ChangeStreamOperationType: \"{stringValue}\".");
+            }
+        }
+
+        /// <inheritdoc />
+        public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, ChangeStreamOperationType value)
+        {
+            var writer = context.Writer;
+
+            switch (value)
+            {
+                case ChangeStreamOperationType.Delete: writer.WriteString("delete"); break;
+                case ChangeStreamOperationType.Insert: writer.WriteString("insert"); break;
+                case ChangeStreamOperationType.Invalidate: writer.WriteString("invalidate"); break;
+                case ChangeStreamOperationType.Replace: writer.WriteString("replace"); break;
+                case ChangeStreamOperationType.Update: writer.WriteString("update"); break;
+                default: throw new ArgumentException($"Invalid ChangeStreamOperationType: {value}.", nameof(value));
+            }
+        }
+    }
+}

+ 87 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamUpdateDescription.cs

@@ -0,0 +1,87 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System.Linq;
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Shared;
+
+namespace MongoDB.Driver
+{
+    /// <summary>
+    /// An UpdateDescription in a ChangeStreamDocument instance.
+    /// </summary>
+    public sealed class ChangeStreamUpdateDescription
+    {
+        // private fields
+        private readonly string[] _removedFields;
+        private readonly BsonDocument _updatedFields;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ChangeStreamUpdateDescription" /> class.
+        /// </summary>
+        /// <param name="updatedFields">The updated fields.</param>
+        /// <param name="removedFields">The removed fields.</param>
+        public ChangeStreamUpdateDescription(
+            BsonDocument updatedFields,
+            string[] removedFields)
+        {
+            _updatedFields = Ensure.IsNotNull(updatedFields, nameof(updatedFields));
+            _removedFields = Ensure.IsNotNull(removedFields, nameof(removedFields));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the removed fields.
+        /// </summary>
+        /// <value>
+        /// The removed fields.
+        /// </value>
+        public string[] RemovedFields => _removedFields;
+
+        /// <summary>
+        /// Gets the updated fields.
+        /// </summary>
+        /// <value>
+        /// The updated fields.
+        /// </value>
+        public BsonDocument UpdatedFields => _updatedFields;
+
+        // public methods
+        /// <inheritdoc />
+        public override bool Equals(object obj)
+        {
+            if (obj == null || obj.GetType() != typeof(ChangeStreamUpdateDescription))
+            {
+                return false;
+            }
+
+            var other = (ChangeStreamUpdateDescription)obj;
+            return
+                _removedFields.SequenceEqual(other._removedFields) &&
+                _updatedFields.Equals(other._updatedFields);
+        }
+
+        /// <inheritdoc />
+        public override int GetHashCode()
+        {
+            return new Hasher()
+                .HashElements(_removedFields)
+                .Hash(_updatedFields)
+                .GetHashCode();
+        }
+    }
+}

+ 89 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ChangeStreamUpdateDescriptionSerializer.cs

@@ -0,0 +1,89 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Misc;
+using System;
+
+namespace MongoDB.Driver
+{
+    /// <summary>
+    /// A serialize for ChangeStreamUpdateDescription values.
+    /// </summary>
+    public class ChangeStreamUpdateDescriptionSerializer : SealedClassSerializerBase<ChangeStreamUpdateDescription>
+    {
+        #region static
+        // private static fields
+        private static readonly ChangeStreamUpdateDescriptionSerializer __instance = new ChangeStreamUpdateDescriptionSerializer();
+        private static readonly IBsonSerializer<string[]> __stringArraySerializer = new ArraySerializer<string>();
+
+        // public static properties
+        /// <summary>
+        /// Gets a ChangeStreamUpdateDescriptionSerializer.
+        /// </summary>
+        /// <value>
+        /// A ChangeStreamUpdateDescriptionSerializer.
+        /// </value>
+        public static ChangeStreamUpdateDescriptionSerializer Instance => __instance;
+        #endregion
+
+        /// <inheritdoc />
+        protected override ChangeStreamUpdateDescription DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args)
+        {
+            var reader = context.Reader;
+
+            BsonDocument updatedFields = null;
+            string[] removedFields = null;
+
+            reader.ReadStartDocument();
+            while (reader.ReadBsonType() != 0)
+            {
+                var fieldName = reader.ReadName();
+                switch (fieldName)
+                {
+                    case "updatedFields":
+                        updatedFields = BsonDocumentSerializer.Instance.Deserialize(context);
+                        break;
+
+                    case "removedFields":
+                        removedFields = __stringArraySerializer.Deserialize(context);
+                        break;
+
+                    default:
+                        throw new FormatException($"Invalid field name: \"{fieldName}\".");
+                }
+            }
+            reader.ReadEndDocument();
+
+            return new ChangeStreamUpdateDescription(updatedFields, removedFields);
+        }
+
+        /// <inheritdoc />
+        protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, ChangeStreamUpdateDescription value)
+        {
+            var writer = context.Writer;
+
+            writer.WriteStartDocument();
+            writer.WriteName("updatedFields");
+            BsonDocumentSerializer.Instance.Serialize(context, value.UpdatedFields);
+            writer.WriteName("removedFields");
+            __stringArraySerializer.Serialize(context, value.RemovedFields);
+            writer.WriteEndDocument();
+        }
+    }
+}

+ 88 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/SaslMapParser.cs

@@ -0,0 +1,88 @@
+/* Copyright 2018–present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace MongoDB.Driver.Core.Authentication
+{
+    /// <summary>
+    /// Per RFC5802: https://tools.ietf.org/html/rfc5802
+    /// "SCRAM is a SASL mechanism whose client response and server challenge
+    /// messages are text-based messages containing one or more attribute-
+    /// value pairs separated by commas. Each attribute has a one-letter
+    /// name."  
+    /// </summary>
+    internal static class SaslMapParser
+    {
+        private const int EOF = -1;
+
+        public static IDictionary<char, string> Parse(string text)
+        {
+            IDictionary<char, string> dict = new Dictionary<char, string>();
+
+            using (var reader = new StringReader(text))
+            {
+                while (reader.Peek() != EOF)
+                {
+                    dict.Add(ReadKeyValue(reader));
+                    if (reader.Peek() == ',')
+                    {
+                        Read(reader, ',');
+                    }
+                }
+            }
+
+            return dict;
+        }
+
+        private static KeyValuePair<char, string> ReadKeyValue(TextReader reader)
+        {
+            var key = ReadKey(reader);
+            Read(reader, '=');
+            var value = ReadValue(reader);
+            return new KeyValuePair<char, string>(key, value);
+        }
+
+        private static char ReadKey(TextReader reader)
+        {
+            // keys are of length 1.
+            return (char)reader.Read();
+        }
+
+        private static void Read(TextReader reader, char expected)
+        {
+            var ch = (char)reader.Read();
+            if (ch != expected)
+            {
+                throw new IOException(string.Format("Expected {0} but found {1}.", expected, ch));
+            }
+        }
+
+        private static string ReadValue(TextReader reader)
+        {
+            var sb = new StringBuilder();
+            var ch = reader.Peek();
+            while (ch != ',' && ch != EOF)
+            {
+                sb.Append((char)reader.Read());
+                ch = reader.Peek();
+            }
+
+            return sb.ToString();
+        }
+    }
+}

+ 805 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/SaslPrepHelper.cs

@@ -0,0 +1,805 @@
+/* Original work:
+ *   Copyright 2017 Tom Bentley
+ * 
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *   
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *   
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ * 
+ * Modified work: 
+ *   Copyright 2018–present MongoDB Inc.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *   
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *   
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+
+namespace MongoDB.Driver.Core.Authentication
+{
+    /// <summary>
+    /// Utility class for Sasl string preparation.
+    /// </summary>
+    internal static class SaslPrepHelper
+    {
+        private const int MinCodepoint = 0x00;
+        private const int MaxCodepoint = 0x10FFFF;
+        private const int SurrogateMinCodepoint = 0x00d800;
+        private const int SurrogateMaxCodePoint = 0x00dfff;
+        
+        /// <summary>
+        /// Return the SASLPrep-canonicalised version of the given <paramref name="str"/> for use as a query string.                          
+        /// This implements the {@code SASLPrep} algorithm defined in <a href="https://tools.ietf.org/html/rfc4013">RFC 4013</a>.          
+        /// See <a href="https://tools.ietf.org/html/rfc3454#section-7">RFC 3454, Section 7</a> for discussion of what a
+        /// query string is.
+        /// String normalization step in the .NET Standard version of the driver is skipped due to a lack of a string
+        /// normalization function.
+        /// </summary>
+        /// <param name="str">The string to canonicalise.</param>
+        /// <returns>The canonicalised string.</returns>
+        public static string SaslPrepQuery(string str)
+        {
+            return SaslPrep(str, true);
+        }
+
+        /// <summary>
+        /// Return the SASLPrep-canonicalised version of the given <paramref name="str"/> for use as a stored string.                          
+        /// This implements the SASLPrep algorithm defined in <a href="https://tools.ietf.org/html/rfc4013">RFC 4013</a>.
+        /// See <a href="https://tools.ietf.org/html/rfc3454#section-7">RFC 3454, Section 7</a> for discussion of what a
+        /// stored string is.
+        /// String normalization step in the .NET Standard version of the driver is skipped due to a lack of a string
+        /// normalization function.
+        /// </summary>
+        ///<param name="str">The string to canonicalise.</param>
+        ///<returns>The canonicalised string.</returns>
+        public static string SaslPrepStored(string str)
+        {
+            return SaslPrep(str, false);
+        }
+
+        private static string SaslPrep(string str, bool allowUnassigned) {
+            var chars = str.ToCharArray();
+
+            // 1. Map
+            // non-ASCII space chars mapped to space
+            for (var i = 0; i < str.Length; i++)
+            {
+                var ch = str[i];
+                if (NonAsciiSpace(ch)) 
+                {
+                    chars[i] = ' ';
+                }
+            }
+
+            var length = 0;
+            for (var i = 0; i < str.Length; i++)
+            {
+                var ch = chars[i];
+                if (!MappedToNothing(ch))
+                {
+                    chars[length++] = ch;
+                }
+            }
+
+            var mappedString = new string(chars.Take(length).ToArray()); 
+            // 2. Normalize
+#if NET452
+            var normalized = mappedString.Normalize(NormalizationForm.FormKC);
+#else
+            // String normalization step in the .NET Standard version of the driver is skipped due to a lack of a string
+            // normalization function.
+            var normalized = mappedString;
+#endif
+            var containsRandALCat = false;
+            var containsLCat = false;
+            var initialRandALCat = false;
+            for (var i = 0; i < normalized.Length;)
+            {
+                int codepoint = char.ConvertToUtf32(normalized, i);
+                // 3. Prohibit
+                if (Prohibited(codepoint))
+                {
+                    throw new ArgumentException("Prohibited character at position " + i);
+                }
+
+                // 4. Check bidi
+                var isRandALcat = IsRandALcat(codepoint);
+                containsRandALCat |= isRandALcat;
+                containsLCat |= IsLCat(codepoint);
+
+                initialRandALCat |= i == 0 && isRandALcat;
+                if (!allowUnassigned && !IsDefined(codepoint))
+                {
+                    throw new ArgumentException("Character at position " + i + " is unassigned");
+                }   
+
+                i += CharCount(codepoint);
+
+                if (initialRandALCat && i >= normalized.Length && !isRandALcat)
+                {
+                    throw new ArgumentException("First character is RandALCat, but last character is not");
+                }      
+            }
+
+            if (containsRandALCat && containsLCat)
+            {
+                throw new ArgumentException("Contains both RandALCat characters and LCat characters");
+            }
+                
+            return normalized;
+        }
+        
+        /// <summary>
+        /// Return true if the given <paramref name="ch"/> is an ASCII control character as defined by
+        /// <a href="https://tools.ietf.org/html/rfc3454#appendix-C.2.1">RFC 3454, Appendix C.2.1</a>. 
+        /// </summary>
+        /// <param name="ch">The character.</param>
+        /// <returns>Whether the given character is an ASCII control character.</returns>
+        private static bool AsciiControl(char ch)
+        {
+            return ch <= '\u001F' || ch == '\u007F';
+        }
+        
+        /// <summary>
+        /// Return true if the given <paramref name="codepoint"/> is a "change display properties" or a deprecated
+        /// character as defined by <a href="https://tools.ietf.org/html/rfc3454#appendix-C.8">RFC 3454, Appendix C.8</a>.
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns>Whether the codepoint is a "change display properties" or a deprecated character.</returns>
+        private static bool ChangeDisplayProperties(int codepoint)
+        {
+            return codepoint == 0x0340
+                || codepoint == 0x0341
+                || codepoint == 0x200E
+                || codepoint == 0x200F
+                || codepoint == 0x202A
+                || codepoint == 0x202B
+                || codepoint == 0x202C
+                || codepoint == 0x202D
+                || codepoint == 0x202E
+                || codepoint == 0x206A
+                || codepoint == 0x206B
+                || codepoint == 0x206C
+                || codepoint == 0x206D
+                || codepoint == 0x206E
+                || codepoint == 0x206F;
+        }
+
+        /// <summary>
+        /// Returns the number of characters required to represent a specified Unicode character.
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns>Number of characters required to represent a specified Unicode character.</returns>
+        private static int CharCount(int codepoint)
+        {
+            return codepoint >= 0x10000 ? 2 : 1;
+        }
+        
+        /// <summary>
+        /// Return true if the given <paramref name="codepoint"/> is inappropriate for canonical representation
+        /// characters as defined by <a href="https://tools.ietf.org/html/rfc3454#appendix-C.7">RFC 3454, Appendix C.7</a>. 
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns></returns>
+        private static bool InappropriateForCanonical(int codepoint)
+        {
+            return 0x2FF0 <= codepoint && codepoint <= 0x2FFB;
+        }
+
+        /// <summary>
+        /// Return true if the given <paramref name="codepoint"/> is inappropriate for plain text characters as defined
+        /// by <a href="https://tools.ietf.org/html/rfc3454#appendix-C.6">RFC 3454, Appendix C.6</a>.
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns></returns>
+        private static bool InappropriateForPlainText(int codepoint)
+        {
+            return codepoint == 0xFFF9
+                || codepoint == 0xFFFA
+                || codepoint == 0xFFFB
+                || codepoint == 0xFFFC
+                || codepoint == 0xFFFD;
+        }
+
+        /// <summary>
+        /// Returns whether or not a Unicode character represented by a codepoint is defined in Unicode.
+        /// A character is considered to be defined if its Unicode designation is "Cn" (other, not assigned) OR if it is
+        /// part of a surrogate pair.
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns>Whether or not the Unicode character represnted by codepoint is defined in Unicode.</returns>
+        private static bool IsDefined(int codepoint)
+        {   
+            return IsSurrogateCodepoint(codepoint) || 
+                  CharUnicodeInfo.GetUnicodeCategory(char.ConvertFromUtf32(codepoint), 0) != UnicodeCategory.OtherNotAssigned;
+        }
+
+        /// <summary>
+        /// Returns whether or not a Unicode character represented by a codepoint is an "LCat" character.
+        /// See <a href="https://tools.ietf.org/html/rfc3454#section-6">RFC 3454: Section 6</a> and
+        /// <a href="https://tools.ietf.org/html/rfc3454#appendix-D.2">RFC 3454: Appendix D.2 </a> for more details.
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns>Whether or not the character is an "LCat" character.</returns>
+        private static bool IsLCat(int codepoint)
+        {
+            return 0x0041 <= codepoint && codepoint <= 0x005A ||
+                0x0061 <= codepoint && codepoint <= 0x007A ||
+                codepoint == 0x00AA ||
+                codepoint == 0x00B5 ||
+                codepoint == 0x00BA ||
+                0x00C0 <= codepoint && codepoint <= 0x00D6 ||
+                0x00D8 <= codepoint && codepoint <= 0x00F6 ||
+                0x00F8 <= codepoint && codepoint <= 0x0220 ||
+                0x0222 <= codepoint && codepoint <= 0x0233 ||
+                0x0250 <= codepoint && codepoint <= 0x02AD ||
+                0x02B0 <= codepoint && codepoint <= 0x02B8 ||
+                0x02BB <= codepoint && codepoint <= 0x02C1 ||
+                0x02D0 <= codepoint && codepoint <= 0x02D1 ||
+                0x02E0 <= codepoint && codepoint <= 0x02E4 ||
+                codepoint == 0x02EE ||
+                codepoint == 0x037A ||
+                codepoint == 0x0386 ||
+                0x0388 <= codepoint && codepoint <= 0x038A ||
+                codepoint == 0x038C ||
+                0x038E <= codepoint && codepoint <= 0x03A1 ||
+                0x03A3 <= codepoint && codepoint <= 0x03CE ||
+                0x03D0 <= codepoint && codepoint <= 0x03F5 ||
+                0x0400 <= codepoint && codepoint <= 0x0482 ||
+                0x048A <= codepoint && codepoint <= 0x04CE ||
+                0x04D0 <= codepoint && codepoint <= 0x04F5 ||
+                0x04F8 <= codepoint && codepoint <= 0x04F9 ||
+                0x0500 <= codepoint && codepoint <= 0x050F ||
+                0x0531 <= codepoint && codepoint <= 0x0556 ||
+                0x0559 <= codepoint && codepoint <= 0x055F ||
+                0x0561 <= codepoint && codepoint <= 0x0587 ||
+                codepoint == 0x0589 ||
+                codepoint == 0x0903 ||
+                0x0905 <= codepoint && codepoint <= 0x0939 ||
+                0x093D <= codepoint && codepoint <= 0x0940 ||
+                0x0949 <= codepoint && codepoint <= 0x094C ||
+                codepoint == 0x0950 ||
+                0x0958 <= codepoint && codepoint <= 0x0961 ||
+                0x0964 <= codepoint && codepoint <= 0x0970 ||
+                0x0982 <= codepoint && codepoint <= 0x0983 ||
+                0x0985 <= codepoint && codepoint <= 0x098C ||
+                0x098F <= codepoint && codepoint <= 0x0990 ||
+                0x0993 <= codepoint && codepoint <= 0x09A8 ||
+                0x09AA <= codepoint && codepoint <= 0x09B0 ||
+                codepoint == 0x09B2 ||
+                0x09B6 <= codepoint && codepoint <= 0x09B9 ||
+                0x09BE <= codepoint && codepoint <= 0x09C0 ||
+                0x09C7 <= codepoint && codepoint <= 0x09C8 ||
+                0x09CB <= codepoint && codepoint <= 0x09CC ||
+                codepoint == 0x09D7 ||
+                0x09DC <= codepoint && codepoint <= 0x09DD ||
+                0x09DF <= codepoint && codepoint <= 0x09E1 ||
+                0x09E6 <= codepoint && codepoint <= 0x09F1 ||
+                0x09F4 <= codepoint && codepoint <= 0x09FA ||
+                0x0A05 <= codepoint && codepoint <= 0x0A0A ||
+                0x0A0F <= codepoint && codepoint <= 0x0A10 ||
+                0x0A13 <= codepoint && codepoint <= 0x0A28 ||
+                0x0A2A <= codepoint && codepoint <= 0x0A30 ||
+                0x0A32 <= codepoint && codepoint <= 0x0A33 ||
+                0x0A35 <= codepoint && codepoint <= 0x0A36 ||
+                0x0A38 <= codepoint && codepoint <= 0x0A39 ||
+                0x0A3E <= codepoint && codepoint <= 0x0A40 ||
+                0x0A59 <= codepoint && codepoint <= 0x0A5C ||
+                codepoint == 0x0A5E ||
+                0x0A66 <= codepoint && codepoint <= 0x0A6F ||
+                0x0A72 <= codepoint && codepoint <= 0x0A74 ||
+                codepoint == 0x0A83 ||
+                0x0A85 <= codepoint && codepoint <= 0x0A8B ||
+                codepoint == 0x0A8D ||
+                0x0A8F <= codepoint && codepoint <= 0x0A91 ||
+                0x0A93 <= codepoint && codepoint <= 0x0AA8 ||
+                0x0AAA <= codepoint && codepoint <= 0x0AB0 ||
+                0x0AB2 <= codepoint && codepoint <= 0x0AB3 ||
+                0x0AB5 <= codepoint && codepoint <= 0x0AB9 ||
+                0x0ABD <= codepoint && codepoint <= 0x0AC0 ||
+                codepoint == 0x0AC9 ||
+                0x0ACB <= codepoint && codepoint <= 0x0ACC ||
+                codepoint == 0x0AD0 ||
+                codepoint == 0x0AE0 ||
+                0x0AE6 <= codepoint && codepoint <= 0x0AEF ||
+                0x0B02 <= codepoint && codepoint <= 0x0B03 ||
+                0x0B05 <= codepoint && codepoint <= 0x0B0C ||
+                0x0B0F <= codepoint && codepoint <= 0x0B10 ||
+                0x0B13 <= codepoint && codepoint <= 0x0B28 ||
+                0x0B2A <= codepoint && codepoint <= 0x0B30 ||
+                0x0B32 <= codepoint && codepoint <= 0x0B33 ||
+                0x0B36 <= codepoint && codepoint <= 0x0B39 ||
+                0x0B3D <= codepoint && codepoint <= 0x0B3E ||
+                codepoint == 0x0B40 ||
+                0x0B47 <= codepoint && codepoint <= 0x0B48 ||
+                0x0B4B <= codepoint && codepoint <= 0x0B4C ||
+                codepoint == 0x0B57 ||
+                0x0B5C <= codepoint && codepoint <= 0x0B5D ||
+                0x0B5F <= codepoint && codepoint <= 0x0B61 ||
+                0x0B66 <= codepoint && codepoint <= 0x0B70 ||
+                codepoint == 0x0B83 ||
+                0x0B85 <= codepoint && codepoint <= 0x0B8A ||
+                0x0B8E <= codepoint && codepoint <= 0x0B90 ||
+                0x0B92 <= codepoint && codepoint <= 0x0B95 ||
+                0x0B99 <= codepoint && codepoint <= 0x0B9A ||
+                codepoint == 0x0B9C ||
+                0x0B9E <= codepoint && codepoint <= 0x0B9F ||
+                0x0BA3 <= codepoint && codepoint <= 0x0BA4 ||
+                0x0BA8 <= codepoint && codepoint <= 0x0BAA ||
+                0x0BAE <= codepoint && codepoint <= 0x0BB5 ||
+                0x0BB7 <= codepoint && codepoint <= 0x0BB9 ||
+                0x0BBE <= codepoint && codepoint <= 0x0BBF ||
+                0x0BC1 <= codepoint && codepoint <= 0x0BC2 ||
+                0x0BC6 <= codepoint && codepoint <= 0x0BC8 ||
+                0x0BCA <= codepoint && codepoint <= 0x0BCC ||
+                codepoint == 0x0BD7 ||
+                0x0BE7 <= codepoint && codepoint <= 0x0BF2 ||
+                0x0C01 <= codepoint && codepoint <= 0x0C03 ||
+                0x0C05 <= codepoint && codepoint <= 0x0C0C ||
+                0x0C0E <= codepoint && codepoint <= 0x0C10 ||
+                0x0C12 <= codepoint && codepoint <= 0x0C28 ||
+                0x0C2A <= codepoint && codepoint <= 0x0C33 ||
+                0x0C35 <= codepoint && codepoint <= 0x0C39 ||
+                0x0C41 <= codepoint && codepoint <= 0x0C44 ||
+                0x0C60 <= codepoint && codepoint <= 0x0C61 ||
+                0x0C66 <= codepoint && codepoint <= 0x0C6F ||
+                0x0C82 <= codepoint && codepoint <= 0x0C83 ||
+                0x0C85 <= codepoint && codepoint <= 0x0C8C ||
+                0x0C8E <= codepoint && codepoint <= 0x0C90 ||
+                0x0C92 <= codepoint && codepoint <= 0x0CA8 ||
+                0x0CAA <= codepoint && codepoint <= 0x0CB3 ||
+                0x0CB5 <= codepoint && codepoint <= 0x0CB9 ||
+                codepoint == 0x0CBE ||
+                0x0CC0 <= codepoint && codepoint <= 0x0CC4 ||
+                0x0CC7 <= codepoint && codepoint <= 0x0CC8 ||
+                0x0CCA <= codepoint && codepoint <= 0x0CCB ||
+                0x0CD5 <= codepoint && codepoint <= 0x0CD6 ||
+                codepoint == 0x0CDE ||
+                0x0CE0 <= codepoint && codepoint <= 0x0CE1 ||
+                0x0CE6 <= codepoint && codepoint <= 0x0CEF ||
+                0x0D02 <= codepoint && codepoint <= 0x0D03 ||
+                0x0D05 <= codepoint && codepoint <= 0x0D0C ||
+                0x0D0E <= codepoint && codepoint <= 0x0D10 ||
+                0x0D12 <= codepoint && codepoint <= 0x0D28 ||
+                0x0D2A <= codepoint && codepoint <= 0x0D39 ||
+                0x0D3E <= codepoint && codepoint <= 0x0D40 ||
+                0x0D46 <= codepoint && codepoint <= 0x0D48 ||
+                0x0D4A <= codepoint && codepoint <= 0x0D4C ||
+                codepoint == 0x0D57 ||
+                0x0D60 <= codepoint && codepoint <= 0x0D61 ||
+                0x0D66 <= codepoint && codepoint <= 0x0D6F ||
+                0x0D82 <= codepoint && codepoint <= 0x0D83 ||
+                0x0D85 <= codepoint && codepoint <= 0x0D96 ||
+                0x0D9A <= codepoint && codepoint <= 0x0DB1 ||
+                0x0DB3 <= codepoint && codepoint <= 0x0DBB ||
+                codepoint == 0x0DBD ||
+                0x0DC0 <= codepoint && codepoint <= 0x0DC6 ||
+                0x0DCF <= codepoint && codepoint <= 0x0DD1 ||
+                0x0DD8 <= codepoint && codepoint <= 0x0DDF ||
+                0x0DF2 <= codepoint && codepoint <= 0x0DF4 ||
+                0x0E01 <= codepoint && codepoint <= 0x0E30 ||
+                0x0E32 <= codepoint && codepoint <= 0x0E33 ||
+                0x0E40 <= codepoint && codepoint <= 0x0E46 ||
+                0x0E4F <= codepoint && codepoint <= 0x0E5B ||
+                0x0E81 <= codepoint && codepoint <= 0x0E82 ||
+                codepoint == 0x0E84 ||
+                0x0E87 <= codepoint && codepoint <= 0x0E88 ||
+                codepoint == 0x0E8A ||
+                codepoint == 0x0E8D ||
+                0x0E94 <= codepoint && codepoint <= 0x0E97 ||
+                0x0E99 <= codepoint && codepoint <= 0x0E9F ||
+                0x0EA1 <= codepoint && codepoint <= 0x0EA3 ||
+                codepoint == 0x0EA5 ||
+                codepoint == 0x0EA7 ||
+                0x0EAA <= codepoint && codepoint <= 0x0EAB ||
+                0x0EAD <= codepoint && codepoint <= 0x0EB0 ||
+                0x0EB2 <= codepoint && codepoint <= 0x0EB3 ||
+                codepoint == 0x0EBD ||
+                0x0EC0 <= codepoint && codepoint <= 0x0EC4 ||
+                codepoint == 0x0EC6 ||
+                0x0ED0 <= codepoint && codepoint <= 0x0ED9 ||
+                0x0EDC <= codepoint && codepoint <= 0x0EDD ||
+                0x0F00 <= codepoint && codepoint <= 0x0F17 ||
+                0x0F1A <= codepoint && codepoint <= 0x0F34 ||
+                codepoint == 0x0F36 ||
+                codepoint == 0x0F38 ||
+                0x0F3E <= codepoint && codepoint <= 0x0F47 ||
+                0x0F49 <= codepoint && codepoint <= 0x0F6A ||
+                codepoint == 0x0F7F ||
+                codepoint == 0x0F85 ||
+                0x0F88 <= codepoint && codepoint <= 0x0F8B ||
+                0x0FBE <= codepoint && codepoint <= 0x0FC5 ||
+                0x0FC7 <= codepoint && codepoint <= 0x0FCC ||
+                codepoint == 0x0FCF ||
+                0x1000 <= codepoint && codepoint <= 0x1021 ||
+                0x1023 <= codepoint && codepoint <= 0x1027 ||
+                0x1029 <= codepoint && codepoint <= 0x102A ||
+                codepoint == 0x102C ||
+                codepoint == 0x1031 ||
+                codepoint == 0x1038 ||
+                0x1040 <= codepoint && codepoint <= 0x1057 ||
+                0x10A0 <= codepoint && codepoint <= 0x10C5 ||
+                0x10D0 <= codepoint && codepoint <= 0x10F8 ||
+                codepoint == 0x10FB ||
+                0x1100 <= codepoint && codepoint <= 0x1159 ||
+                0x115F <= codepoint && codepoint <= 0x11A2 ||
+                0x11A8 <= codepoint && codepoint <= 0x11F9 ||
+                0x1200 <= codepoint && codepoint <= 0x1206 ||
+                0x1208 <= codepoint && codepoint <= 0x1246 ||
+                codepoint == 0x1248 ||
+                0x124A <= codepoint && codepoint <= 0x124D ||
+                0x1250 <= codepoint && codepoint <= 0x1256 ||
+                codepoint == 0x1258 ||
+                0x125A <= codepoint && codepoint <= 0x125D ||
+                0x1260 <= codepoint && codepoint <= 0x1286 ||
+                codepoint == 0x1288 ||
+                0x128A <= codepoint && codepoint <= 0x128D ||
+                0x1290 <= codepoint && codepoint <= 0x12AE ||
+                codepoint == 0x12B0 ||
+                0x12B2 <= codepoint && codepoint <= 0x12B5 ||
+                0x12B8 <= codepoint && codepoint <= 0x12BE ||
+                codepoint == 0x12C0 ||
+                0x12C2 <= codepoint && codepoint <= 0x12C5 ||
+                0x12C8 <= codepoint && codepoint <= 0x12CE ||
+                0x12D0 <= codepoint && codepoint <= 0x12D6 ||
+                0x12D8 <= codepoint && codepoint <= 0x12EE ||
+                0x12F0 <= codepoint && codepoint <= 0x130E ||
+                codepoint == 0x1310 ||
+                0x1312 <= codepoint && codepoint <= 0x1315 ||
+                0x1318 <= codepoint && codepoint <= 0x131E ||
+                0x1320 <= codepoint && codepoint <= 0x1346 ||
+                0x1348 <= codepoint && codepoint <= 0x135A ||
+                0x1361 <= codepoint && codepoint <= 0x137C ||
+                0x13A0 <= codepoint && codepoint <= 0x13F4 ||
+                0x1401 <= codepoint && codepoint <= 0x1676 ||
+                0x1681 <= codepoint && codepoint <= 0x169A ||
+                0x16A0 <= codepoint && codepoint <= 0x16F0 ||
+                0x1700 <= codepoint && codepoint <= 0x170C ||
+                0x170E <= codepoint && codepoint <= 0x1711 ||
+                0x1720 <= codepoint && codepoint <= 0x1731 ||
+                0x1735 <= codepoint && codepoint <= 0x1736 ||
+                0x1740 <= codepoint && codepoint <= 0x1751 ||
+                0x1760 <= codepoint && codepoint <= 0x176C ||
+                0x176E <= codepoint && codepoint <= 0x1770 ||
+                0x1780 <= codepoint && codepoint <= 0x17B6 ||
+                0x17BE <= codepoint && codepoint <= 0x17C5 ||
+                0x17C7 <= codepoint && codepoint <= 0x17C8 ||
+                0x17D4 <= codepoint && codepoint <= 0x17DA ||
+                codepoint == 0x17DC ||
+                0x17E0 <= codepoint && codepoint <= 0x17E9 ||
+                0x1810 <= codepoint && codepoint <= 0x1819 ||
+                0x1820 <= codepoint && codepoint <= 0x1877 ||
+                0x1880 <= codepoint && codepoint <= 0x18A8 ||
+                0x1E00 <= codepoint && codepoint <= 0x1E9B ||
+                0x1EA0 <= codepoint && codepoint <= 0x1EF9 ||
+                0x1F00 <= codepoint && codepoint <= 0x1F15 ||
+                0x1F18 <= codepoint && codepoint <= 0x1F1D ||
+                0x1F20 <= codepoint && codepoint <= 0x1F45 ||
+                0x1F48 <= codepoint && codepoint <= 0x1F4D ||
+                0x1F50 <= codepoint && codepoint <= 0x1F57 ||
+                codepoint == 0x1F59 ||
+                codepoint == 0x1F5B ||
+                codepoint == 0x1F5D ||
+                0x1F5F <= codepoint && codepoint <= 0x1F7D ||
+                0x1F80 <= codepoint && codepoint <= 0x1FB4 ||
+                0x1FB6 <= codepoint && codepoint <= 0x1FBC ||
+                codepoint == 0x1FBE ||
+                0x1FC2 <= codepoint && codepoint <= 0x1FC4 ||
+                0x1FC6 <= codepoint && codepoint <= 0x1FCC ||
+                0x1FD0 <= codepoint && codepoint <= 0x1FD3 ||
+                0x1FD6 <= codepoint && codepoint <= 0x1FDB ||
+                0x1FE0 <= codepoint && codepoint <= 0x1FEC ||
+                0x1FF2 <= codepoint && codepoint <= 0x1FF4 ||
+                0x1FF6 <= codepoint && codepoint <= 0x1FFC ||
+                codepoint == 0x200E ||
+                codepoint == 0x2071 ||
+                codepoint == 0x207F ||
+                codepoint == 0x2102 ||
+                codepoint == 0x2107 ||
+                0x210A <= codepoint && codepoint <= 0x2113 ||
+                codepoint == 0x2115 ||
+                0x2119 <= codepoint && codepoint <= 0x211D ||
+                codepoint == 0x2124 ||
+                codepoint == 0x2126 ||
+                codepoint == 0x2128 ||
+                0x212A <= codepoint && codepoint <= 0x212D ||
+                0x212F <= codepoint && codepoint <= 0x2131 ||
+                0x2133 <= codepoint && codepoint <= 0x2139 ||
+                0x213D <= codepoint && codepoint <= 0x213F ||
+                0x2145 <= codepoint && codepoint <= 0x2149 ||
+                0x2160 <= codepoint && codepoint <= 0x2183 ||
+                0x2336 <= codepoint && codepoint <= 0x237A ||
+                codepoint == 0x2395 ||
+                0x249C <= codepoint && codepoint <= 0x24E9 ||
+                0x3005 <= codepoint && codepoint <= 0x3007 ||
+                0x3021 <= codepoint && codepoint <= 0x3029 ||
+                0x3031 <= codepoint && codepoint <= 0x3035 ||
+                0x3038 <= codepoint && codepoint <= 0x303C ||
+                0x3041 <= codepoint && codepoint <= 0x3096 ||
+                0x309D <= codepoint && codepoint <= 0x309F ||
+                0x30A1 <= codepoint && codepoint <= 0x30FA ||
+                0x30FC <= codepoint && codepoint <= 0x30FF ||
+                0x3105 <= codepoint && codepoint <= 0x312C ||
+                0x3131 <= codepoint && codepoint <= 0x318E ||
+                0x3190 <= codepoint && codepoint <= 0x31B7 ||
+                0x31F0 <= codepoint && codepoint <= 0x321C ||
+                0x3220 <= codepoint && codepoint <= 0x3243 ||
+                0x3260 <= codepoint && codepoint <= 0x327B ||
+                0x327F <= codepoint && codepoint <= 0x32B0 ||
+                0x32C0 <= codepoint && codepoint <= 0x32CB ||
+                0x32D0 <= codepoint && codepoint <= 0x32FE ||
+                0x3300 <= codepoint && codepoint <= 0x3376 ||
+                0x337B <= codepoint && codepoint <= 0x33DD ||
+                0x33E0 <= codepoint && codepoint <= 0x33FE ||
+                0x3400 <= codepoint && codepoint <= 0x4DB5 ||
+                0x4E00 <= codepoint && codepoint <= 0x9FA5 ||
+                0xA000 <= codepoint && codepoint <= 0xA48C ||
+                0xAC00 <= codepoint && codepoint <= 0xD7A3 ||
+                0xD800 <= codepoint && codepoint <= 0xFA2D ||
+                0xFA30 <= codepoint && codepoint <= 0xFA6A ||
+                0xFB00 <= codepoint && codepoint <= 0xFB06 ||
+                0xFB13 <= codepoint && codepoint <= 0xFB17 ||
+                0xFF21 <= codepoint && codepoint <= 0xFF3A ||
+                0xFF41 <= codepoint && codepoint <= 0xFF5A ||
+                0xFF66 <= codepoint && codepoint <= 0xFFBE ||
+                0xFFC2 <= codepoint && codepoint <= 0xFFC7 ||
+                0xFFCA <= codepoint && codepoint <= 0xFFCF ||
+                0xFFD2 <= codepoint && codepoint <= 0xFFD7 ||
+                0xFFDA <= codepoint && codepoint <= 0xFFDC ||
+                0x10300 <= codepoint && codepoint <= 0x1031E ||
+                0x10320 <= codepoint && codepoint <= 0x10323 ||
+                0x10330 <= codepoint && codepoint <= 0x1034A ||
+                0x10400 <= codepoint && codepoint <= 0x10425 ||
+                0x10428 <= codepoint && codepoint <= 0x1044D ||
+                0x1D000 <= codepoint && codepoint <= 0x1D0F5 ||
+                0x1D100 <= codepoint && codepoint <= 0x1D126 ||
+                0x1D12A <= codepoint && codepoint <= 0x1D166 ||
+                0x1D16A <= codepoint && codepoint <= 0x1D172 ||
+                0x1D183 <= codepoint && codepoint <= 0x1D184 ||
+                0x1D18C <= codepoint && codepoint <= 0x1D1A9 ||
+                0x1D1AE <= codepoint && codepoint <= 0x1D1DD ||
+                0x1D400 <= codepoint && codepoint <= 0x1D454 ||
+                0x1D456 <= codepoint && codepoint <= 0x1D49C ||
+                0x1D49E <= codepoint && codepoint <= 0x1D49F ||
+                codepoint == 0x1D4A2 ||
+                0x1D4A5 <= codepoint && codepoint <= 0x1D4A6 ||
+                0x1D4A9 <= codepoint && codepoint <= 0x1D4AC ||
+                0x1D4AE <= codepoint && codepoint <= 0x1D4B9 ||
+                codepoint == 0x1D4BB ||
+                0x1D4BD <= codepoint && codepoint <= 0x1D4C0 ||
+                0x1D4C2 <= codepoint && codepoint <= 0x1D4C3 ||
+                0x1D4C5 <= codepoint && codepoint <= 0x1D505 ||
+                0x1D507 <= codepoint && codepoint <= 0x1D50A ||
+                0x1D50D <= codepoint && codepoint <= 0x1D514 ||
+                0x1D516 <= codepoint && codepoint <= 0x1D51C ||
+                0x1D51E <= codepoint && codepoint <= 0x1D539 ||
+                0x1D53B <= codepoint && codepoint <= 0x1D53E ||
+                0x1D540 <= codepoint && codepoint <= 0x1D544 ||
+                codepoint == 0x1D546 ||
+                0x1D54A <= codepoint && codepoint <= 0x1D550 ||
+                0x1D552 <= codepoint && codepoint <= 0x1D6A3 ||
+                0x1D6A8 <= codepoint && codepoint <= 0x1D7C9 ||
+                0x20000 <= codepoint && codepoint <= 0x2A6D6 ||
+                0x2F800 <= codepoint && codepoint <= 0x2FA1D ||
+                0xF0000 <= codepoint && codepoint <= 0xFFFFD ||
+                0x100000 <= codepoint && codepoint <= 0x10FFFD;
+        }
+  
+        /// <summary>
+        /// Returns whether or not a Unicode character represented by a codepoint is an "RandALCat" character.
+        /// See <a href="https://tools.ietf.org/html/rfc3454#section-6">RFC 3454: Section 6</a> and
+        /// <a href="https://tools.ietf.org/html/rfc3454#appendix-D.1">RFC 3454: Appendix D.1 </a> for more details.
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns>Whether or not the character is an "RandALCat" character.</returns>
+        private static bool IsRandALcat(int codepoint)
+        {
+            return codepoint == 0x05BE || 
+                codepoint == 0x05C0 ||
+                codepoint == 0x05C3 ||
+                0x05D0 <= codepoint && codepoint <= 0x05EA ||
+                0x05F0 <= codepoint && codepoint <= 0x05F4 ||
+                codepoint == 0x061B ||
+                codepoint == 0x061F ||
+                0x0621 <= codepoint && codepoint <= 0x063A ||
+                0x0640 <= codepoint && codepoint <= 0x064A ||
+                0x066D <= codepoint && codepoint <= 0x066F ||
+                0x0671 <= codepoint && codepoint <= 0x06D5 ||
+                codepoint == 0x06DD ||
+                0x06E5 <= codepoint && codepoint <= 0x06E6 ||
+                0x06FA <= codepoint && codepoint <= 0x06FE ||
+                0x0700 <= codepoint && codepoint <= 0x070D ||
+                codepoint == 0x0710 ||
+                0x0712 <= codepoint && codepoint <= 0x072C ||
+                0x0780 <= codepoint && codepoint <= 0x07A5 ||
+                codepoint == 0x07B1 ||
+                codepoint == 0x200F ||
+                codepoint == 0xFB1D ||
+                0xFB1F <= codepoint && codepoint <= 0xFB28 ||
+                0xFB2A <= codepoint && codepoint <= 0xFB36 ||
+                0xFB38 <= codepoint && codepoint <= 0xFB3C ||
+                codepoint == 0xFB3E ||
+                0xFB40 <= codepoint && codepoint <= 0xFB41 ||
+                0xFB43 <= codepoint && codepoint <= 0xFB44 ||
+                0xFB46 <= codepoint && codepoint <= 0xFBB1 ||
+                0xFBD3 <= codepoint && codepoint <= 0xFD3D ||
+                0xFD50 <= codepoint && codepoint <= 0xFD8F ||
+                0xFD92 <= codepoint && codepoint <= 0xFDC7 ||
+                0xFDF0 <= codepoint && codepoint <= 0xFDFC ||
+                0xFE70 <= codepoint && codepoint <= 0xFE74 || 
+                0xFE76 <= codepoint && codepoint <= 0xFEFC;
+        }
+
+        private static bool IsSurrogateCodepoint(int codepoint)
+        {
+            return SurrogateMinCodepoint <= codepoint && codepoint <= SurrogateMaxCodePoint;
+        }
+        
+        /// <summary>
+        ///  Return true if the given <paramref name="ch"/> is a "commonly mapped to nothing" character as defined by
+        ///  <a href="https://tools.ietf.org/html/rfc3454#appendix-B.1">RFC 3454, Appendix B.1</a>. 
+        /// </summary>
+        /// <param name="ch">The character.</param>
+        /// <returns>Whether the given character is a "commonly mapped to nothing" character.</returns>
+        private static bool MappedToNothing(char ch)
+        {
+            return ch == '\u00AD'
+                || ch == '\u034F'
+                || ch == '\u1806'
+                || ch == '\u180B'
+                || ch == '\u180C'
+                || ch == '\u180D'
+                || ch == '\u200B'
+                || ch == '\u200C'
+                || ch == '\u200D'
+                || ch == '\u2060'
+                || '\uFE00' <= ch && ch <= '\uFE0F'
+                || ch == '\uFEFF';
+        }
+        
+        /// <summary>
+        /// Return true if the given <paramref name="codepoint"/> is a non-ASCII control character as defined by
+        /// <a href="https://tools.ietf.org/html/rfc3454#appendix-C.2.2">RFC 3454, Appendix C.2.2</a>. 
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns>Whether the given character is a non-ASCII control character.</returns>
+        private static bool NonAsciiControl(int codepoint)
+        {
+            return 0x0080 <= codepoint && codepoint <= 0x009F
+                || codepoint == 0x06DD
+                || codepoint == 0x070F
+                || codepoint == 0x180E
+                || codepoint == 0x200C
+                || codepoint == 0x200D
+                || codepoint == 0x2028
+                || codepoint == 0x2029
+                || codepoint == 0x2060
+                || codepoint == 0x2061
+                || codepoint == 0x2062
+                || codepoint == 0x2063
+                || 0x206A <= codepoint && codepoint <= 0x206F
+                || codepoint == 0xFEFF
+                || 0xFFF9 <= codepoint && codepoint <= 0xFFFC
+                || 0x1D173 <= codepoint && codepoint <= 0x1D17A;
+        }
+        
+        /// <summary>
+        /// Return true if the given <paramref name="ch"/> is a non-ASCII space character as defined by
+        /// <a href="https://tools.ietf.org/html/rfc3454#appendix-C.1.2">RFC 3454, Appendix C.1.2</a>. 
+        /// </summary>
+        /// <param name="ch">The character.</param>
+        /// <returns>Whether the given character is a non-ASCII space character.</returns>
+        private static bool NonAsciiSpace(char ch)
+        {
+            return ch == '\u00A0'
+                || ch == '\u1680'
+                || '\u2000' <= ch && ch <= '\u200B'
+                || ch == '\u202F'
+                || ch == '\u205F'
+                || ch == '\u3000';
+        }
+
+        /// <summary>
+        /// Return true if the given <paramref name="codepoint"/> is a non-character code point as defined by
+        /// <a href="https://tools.ietf.org/html/rfc3454#appendix-C.4">RFC 3454, Appendix C.4</a>.
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns>Whether the given <paramref name="codepoint"/> is a non-character code point.</returns>
+        private static bool NonCharacterCodepoint(int codepoint)
+        {
+            return 0xFDD0 <= codepoint && codepoint <= 0xFDEF
+                || 0xFFFE <= codepoint && codepoint <= 0xFFFF
+                || 0x1FFFE <= codepoint && codepoint <= 0x1FFFF
+                || 0x2FFFE <= codepoint && codepoint <= 0x2FFFF
+                || 0x3FFFE <= codepoint && codepoint <= 0x3FFFF
+                || 0x4FFFE <= codepoint && codepoint <= 0x4FFFF
+                || 0x5FFFE <= codepoint && codepoint <= 0x5FFFF
+                || 0x6FFFE <= codepoint && codepoint <= 0x6FFFF
+                || 0x7FFFE <= codepoint && codepoint <= 0x7FFFF
+                || 0x8FFFE <= codepoint && codepoint <= 0x8FFFF
+                || 0x9FFFE <= codepoint && codepoint <= 0x9FFFF
+                || 0xAFFFE <= codepoint && codepoint <= 0xAFFFF
+                || 0xBFFFE <= codepoint && codepoint <= 0xBFFFF
+                || 0xCFFFE <= codepoint && codepoint <= 0xCFFFF
+                || 0xDFFFE <= codepoint && codepoint <= 0xDFFFF
+                || 0xEFFFE <= codepoint && codepoint <= 0xEFFFF
+                || 0xFFFFE <= codepoint && codepoint <= 0xFFFFF
+                || 0x10FFFE <= codepoint && codepoint <= 0x10FFFF;
+        }
+        
+        /// <summary>
+        /// Return true if the given <paramref name="codepoint"/> is a private use character as defined by
+        /// <a href="https://tools.ietf.org/html/rfc3454#appendix-C.3">RFC 3454, Appendix C.3</a>.
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns>Whether if the given codepoint is a private use character.</returns>
+        private static bool PrivateUse(int codepoint)
+        {
+            return 0xE000 <= codepoint && codepoint <= 0xF8FF
+                || 0xF000 <= codepoint && codepoint <= 0xFFFFD
+                || 0x100000 <= codepoint && codepoint <= 0x10FFFD;
+        }
+        
+        /// <summary>
+        /// Return true if the given <paramref name="codepoint"/> is a prohibited character as defined by
+        ///<a href="https://tools.ietf.org/html/rfc4013#section-2.3">RFC 4013, Section 2.3</a>. 
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns>Whether the codepoint is a prohibited character.</returns>
+        private static bool Prohibited(int codepoint)
+        {
+            return NonAsciiSpace((char) codepoint)
+                || AsciiControl((char) codepoint)
+                || NonAsciiControl(codepoint)
+                || PrivateUse(codepoint)
+                || NonCharacterCodepoint(codepoint)
+                || Surrogatecodepoint(codepoint)
+                || InappropriateForPlainText(codepoint)
+                || InappropriateForCanonical(codepoint)
+                || ChangeDisplayProperties(codepoint)
+                || Tagging(codepoint);
+        }
+
+        /// <summary>
+        /// Return true if the given <paramref name="codepoint"/> is a surrogate code point as defined by
+        /// <a href="https://tools.ietf.org/html/rfc3454#appendix-C.5">RFC 3454, Appendix C.5</a>.
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns>Whether the given <paramref name="codepoint"/> is a surrogate code point.</returns>
+        private static bool Surrogatecodepoint(int codepoint)
+        {
+            return 0xD800 <= codepoint && codepoint <= 0xDFFF;
+        }
+        
+        /// <summary>
+        /// Return true if the given <paramref name="codepoint"/> is a tagging character as defined by
+        /// <a href="https://tools.ietf.org/html/rfc3454#appendix-C.9">RFC 3454, Appendix C.9</a>.
+        /// </summary>
+        /// <param name="codepoint">The Unicode character's codepoint.</param>
+        /// <returns></returns>
+        private static bool Tagging(int codepoint)
+        {
+            return codepoint == 0xE0001
+                || 0xE0020 <= codepoint && codepoint <= 0xE007F;
+        }
+    }
+}

+ 129 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/ScramSha256Authenticator.cs

@@ -0,0 +1,129 @@
+/* Copyright 2018–present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Security.Cryptography;
+using System.Text;
+using MongoDB.Bson.IO;
+using MongoDB.Driver.Core.Authentication.Vendored;
+using MongoDB.Driver.Core.Connections;
+using MongoDB.Driver.Core.Misc;
+
+// use our vendored version of Rfc2898DeriveBytes because .NET Standard 1.5 and .NET Framework 4.5 do not support
+// a version of Rfc2898DeriveBytes that allows us to specify to hash algorithm to be used
+using Rfc2898DeriveBytes = MongoDB.Driver.Core.Authentication.Vendored.Rfc2898DeriveBytes;
+
+namespace MongoDB.Driver.Core.Authentication
+{
+    /// <summary>
+    /// A SCRAM-SHA256 SASL authenticator.
+    /// In .NET Standard, this class does not normalize the password in the credentials, so non-ASCII
+    /// passwords may not work unless they are normalized into Unicode Normalization Form KC beforehand.
+    /// </summary>
+    public sealed class ScramSha256Authenticator : ScramShaAuthenticator
+    {
+        // static properties
+        /// <summary>
+        /// Gets the name of the mechanism.
+        /// </summary>
+        /// <value>
+        /// The name of the mechanism.
+        /// </value>
+        public static string MechanismName => "SCRAM-SHA-256";
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScramSha256Authenticator"/> class.
+        /// In .NET Standard, this class does not normalize the password in <paramref name="credential"/>, so non-ASCII
+        /// passwords may not work unless they are normalized into Unicode Normalization Form KC beforehand.
+        /// </summary>
+        /// <param name="credential">The credential.</param>
+        public ScramSha256Authenticator(UsernamePasswordCredential credential)
+            : this(credential, new DefaultRandomStringGenerator())
+        {
+        }
+
+        internal ScramSha256Authenticator(UsernamePasswordCredential credential, IRandomStringGenerator randomStringGenerator)
+            : base(credential, HashAlgorithmName.SHA256, randomStringGenerator, H256, Hi256, Hmac256)
+        {
+        }
+
+        private static byte[] H256(byte[] data)
+        {
+            using (var sha256 = SHA256.Create())
+            {
+                return sha256.ComputeHash(data);
+            }
+        }
+
+        private static byte[] Hi256(UsernamePasswordCredential credential, byte[] salt, int iterations)
+        {
+#if NET452
+            var passwordIntPtr = Marshal.SecureStringToGlobalAllocUnicode(credential.SaslPreppedPassword);
+#else
+            var passwordIntPtr = SecureStringMarshal.SecureStringToGlobalAllocUnicode(credential.SaslPreppedPassword);
+#endif
+            try
+            {
+                var passwordChars = new char[credential.SaslPreppedPassword.Length];
+                var passwordCharsHandle = GCHandle.Alloc(passwordChars, GCHandleType.Pinned);
+                try
+                {
+                    Marshal.Copy(passwordIntPtr, passwordChars, 0, credential.SaslPreppedPassword.Length);
+                    return Hi256(passwordChars, salt, iterations);
+                }
+                finally
+                {
+                    Array.Clear(passwordChars, 0, passwordChars.Length);
+                    passwordCharsHandle.Free();
+                }
+            }
+            finally
+            {
+                Marshal.ZeroFreeGlobalAllocUnicode(passwordIntPtr);
+            }
+        }
+
+        private static byte[] Hi256(char[] passwordChars, byte[] salt, int iterations)
+        {
+            var passwordBytes = new byte[Utf8Encodings.Strict.GetByteCount(passwordChars)];
+            var passwordBytesHandle = GCHandle.Alloc(passwordBytes, GCHandleType.Pinned);
+            try
+            {
+                Utf8Encodings.Strict.GetBytes(passwordChars, 0, passwordChars.Length, passwordBytes, 0);
+
+                // 32 is the length of output of a sha-256 hmac
+                return new Rfc2898DeriveBytes(passwordBytes, salt, iterations, HashAlgorithmName.SHA256).GetBytes(32); 				
+            }
+            finally
+            {
+                Array.Clear(passwordBytes, 0, passwordBytes.Length);
+                passwordBytesHandle.Free();
+            }
+        }
+
+        private static byte[] Hmac256(UTF8Encoding encoding, byte[] data, string key)
+        {
+            using (var hmac = new HMACSHA256(data))
+            {
+                return hmac.ComputeHash(encoding.GetBytes(key));
+            }
+        }
+    }
+}

+ 290 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/ScramShaAuthenticator.cs

@@ -0,0 +1,290 @@
+/* Copyright 2018–present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+using MongoDB.Bson.IO;
+using MongoDB.Driver.Core.Authentication.Vendored;
+using MongoDB.Driver.Core.Connections;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.Authentication
+{
+    /// <summary>
+    /// A SCRAM-SHA SASL authenticator.
+    /// </summary>
+    public abstract class ScramShaAuthenticator : SaslAuthenticator
+    {
+        /// <summary>
+        /// An H function as defined in RFC5802.
+        /// </summary>
+        /// <param name="data">The data to hash. Also called "str" in RFC5802.</param>
+        protected internal delegate byte[] H(byte[] data);
+        
+        /// <summary>
+        /// A Hi function used to compute the SaltedPassword as defined in RFC5802, except with "str" parameter replaced
+        /// with a UsernamePassword credential so that the password can be optionally digested/prepped in a secure fashion
+        /// before being consumed as the "str" parameter would be in RFC5802's Hi.
+        /// </summary>
+        /// <param name="credentials">The credential to be digested/prepped before being consumed as the "str"
+        /// parameter would be in RFC5802's Hi</param>
+        /// <param name="salt">The salt.</param>
+        /// <param name="iterations">The iteration count.</param>
+        protected internal delegate byte[] Hi(UsernamePasswordCredential credentials, byte[] salt, int iterations);
+        
+        /// <summary>
+        /// An HMAC function as defined in RFC5802, plus the encoding of the data.
+        /// </summary>
+        /// <param name="encoding">The encoding of the data.</param>
+        /// <param name="data">The data. Also called "str" in RFC5802.</param>
+        /// <param name="key">The key.</param>
+        protected internal delegate byte[] Hmac(UTF8Encoding encoding, byte[] data, string key);
+        
+        // fields
+        private readonly string _databaseName;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScramShaAuthenticator"/> class.
+        /// </summary>
+        /// <param name="credential">The credential.</param>
+        /// <param name="hashAlgorithmName">The hash algorithm name.</param>
+        /// <param name="h">The H function to use.</param>
+        /// <param name="hi">The Hi function to use.</param>
+        /// <param name="hmac">The Hmac function to use.</param>
+        protected ScramShaAuthenticator(UsernamePasswordCredential credential, 
+            HashAlgorithmName hashAlgorithmName,
+            H h,
+            Hi hi,
+            Hmac hmac)
+            : this(credential, hashAlgorithmName, new DefaultRandomStringGenerator(), h, hi, hmac) { }
+        
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ScramShaAuthenticator"/> class.
+        /// </summary>
+        /// <param name="credential">The credential.</param>
+        /// <param name="hashAlgorithName">The hash algorithm name.</param>
+        /// <param name="randomStringGenerator">The random string generator.</param>
+        /// <param name="h">The H function to use.</param>
+        /// <param name="hi">The Hi function to use.</param>
+        /// <param name="hmac">The Hmac function to use.</param>
+        internal ScramShaAuthenticator(
+            UsernamePasswordCredential credential, 
+            HashAlgorithmName hashAlgorithName,
+            IRandomStringGenerator randomStringGenerator,
+            H h,
+            Hi hi,
+            Hmac hmac)
+            : base(new ScramShaMechanism(credential, hashAlgorithName, randomStringGenerator, h, hi, hmac))
+        {
+            _databaseName = credential.Source;
+        }
+
+        // properties
+        /// <inheritdoc/>
+        public override string DatabaseName => _databaseName;
+
+        // nested classes
+        private class ScramShaMechanism : ISaslMechanism
+        {
+            private readonly UsernamePasswordCredential _credential;
+            private readonly IRandomStringGenerator _randomStringGenerator;
+            private readonly H _h;
+            private readonly Hi _hi;
+            private readonly Hmac _hmac;
+            private readonly string _name;
+
+            public ScramShaMechanism(
+                UsernamePasswordCredential credential, 
+                HashAlgorithmName hashAlgorithmName, 
+                IRandomStringGenerator randomStringGenerator,
+                H h,
+                Hi hi,
+                Hmac hmac)
+            {
+                _credential = Ensure.IsNotNull(credential, nameof(credential));
+                _h = h;
+                _hi = hi;
+                _hmac = hmac;
+                if (!hashAlgorithmName.ToString().StartsWith("SHA"))
+                {
+                    throw new ArgumentException("Must specify a SHA algorithm.");
+                }
+                _name = $"SCRAM-SHA-{hashAlgorithmName.ToString().Substring(3)}";
+                _randomStringGenerator = Ensure.IsNotNull(randomStringGenerator, nameof(randomStringGenerator));
+            }
+
+            public string Name => _name;
+
+            public ISaslStep Initialize(IConnection connection, SaslConversation conversation, ConnectionDescription description)
+            {
+                Ensure.IsNotNull(connection, nameof(connection));
+                Ensure.IsNotNull(description, nameof(description));
+
+                const string gs2Header = "n,,";
+                var username = "n=" + PrepUsername(_credential.Username);
+                var r = GenerateRandomString();
+                var nonce = "r=" + r;
+
+                var clientFirstMessageBare = username + "," + nonce;
+                var clientFirstMessage = gs2Header + clientFirstMessageBare;
+                var clientFirstMessageBytes = Utf8Encodings.Strict.GetBytes(clientFirstMessage); 
+
+                return new ClientFirst(clientFirstMessageBytes, clientFirstMessageBare, _credential, r, _h, _hi, _hmac);
+            }
+
+            private string GenerateRandomString()
+            {
+                const string legalCharacters = "!\"#$%&'()*+-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
+
+                return _randomStringGenerator.Generate(20, legalCharacters);
+            }
+
+            private string PrepUsername(string username)
+            {
+                return username.Replace("=", "=3D").Replace(",", "=2C");
+            }
+        }
+        
+        private class ClientFirst : ISaslStep
+        {
+            
+            private readonly byte[] _bytesToSendToServer;
+            private readonly string _clientFirstMessageBare;
+            private readonly UsernamePasswordCredential _credential;
+           
+            private readonly string _rPrefix;
+            private readonly H _h;
+            private readonly Hi _hi;
+            private readonly Hmac _hmac;
+
+            public ClientFirst(
+                byte[] bytesToSendToServer, 
+                string clientFirstMessageBare, 
+                UsernamePasswordCredential credential, 
+                string rPrefix,
+                H h,
+                Hi hi,
+                Hmac hmac)
+            {
+                _bytesToSendToServer = bytesToSendToServer;
+                _clientFirstMessageBare = clientFirstMessageBare;
+                _credential = credential;
+                _h = h;
+                _hi = hi;
+                _hmac = hmac;
+                _rPrefix = rPrefix;
+            }
+
+            public byte[] BytesToSendToServer => _bytesToSendToServer;
+
+            public bool IsComplete => false;
+
+            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
+            {
+                var encoding = Utf8Encodings.Strict;
+                var serverFirstMessage = encoding.GetString(bytesReceivedFromServer);
+                var map = SaslMapParser.Parse(serverFirstMessage);
+
+                var r = map['r'];
+                if (!r.StartsWith(_rPrefix))
+                {
+                    throw new MongoAuthenticationException(conversation.ConnectionId, message: "Server sent an invalid nonce.");
+                }
+                var s = map['s'];
+                var i = map['i'];
+
+                const string gs2Header = "n,,";
+                var channelBinding = "c=" + Convert.ToBase64String(encoding.GetBytes(gs2Header));
+                var nonce = "r=" + r;
+                var clientFinalMessageWithoutProof = channelBinding + "," + nonce;
+
+                var saltedPassword = _hi(
+                    _credential,
+                    Convert.FromBase64String(s),
+                    int.Parse(i));
+
+                var clientKey = _hmac(encoding, saltedPassword, "Client Key");
+                var storedKey = _h(clientKey);
+                var authMessage = _clientFirstMessageBare + "," + serverFirstMessage + "," + clientFinalMessageWithoutProof;
+                var clientSignature = _hmac(encoding, storedKey, authMessage);
+                var clientProof = XOR(clientKey, clientSignature);
+                var serverKey = _hmac(encoding, saltedPassword, "Server Key");
+                var serverSignature = _hmac(encoding, serverKey, authMessage);
+
+                var proof = "p=" + Convert.ToBase64String(clientProof);
+                var clientFinalMessage = clientFinalMessageWithoutProof + "," + proof;
+
+                return new ClientLast(encoding.GetBytes(clientFinalMessage), serverSignature);
+            }
+
+            private byte[] XOR(byte[] a, byte[] b)
+            {
+                var result = new byte[a.Length];
+                for (int i = 0; i < a.Length; i++)
+                {
+                    result[i] = (byte)(a[i] ^ b[i]);
+                }
+
+                return result;
+            }
+
+        }
+
+        private class ClientLast : ISaslStep
+        {            
+            private readonly byte[] _bytesToSendToServer;
+            private readonly byte[] _serverSignature64;
+
+            public ClientLast(byte[] bytesToSendToServer, byte[] serverSignature64)
+            {
+                _bytesToSendToServer = bytesToSendToServer;
+                _serverSignature64 = serverSignature64;
+            }
+
+            public byte[] BytesToSendToServer => _bytesToSendToServer;
+
+            public bool IsComplete => false;
+
+            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
+            {
+                var encoding = Utf8Encodings.Strict;
+                var map = SaslMapParser.Parse(encoding.GetString(bytesReceivedFromServer));
+                var serverSignature = Convert.FromBase64String(map['v']);
+
+                if (!ConstantTimeEquals(_serverSignature64, serverSignature))
+                {
+                    throw new MongoAuthenticationException(conversation.ConnectionId, message: "Server signature was invalid.");
+                }
+
+                return new CompletedStep();
+            }
+            
+            private bool ConstantTimeEquals(byte[] a, byte[] b)
+            {
+                var diff = a.Length ^ b.Length;
+                for (var i = 0; i < a.Length && i < b.Length; i++)
+                {
+                    diff |= a[i] ^ b[i];
+                }
+
+                return diff == 0;
+            }
+        }
+    }
+}

+ 175 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/Vendored/CryptographyHelpers.cs

@@ -0,0 +1,175 @@
+/* Original work:
+ *   Copyright 2016 .NET Foundation and Contributors
+ * 
+ *   The MIT License (MIT)
+ *   
+ *   Copyright (c) .NET Foundation and Contributors
+ *   
+ *   All rights reserved.
+ *   
+ *   Permission is hereby granted, free of charge, to any person obtaining a copy
+ *   of this software and associated documentation files (the "Software"), to deal
+ *   in the Software without restriction, including without limitation the rights
+ *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *   copies of the Software, and to permit persons to whom the Software is
+ *   furnished to do so, subject to the following conditions:
+ *   
+ *   The above copyright notice and this permission notice shall be included in all
+ *   copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *   SOFTWARE.
+ * 
+ * Modified work: 
+ *   Copyright 2018–present MongoDB Inc.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *   
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *   
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+
+using System.Diagnostics;
+using System.Security.Cryptography;
+
+namespace MongoDB.Driver.Core.Authentication.Vendored
+{
+    internal static class CryptographyHelpers
+    {
+        
+        private static readonly string Cryptography_MissingIV
+            = "The cipher mode specified requires that an initialization vector (IV) be used.";
+
+        public static byte[] CloneByteArray(this byte[] src)
+        {
+            if (src == null)
+            {
+                return null;
+            }
+
+            return (byte[])(src.Clone());
+        }
+
+        public static KeySizes[] CloneKeySizesArray(this KeySizes[] src)
+        {
+            return (KeySizes[])(src.Clone());
+        }
+
+        public static bool UsesIv(this CipherMode cipherMode)
+        {
+            return cipherMode != CipherMode.ECB;
+        }
+
+        public static byte[] GetCipherIv(this CipherMode cipherMode, byte[] iv)
+        {
+            if (cipherMode.UsesIv())
+            {
+                if (iv == null)
+                {
+                    throw new CryptographicException(Cryptography_MissingIV);
+                }
+
+                return iv;
+            }
+
+            return null;
+        }
+
+        public static bool IsLegalSize(this int size, KeySizes[] legalSizes)
+        {
+            for (int i = 0; i < legalSizes.Length; i++)
+            {
+                KeySizes currentSizes = legalSizes[i];
+
+                // If a cipher has only one valid key size, MinSize == MaxSize and SkipSize will be 0
+                if (currentSizes.SkipSize == 0)
+                {
+                    if (currentSizes.MinSize == size)
+                        return true;
+                }
+                else if (size >= currentSizes.MinSize && size <= currentSizes.MaxSize)
+                {
+                    // If the number is in range, check to see if it's a legal increment above MinSize
+                    int delta = size - currentSizes.MinSize;
+
+                    // While it would be unusual to see KeySizes { 10, 20, 5 } and { 11, 14, 1 }, it could happen.
+                    // So don't return false just because this one doesn't match.
+                    if (delta % currentSizes.SkipSize == 0)
+                    {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public static byte[] GenerateRandom(int count)
+        {
+            byte[] buffer = new byte[count];
+            using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
+            {
+                rng.GetBytes(buffer);
+            }
+            return buffer;
+        }
+
+        // encodes the integer i into a 4-byte array, in big endian.
+        public static void WriteInt(uint i, byte[] arr, int offset)
+        {
+            unchecked
+            {
+                Debug.Assert(arr != null);
+                Debug.Assert(arr.Length >= offset + sizeof(uint));
+
+                arr[offset] = (byte)(i >> 24);
+                arr[offset + 1] = (byte)(i >> 16);
+                arr[offset + 2] = (byte)(i >> 8);
+                arr[offset + 3] = (byte)i;
+            }
+        }
+
+        public static byte[] FixupKeyParity(this byte[] key)
+        {
+            byte[] oddParityKey = new byte[key.Length];
+            for (int index = 0; index < key.Length; index++)
+            {
+                // Get the bits we are interested in
+                oddParityKey[index] = (byte)(key[index] & 0xfe);
+
+                // Get the parity of the sum of the previous bits
+                byte tmp1 = (byte)((oddParityKey[index] & 0xF) ^ (oddParityKey[index] >> 4));
+                byte tmp2 = (byte)((tmp1 & 0x3) ^ (tmp1 >> 2));
+                byte sumBitsMod2 = (byte)((tmp2 & 0x1) ^ (tmp2 >> 1));
+
+                // We need to set the last bit in oddParityKey[index] to the negation
+                // of the last bit in sumBitsMod2
+                if (sumBitsMod2 == 0)
+                    oddParityKey[index] |= 1;
+            }
+            return oddParityKey;
+        }
+
+        internal static void ConvertIntToByteArray(uint value, byte[] dest)
+        {
+            Debug.Assert(dest != null);
+            Debug.Assert(dest.Length == 4);
+            dest[0] = (byte)((value & 0xFF000000) >> 24);
+            dest[1] = (byte)((value & 0xFF0000) >> 16);
+            dest[2] = (byte)((value & 0xFF00) >> 8);
+            dest[3] = (byte)(value & 0xFF);
+        }
+    }
+}

+ 172 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/Vendored/HashAlgorithmName.cs

@@ -0,0 +1,172 @@
+/* Original work:
+ *   Copyright 2016 .NET Foundation and Contributors
+ * 
+ *   The MIT License (MIT)
+ *   
+ *   Copyright (c) .NET Foundation and Contributors
+ *   
+ *   All rights reserved.
+ *   
+ *   Permission is hereby granted, free of charge, to any person obtaining a copy
+ *   of this software and associated documentation files (the "Software"), to deal
+ *   in the Software without restriction, including without limitation the rights
+ *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *   copies of the Software, and to permit persons to whom the Software is
+ *   furnished to do so, subject to the following conditions:
+ *   
+ *   The above copyright notice and this permission notice shall be included in all
+ *   copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *   SOFTWARE.
+ * 
+ * Modified work: 
+ *   Copyright 2018–present MongoDB Inc.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *   
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *   
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+using System;
+
+namespace MongoDB.Driver.Core.Authentication.Vendored
+{
+    // .NET Standard 1.5 includes this class, as does .NET Framework >= 4.6
+#if NET452
+   // Strongly typed string representing the name of a hash algorithm.
+    // Open ended to allow extensibility while giving the discoverable feel of an enum for common values.
+
+    /// <summary>
+    /// Specifies the name of a cryptographic hash algorithm.
+    /// </summary>
+    /// <remarks>
+    /// Asymmetric Algorithms implemented using Microsoft's CNG (Cryptography Next Generation) API
+    /// will interpret the underlying string value as a CNG algorithm identifier: 
+    ///   * https://msdn.microsoft.com/en-us/library/windows/desktop/aa375534(v=vs.85).aspx
+    ///
+    /// As with CNG, the names are case-sensitive. 
+    /// 
+    /// Asymmetric Algorithms implemented using other technologies:
+    ///    * Must recognize at least "MD5", "SHA1", "SHA256", "SHA384", and "SHA512".
+    ///    * Should recognize additional CNG IDs for any other hash algorithms that they also support.
+    /// </remarks>
+    public struct HashAlgorithmName : IEquatable<HashAlgorithmName>
+    {
+        // Returning a new instance every time is free here since HashAlgorithmName is a struct with
+        // a single string field. The optimized codegen should be equivalent to return "MD5".
+
+        /// <summary>
+        /// Gets a <see cref="HashAlgorithmName" /> representing "MD5"
+        /// </summary>
+        public static HashAlgorithmName MD5 { get { return new HashAlgorithmName("MD5"); } }
+
+        /// <summary>
+        /// Gets a <see cref="HashAlgorithmName" /> representing "SHA1"
+        /// </summary>
+        public static HashAlgorithmName SHA1 { get { return new HashAlgorithmName("SHA1"); } }
+
+        /// <summary>
+        /// Gets a <see cref="HashAlgorithmName" /> representing "SHA256"
+        /// </summary>
+        public static HashAlgorithmName SHA256 { get { return new HashAlgorithmName("SHA256"); } }
+
+        /// <summary>
+        /// Gets a <see cref="HashAlgorithmName" /> representing "SHA384"
+        /// </summary>
+        public static HashAlgorithmName SHA384 { get { return new HashAlgorithmName("SHA384"); } }
+
+        /// <summary>
+        /// Gets a <see cref="HashAlgorithmName" /> representing "SHA512"
+        /// </summary>
+        public static HashAlgorithmName SHA512 { get { return new HashAlgorithmName("SHA512"); } }
+
+        private readonly string _name;
+
+        /// <summary>
+        /// Gets a <see cref="HashAlgorithmName" /> representing a custom name.
+        /// </summary>
+        /// <param name="name">The custom hash algorithm name.</param>
+        public HashAlgorithmName(string name)
+        {
+            // Note: No validation because we have to deal with default(HashAlgorithmName) regardless.
+            _name = name;
+        }
+
+        /// <summary>
+        /// Gets the underlying string representation of the algorithm name. 
+        /// </summary>
+        /// <remarks>
+        /// May be null or empty to indicate that no hash algorithm is applicable.
+        /// </remarks>
+        public string Name
+        {
+            get { return _name; }
+        }
+
+        /// <inheritdoc/>
+        public override string ToString()
+        {
+            return _name ?? String.Empty;
+        }
+        
+        /// <inheritdoc/>
+        public override bool Equals(object obj)
+        {
+            return obj is HashAlgorithmName && Equals((HashAlgorithmName)obj);
+        }
+
+        /// <inheritdoc/>
+        public bool Equals(HashAlgorithmName other)
+        {
+            // NOTE: intentionally ordinal and case sensitive, matches CNG.
+            return _name == other._name;
+        }
+        
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return _name == null ? 0 : _name.GetHashCode();
+        }
+
+        /// <summary>
+        /// Implements the operator ==.
+        /// </summary>
+        /// <param name="left">The left operand.</param>
+        /// <param name="right">The right operand.</param>
+        /// <returns>
+        /// The result of the == operator.
+        /// </returns>
+        public static bool operator ==(HashAlgorithmName left, HashAlgorithmName right)
+        {
+            return left.Equals(right);
+        }
+
+        /// <summary>
+        /// Implements the operator !=.
+        /// </summary>
+        /// <param name="left">The left operand.</param>
+        /// <param name="right">The right operand.</param>
+        /// <returns>
+        /// The result of the != operator.
+        /// </returns>
+        public static bool operator !=(HashAlgorithmName left, HashAlgorithmName right)
+        {
+            return !(left == right);
+        }
+    }
+#endif    
+}

+ 337 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Authentication/Vendored/Rfc2898DeriveBytes.cs

@@ -0,0 +1,337 @@
+/* Original work:
+ *   Copyright 2016 .NET Foundation and Contributors
+ * 
+ *   The MIT License (MIT)
+ *   
+ *   Copyright (c) .NET Foundation and Contributors
+ *   
+ *   All rights reserved.
+ *   
+ *   Permission is hereby granted, free of charge, to any person obtaining a copy
+ *   of this software and associated documentation files (the "Software"), to deal
+ *   in the Software without restriction, including without limitation the rights
+ *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *   copies of the Software, and to permit persons to whom the Software is
+ *   furnished to do so, subject to the following conditions:
+ *   
+ *   The above copyright notice and this permission notice shall be included in all
+ *   copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *   SOFTWARE.
+ * 
+ * Modified work: 
+ *   Copyright 2018–present MongoDB Inc.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *   
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *   
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+using System;
+using System.Diagnostics;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace MongoDB.Driver.Core.Authentication.Vendored
+{
+    
+    internal class Rfc2898DeriveBytes : DeriveBytes
+    {
+        private static readonly string Cryptography_PasswordDerivedBytes_FewBytesSalt 
+            = "Salt is not at least eight bytes.";
+        private static readonly string ArgumentOutOfRange_NeedPosNum
+            = "Positive number required.";
+
+        private static readonly string Cryptography_HashAlgorithmNameNullOrEmpty
+            = "The hash algorithm name cannot be null or empty.";
+
+        private static readonly string ArgumentOutOfRange_NeedNonNegNum
+            = "Non-negative number required.";
+
+        private static readonly string Cryptography_UnknownHashAlgorithm
+            = "'{0}' is not a known hash algorithm.";
+
+        private const int MinimumSaltSize = 8;
+
+        private readonly byte[] _password;
+        private byte[] _salt;
+        private uint _iterations;
+        private HMAC _hmac;
+        private int _blockSize;
+
+        private byte[] _buffer;
+        private uint _block;
+        private int _startIndex;
+        private int _endIndex;
+
+        public HashAlgorithmName HashAlgorithm { get; }
+
+        public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations)
+            : this(password, salt, iterations, HashAlgorithmName.SHA1)
+        {
+        }
+
+        public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations, HashAlgorithmName hashAlgorithm)
+        {
+            if (salt == null)
+                throw new ArgumentNullException(nameof(salt));
+            if (salt.Length < MinimumSaltSize)
+                throw new ArgumentException(Cryptography_PasswordDerivedBytes_FewBytesSalt, nameof(salt));
+            if (iterations <= 0)
+                throw new ArgumentOutOfRangeException(nameof(iterations), ArgumentOutOfRange_NeedPosNum);
+            if (password == null)
+                throw new NullReferenceException();  // This "should" be ArgumentNullException but for compat, we throw NullReferenceException.
+
+            _salt = salt.CloneByteArray();
+            _iterations = (uint)iterations;
+            _password = password.CloneByteArray();
+            HashAlgorithm = hashAlgorithm;
+            _hmac = OpenHmac();
+            // _blockSize is in bytes, HashSize is in bits.
+            _blockSize = _hmac.HashSize >> 3;
+
+            Initialize();
+        }
+
+        public Rfc2898DeriveBytes(string password, byte[] salt)
+             : this(password, salt, 1000)
+        {
+        }
+
+        public Rfc2898DeriveBytes(string password, byte[] salt, int iterations)
+            : this(password, salt, iterations, HashAlgorithmName.SHA1)
+        {
+        }
+
+        public Rfc2898DeriveBytes(string password, byte[] salt, int iterations, HashAlgorithmName hashAlgorithm)
+            : this(Encoding.UTF8.GetBytes(password), salt, iterations, hashAlgorithm)
+        {
+        }
+
+        public Rfc2898DeriveBytes(string password, int saltSize)
+            : this(password, saltSize, 1000)
+        {
+        }
+
+        public Rfc2898DeriveBytes(string password, int saltSize, int iterations)
+            : this(password, saltSize, iterations, HashAlgorithmName.SHA1)
+        {
+        }
+
+        public Rfc2898DeriveBytes(string password, int saltSize, int iterations, HashAlgorithmName hashAlgorithm)
+        {
+            if (saltSize < 0)
+                throw new ArgumentOutOfRangeException(nameof(saltSize), ArgumentOutOfRange_NeedNonNegNum);
+            if (saltSize < MinimumSaltSize)
+                throw new ArgumentException(Cryptography_PasswordDerivedBytes_FewBytesSalt, nameof(saltSize));
+            if (iterations <= 0)
+                throw new ArgumentOutOfRangeException(nameof(iterations), ArgumentOutOfRange_NeedPosNum);
+
+            _salt = CryptographyHelpers.GenerateRandom(saltSize);
+            _iterations = (uint)iterations;
+            _password = Encoding.UTF8.GetBytes(password);
+            HashAlgorithm = hashAlgorithm;
+            _hmac = OpenHmac();
+            // _blockSize is in bytes, HashSize is in bits.
+            _blockSize = _hmac.HashSize >> 3;
+
+            Initialize();
+        }
+
+        public int IterationCount
+        {
+            get
+            {
+                return (int)_iterations;
+            }
+
+            set
+            {
+                if (value <= 0)
+                    throw new ArgumentOutOfRangeException(nameof(value), ArgumentOutOfRange_NeedPosNum);
+                _iterations = (uint)value;
+                Initialize();
+            }
+        }
+
+        public byte[] Salt
+        {
+            get
+            {
+                return _salt.CloneByteArray();
+            }
+
+            set
+            {
+                if (value == null)
+                    throw new ArgumentNullException(nameof(value));
+                if (value.Length < MinimumSaltSize)
+                    throw new ArgumentException(Cryptography_PasswordDerivedBytes_FewBytesSalt);
+                _salt = value.CloneByteArray();
+                Initialize();
+            }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                if (_hmac != null)
+                {
+                    _hmac.Dispose();
+                    _hmac = null;
+                }
+
+                if (_buffer != null)
+                    Array.Clear(_buffer, 0, _buffer.Length);
+                if (_password != null)
+                    Array.Clear(_password, 0, _password.Length);
+                if (_salt != null)
+                    Array.Clear(_salt, 0, _salt.Length);
+            }
+            base.Dispose(disposing);
+        }
+
+        public override byte[] GetBytes(int cb)
+        {
+            Debug.Assert(_blockSize > 0);
+
+            if (cb <= 0)
+                throw new ArgumentOutOfRangeException(nameof(cb), ArgumentOutOfRange_NeedPosNum);
+            byte[] password = new byte[cb];
+
+            int offset = 0;
+            int size = _endIndex - _startIndex;
+            if (size > 0)
+            {
+                if (cb >= size)
+                {
+                    Buffer.BlockCopy(_buffer, _startIndex, password, 0, size);
+                    _startIndex = _endIndex = 0;
+                    offset += size;
+                }
+                else
+                {
+                    Buffer.BlockCopy(_buffer, _startIndex, password, 0, cb);
+                    _startIndex += cb;
+                    return password;
+                }
+            }
+
+            Debug.Assert(_startIndex == 0 && _endIndex == 0, "Invalid start or end index in the internal buffer.");
+
+            while (offset < cb)
+            {
+                byte[] T_block = Func();
+                int remainder = cb - offset;
+                if (remainder > _blockSize)
+                {
+                    Buffer.BlockCopy(T_block, 0, password, offset, _blockSize);
+                    offset += _blockSize;
+                }
+                else
+                {
+                    Buffer.BlockCopy(T_block, 0, password, offset, remainder);
+                    offset += remainder;
+                    Buffer.BlockCopy(T_block, remainder, _buffer, _startIndex, _blockSize - remainder);
+                    _endIndex += (_blockSize - remainder);
+                    return password;
+                }
+            }
+            return password;
+        }
+
+        public byte[] CryptDeriveKey(string algname, string alghashname, int keySize, byte[] rgbIV)
+        {
+            // If this were to be implemented here, CAPI would need to be used (not CNG) because of
+            // unfortunate differences between the two. Using CNG would break compatibility. Since this
+            // assembly currently doesn't use CAPI it would require non-trivial additions.
+            // In addition, if implemented here, only Windows would be supported as it is intended as
+            // a thin wrapper over the corresponding native API.
+            // Note that this method is implemented in PasswordDeriveBytes (in the Csp assembly) using CAPI.
+            throw new PlatformNotSupportedException();
+        }
+
+        public override void Reset()
+        {
+            Initialize();
+        }
+        
+        private static string Format(string resourceFormat, params object[] args)
+        {
+            return args != null ? string.Format(resourceFormat, args) : resourceFormat;
+        }
+
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "HMACSHA1 is needed for compat. (https://github.com/dotnet/corefx/issues/9438)")]
+        private HMAC OpenHmac()
+        {
+            Debug.Assert(_password != null);
+
+            HashAlgorithmName hashAlgorithm = HashAlgorithm;
+
+            if (string.IsNullOrEmpty(hashAlgorithm.Name))
+                throw new CryptographicException(Cryptography_HashAlgorithmNameNullOrEmpty);
+
+            if (hashAlgorithm == HashAlgorithmName.SHA1)
+                return new HMACSHA1(_password);
+            if (hashAlgorithm == HashAlgorithmName.SHA256)
+                return new HMACSHA256(_password);
+            if (hashAlgorithm == HashAlgorithmName.SHA384)
+                return new HMACSHA384(_password);
+            if (hashAlgorithm == HashAlgorithmName.SHA512)
+                return new HMACSHA512(_password);
+
+            throw new CryptographicException(Format(Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
+        }
+
+        private void Initialize()
+        {
+            if (_buffer != null)
+                Array.Clear(_buffer, 0, _buffer.Length);
+            _buffer = new byte[_blockSize];
+            _block = 1;
+            _startIndex = _endIndex = 0;
+        }
+
+        // This function is defined as follows:
+        // Func (S, i) = HMAC(S || i) | HMAC2(S || i) | ... | HMAC(iterations) (S || i) 
+        // where i is the block number.
+        private byte[] Func()
+        {
+            byte[] temp = new byte[_salt.Length + sizeof(uint)];
+            Buffer.BlockCopy(_salt, 0, temp, 0, _salt.Length);
+            CryptographyHelpers.WriteInt(_block, temp, _salt.Length);
+
+            temp = _hmac.ComputeHash(temp);
+
+            byte[] ret = temp;
+            for (int i = 2; i <= _iterations; i++)
+            {
+                temp = _hmac.ComputeHash(temp);
+
+                for (int j = 0; j < _blockSize; j++)
+                {
+                    ret[j] ^= temp[j];
+                }
+            }
+
+            // increment the block count.
+            _block++;
+            return ret;
+        }
+    }
+}

+ 74 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreServerSession.cs

@@ -0,0 +1,74 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using MongoDB.Bson;
+
+namespace MongoDB.Driver
+{
+    /// <summary>
+    /// A server session.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.ICoreServerSession" />
+    internal sealed class CoreServerSession : ICoreServerSession
+    {
+        #region static
+        // private static methods
+        private static BsonDocument GenerateSessionId()
+        {
+            var guid = Guid.NewGuid();
+            var id = new BsonBinaryData(guid, GuidRepresentation.Standard);
+            return new BsonDocument("id", id);
+        }
+        #endregion
+
+        // private fields
+        private readonly BsonDocument _id;
+        private DateTime? _lastUsedAt;
+        private long _transactionNumber;
+
+        // constructors
+        public CoreServerSession()
+        {
+            _id = GenerateSessionId();
+            _transactionNumber = 0;
+        }
+
+        // public properties
+        /// <inheritdoc />
+        public BsonDocument Id => _id;
+
+        /// <inheritdoc />
+        public DateTime? LastUsedAt => _lastUsedAt;
+
+        // public methods
+        /// <inheritdoc />
+        public long AdvanceTransactionNumber()
+        {
+            return ++_transactionNumber;
+        }
+
+        /// <inheritdoc />
+        public void Dispose()
+        {
+        }
+
+        /// <inheritdoc />
+        public void WasUsed()
+        {
+            _lastUsedAt = DateTime.UtcNow;
+        }
+    }
+}

+ 137 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreServerSessionPool.cs

@@ -0,0 +1,137 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using MongoDB.Driver.Core.Clusters;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver
+{
+    internal class CoreServerSessionPool : ICoreServerSessionPool
+    {
+        // private fields
+        private readonly ICluster _cluster;
+        private readonly object _lock = new object();
+        private readonly List<ICoreServerSession> _pool = new List<ICoreServerSession>();
+
+        // constructors
+        public CoreServerSessionPool(ICluster cluster)
+        {
+            _cluster = Ensure.IsNotNull(cluster, nameof(cluster));
+        }
+
+        /// <inheritdoc />
+        public ICoreServerSession AcquireSession()
+        {
+            lock (_lock)
+            {
+                for (var i = _pool.Count - 1; i >= 0; i--)
+                {
+                    var pooledSession = _pool[i];
+                    if (IsAboutToExpire(pooledSession))
+                    {
+                        pooledSession.Dispose();
+                    }
+                    else
+                    {
+                        var removeCount = _pool.Count - i; // the one we're about to return and any about to expire ones we skipped over
+                        _pool.RemoveRange(i, removeCount);
+                        return new ReleaseOnDisposeCoreServerSession(pooledSession, this);
+                    }
+                }
+
+                _pool.Clear(); // they're all about to expire
+            }
+
+            return new ReleaseOnDisposeCoreServerSession(new CoreServerSession(), this);
+        }
+
+        /// <inheritdoc />
+        public void ReleaseSession(ICoreServerSession session)
+        {
+            lock (_lock)
+            {
+                var removeCount = 0;
+                for (var i = 0; i < _pool.Count; i++)
+                {
+                    var pooledSession = _pool[i];
+                    if (IsAboutToExpire(pooledSession))
+                    {
+                        pooledSession.Dispose();
+                        removeCount++;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+                _pool.RemoveRange(0, removeCount);
+
+                if (IsAboutToExpire(session))
+                {
+                    session.Dispose();
+                }
+                else
+                {
+                    _pool.Add(session);
+                }
+            }
+        }
+
+        // private methods
+        private bool IsAboutToExpire(ICoreServerSession session)
+        {
+            var logicalSessionTimeout = _cluster.Description.LogicalSessionTimeout;
+            if (!session.LastUsedAt.HasValue || !logicalSessionTimeout.HasValue)
+            {
+                return true;
+            }
+            else
+            {
+                var expiresAt = session.LastUsedAt.Value + logicalSessionTimeout.Value;
+                var timeRemaining = expiresAt - DateTime.UtcNow;
+                return timeRemaining < TimeSpan.FromMinutes(1);
+            }
+        }
+
+        // nested types
+        internal sealed class ReleaseOnDisposeCoreServerSession : WrappingCoreServerSession
+        {
+            // private fields
+            private readonly ICoreServerSessionPool _pool;
+
+            // constructors
+            public ReleaseOnDisposeCoreServerSession(ICoreServerSession wrapped, ICoreServerSessionPool pool)
+                : base(wrapped, ownsWrapped: false)
+            {
+                _pool = Ensure.IsNotNull(pool, nameof(pool));
+            }
+
+            // protected methods
+            protected override void Dispose(bool disposing)
+            {
+                if (!_disposed)
+                {
+                    if (disposing)
+                    {
+                        _pool.ReleaseSession(Wrapped);
+                    }
+                }
+                base.Dispose(disposing);
+            }
+        }
+    }
+}

+ 481 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreSession.cs

@@ -0,0 +1,481 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Clusters;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.Operations;
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    /// <summary>
+    /// Represents a session.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Bindings.ICoreSession" />
+    public sealed class CoreSession : ICoreSession
+    {
+        // private fields
+        private readonly ICluster _cluster;
+        private readonly IClusterClock _clusterClock = new ClusterClock();
+        private CoreTransaction _currentTransaction;
+        private bool _disposed;
+        private bool _isCommitTransactionInProgress;
+        private readonly IOperationClock _operationClock = new OperationClock();
+        private readonly CoreSessionOptions _options;
+        private readonly ICoreServerSession _serverSession;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CoreSession" /> class.
+        /// </summary>
+        /// <param name="cluster">The cluster.</param>
+        /// <param name="serverSession">The server session.</param>
+        /// <param name="options">The options.</param>
+        public CoreSession(
+            ICluster cluster,
+            ICoreServerSession serverSession,
+            CoreSessionOptions options)
+        {
+            _cluster = Ensure.IsNotNull(cluster, nameof(cluster));
+            _serverSession = Ensure.IsNotNull(serverSession, nameof(serverSession));
+            _options = Ensure.IsNotNull(options, nameof(options));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the cluster.
+        /// </summary>
+        /// <value>
+        /// The cluster.
+        /// </value>
+        public ICluster Cluster => _cluster;
+
+        /// <inheritdoc />
+        public BsonDocument ClusterTime => _clusterClock.ClusterTime;
+
+        /// <inheritdoc />
+        public CoreTransaction CurrentTransaction => _currentTransaction;
+
+        /// <inheritdoc />
+        public BsonDocument Id => _serverSession.Id;
+
+        /// <inheritdoc />
+        public bool IsCausallyConsistent => _options.IsCausallyConsistent;
+
+        /// <inheritdoc />
+        public bool IsImplicit => _options.IsImplicit;
+
+        /// <inheritdoc />
+        public bool IsInTransaction
+        {
+            get
+            {
+                if (_currentTransaction != null)
+                {
+                    switch (_currentTransaction.State)
+                    {
+                        case CoreTransactionState.Aborted:
+                            return false;
+
+                        case CoreTransactionState.Committed:
+                            return _isCommitTransactionInProgress; // when retrying a commit we are temporarily "back in" the already committed transaction
+
+                        default:
+                            return true;
+                    }
+                }
+
+                return false;
+            }
+        }
+
+        /// <inheritdoc />
+        public BsonTimestamp OperationTime => _operationClock.OperationTime;
+
+        /// <inheritdoc />
+        public CoreSessionOptions Options => _options;
+
+        /// <inheritdoc />
+        public ICoreServerSession ServerSession => _serverSession;
+
+        // public methods
+        /// <inheritdoc />
+        public void AbortTransaction(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            EnsureAbortTransactionCanBeCalled(nameof(AbortTransaction));
+
+            try
+            {
+                if (_currentTransaction.IsEmpty)
+                {
+                    return;
+                }
+
+                try
+                {
+                    var firstAttempt = CreateAbortTransactionOperation();
+                    ExecuteEndTransactionOnPrimary(firstAttempt, cancellationToken);
+                    return;
+                }
+                catch (Exception exception) when (ShouldRetryEndTransactionException(exception))
+                {
+                    // ignore exception and retry
+                }
+                catch
+                {
+                    return; // ignore exception and return
+                }
+
+                try
+                {
+                    var secondAttempt = CreateAbortTransactionOperation();
+                    ExecuteEndTransactionOnPrimary(secondAttempt, cancellationToken);
+                }
+                catch
+                {
+                    return; // ignore exception and return
+                }
+            }
+            finally
+            {
+                _currentTransaction.SetState(CoreTransactionState.Aborted);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task AbortTransactionAsync(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            EnsureAbortTransactionCanBeCalled(nameof(AbortTransaction));
+
+            try
+            {
+                if (_currentTransaction.IsEmpty)
+                {
+                    return;
+                }
+
+                try
+                {
+                    var firstAttempt = CreateAbortTransactionOperation();
+                    await ExecuteEndTransactionOnPrimaryAsync(firstAttempt, cancellationToken).ConfigureAwait(false);
+                    return;
+                }
+                catch (Exception exception) when (ShouldRetryEndTransactionException(exception))
+                {
+                    // ignore exception and retry
+                }
+                catch
+                {
+                    return; // ignore exception and return
+                }
+
+                try
+                {
+                    var secondAttempt = CreateAbortTransactionOperation();
+                    await ExecuteEndTransactionOnPrimaryAsync(secondAttempt, cancellationToken).ConfigureAwait(false);
+                }
+                catch
+                {
+                    return; // ignore exception and return
+                }
+            }
+            finally
+            {
+                _currentTransaction.SetState(CoreTransactionState.Aborted);
+            }
+        }
+
+        /// <inheritdoc />
+        public void AboutToSendCommand()
+        {
+            if (_currentTransaction != null)
+            {
+                switch (_currentTransaction.State)
+                {
+                    case CoreTransactionState.Starting: // Starting changes to InProgress after the message is sent to the server
+                    case CoreTransactionState.InProgress:
+                        return;
+
+                    case CoreTransactionState.Aborted:
+                        _currentTransaction = null;
+                        break;
+
+                    case CoreTransactionState.Committed:
+                        // don't set to null when retrying a commit
+                        if (!_isCommitTransactionInProgress)
+                        {
+                            _currentTransaction = null;
+                        }
+                        return;
+
+                    default:
+                        throw new Exception($"Unexpected transaction state: {_currentTransaction.State}.");
+                }
+            }
+        }
+
+        /// <inheritdoc />
+        public void AdvanceClusterTime(BsonDocument newClusterTime)
+        {
+            _clusterClock.AdvanceClusterTime(newClusterTime);
+        }
+
+        /// <inheritdoc />
+        public void AdvanceOperationTime(BsonTimestamp newOperationTime)
+        {
+            _operationClock.AdvanceOperationTime(newOperationTime);
+        }
+
+        /// <inheritdoc />
+        public long AdvanceTransactionNumber()
+        {
+            return _serverSession.AdvanceTransactionNumber();
+        }
+
+        /// <inheritdoc />
+        public void CommitTransaction(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            EnsureCommitTransactionCanBeCalled(nameof(CommitTransaction));
+
+            try
+            {
+                _isCommitTransactionInProgress = true;
+                if (_currentTransaction.IsEmpty)
+                {
+                    return;
+                }
+
+                try
+                {
+                    var firstAttempt = CreateCommitTransactionOperation();
+                    ExecuteEndTransactionOnPrimary(firstAttempt, cancellationToken);
+                    return;
+                }
+                catch (Exception exception) when (ShouldRetryEndTransactionException(exception))
+                {
+                    // ignore exception and retry
+                }
+
+                var secondAttempt = CreateCommitTransactionOperation();
+                ExecuteEndTransactionOnPrimary(secondAttempt, cancellationToken);
+            }
+            finally
+            {
+                _isCommitTransactionInProgress = false;
+                _currentTransaction.SetState(CoreTransactionState.Committed);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task CommitTransactionAsync(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            EnsureCommitTransactionCanBeCalled(nameof(CommitTransaction));
+
+            try
+            {
+                _isCommitTransactionInProgress = true;
+                if (_currentTransaction.IsEmpty)
+                {
+                    return;
+                }
+
+                try
+                {
+                    var firstAttempt = CreateCommitTransactionOperation();
+                    await ExecuteEndTransactionOnPrimaryAsync(firstAttempt, cancellationToken).ConfigureAwait(false);
+                    return;
+                }
+                catch (Exception exception) when (ShouldRetryEndTransactionException(exception))
+                {
+                    // ignore exception and retry
+                }
+
+                var secondAttempt = CreateCommitTransactionOperation();
+                await ExecuteEndTransactionOnPrimaryAsync(secondAttempt, cancellationToken).ConfigureAwait(false);
+            }
+            finally
+            {
+                _isCommitTransactionInProgress = false;
+                _currentTransaction.SetState(CoreTransactionState.Committed);
+            }
+        }
+
+        /// <inheritdoc />
+        public void Dispose()
+        {
+            if (!_disposed)
+            {
+                if (_currentTransaction != null)
+                {
+                    switch (_currentTransaction.State)
+                    {
+                        case CoreTransactionState.Starting:
+                        case CoreTransactionState.InProgress:
+                            try
+                            {
+                                AbortTransaction(CancellationToken.None);
+                            }
+                            catch
+                            {
+                                // ignore exceptions
+                            }
+                            break;
+                    }
+                }
+
+                _serverSession.Dispose();
+                _disposed = true;
+            }
+        }
+
+        /// <inheritdoc />
+        public void StartTransaction(TransactionOptions transactionOptions = null)
+        {
+            EnsureStartTransactionCanBeCalled();
+
+            var transactionNumber = AdvanceTransactionNumber();
+            var effectiveTransactionOptions = GetEffectiveTransactionOptions(transactionOptions);
+            if (!effectiveTransactionOptions.WriteConcern.IsAcknowledged)
+            {
+                throw new InvalidOperationException("Transactions do not support unacknowledged write concerns.");
+            }
+
+            _currentTransaction = new CoreTransaction(transactionNumber, effectiveTransactionOptions);
+        }
+
+        /// <inheritdoc />
+        public void WasUsed()
+        {
+            _serverSession.WasUsed();
+        }
+
+        // private methods
+        private IReadOperation<BsonDocument> CreateAbortTransactionOperation()
+        {
+            return new AbortTransactionOperation(GetTransactionWriteConcern());
+        }
+
+        private IReadOperation<BsonDocument> CreateCommitTransactionOperation()
+        {
+            return new CommitTransactionOperation(GetTransactionWriteConcern());
+        }
+
+        private void EnsureAbortTransactionCanBeCalled(string methodName)
+        {
+            if (_currentTransaction == null)
+            {
+                throw new InvalidOperationException($"{methodName} cannot be called when no transaction started.");
+            }
+
+            switch (_currentTransaction.State)
+            {
+                case CoreTransactionState.Starting:
+                case CoreTransactionState.InProgress:
+                    return;
+
+                case CoreTransactionState.Aborted:
+                    throw new InvalidOperationException($"Cannot call {methodName} twice.");
+
+                case CoreTransactionState.Committed:
+                    throw new InvalidOperationException($"Cannot call {methodName} after calling CommitTransaction.");
+
+                default:
+                    throw new Exception($"{methodName} called in unexpected transaction state: {_currentTransaction.State}.");
+            }
+        }
+
+        private void EnsureCommitTransactionCanBeCalled(string methodName)
+        {
+            if (_currentTransaction == null)
+            {
+                throw new InvalidOperationException($"{methodName} cannot be called when no transaction started.");
+            }
+
+            switch (_currentTransaction.State)
+            {
+                case CoreTransactionState.Starting:
+                case CoreTransactionState.InProgress:
+                case CoreTransactionState.Committed:
+                    return;
+
+                case CoreTransactionState.Aborted:
+                    throw new InvalidOperationException($"Cannot call {methodName} after calling AbortTransaction.");
+
+                default:
+                    throw new Exception($"{methodName} called in unexpected transaction state: {_currentTransaction.State}.");
+            }
+        }
+
+        private void EnsureStartTransactionCanBeCalled()
+        {
+            if (_currentTransaction == null)
+            {
+                return;
+            }
+
+            switch (_currentTransaction.State)
+            {
+                case CoreTransactionState.Aborted:
+                case CoreTransactionState.Committed:
+                    return;
+
+                default:
+                    throw new InvalidOperationException("Transaction already in progress.");
+            }
+        }
+
+        private TResult ExecuteEndTransactionOnPrimary<TResult>(IReadOperation<TResult> operation, CancellationToken cancellationToken)
+        {
+            using (var sessionHandle = new NonDisposingCoreSessionHandle(this))
+            using (var binding = new WritableServerBinding(_cluster, sessionHandle))
+            {
+                return operation.Execute(binding, cancellationToken);
+            }
+        }
+
+        private async Task<TResult> ExecuteEndTransactionOnPrimaryAsync<TResult>(IReadOperation<TResult> operation, CancellationToken cancellationToken)
+        {
+            using (var sessionHandle = new NonDisposingCoreSessionHandle(this))
+            using (var binding = new WritableServerBinding(_cluster, sessionHandle))
+            {
+                return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        private TransactionOptions GetEffectiveTransactionOptions(TransactionOptions transactionOptions)
+        {
+            var readConcern = transactionOptions?.ReadConcern ?? _options.DefaultTransactionOptions?.ReadConcern ?? ReadConcern.Default;
+            var readPreference = transactionOptions?.ReadPreference ?? _options.DefaultTransactionOptions?.ReadPreference ?? ReadPreference.Primary;
+            var writeConcern = transactionOptions?.WriteConcern ?? _options.DefaultTransactionOptions?.WriteConcern ?? new WriteConcern();
+            return new TransactionOptions(readConcern, readPreference, writeConcern);
+        }
+
+        private WriteConcern GetTransactionWriteConcern()
+        {
+            return
+                _currentTransaction.TransactionOptions?.WriteConcern ??
+                _options.DefaultTransactionOptions?.WriteConcern ??
+                WriteConcern.WMajority;
+        }
+
+        private bool ShouldRetryEndTransactionException(Exception exception)
+        {
+            return RetryabilityHelper.IsRetryableWriteException(exception);
+        }
+    }
+}

+ 72 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreSessionHandle.cs

@@ -0,0 +1,72 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    /// <summary>
+    /// A handle to a reference counted core session.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Bindings.ICoreSessionHandle" />
+    public sealed class CoreSessionHandle : WrappingCoreSession, ICoreSessionHandle
+    {
+        // private fields
+        private readonly ReferenceCountedCoreSession _wrapped;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CoreSessionHandle"/> class.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        public CoreSessionHandle(ICoreSession session)
+            : this(new ReferenceCountedCoreSession(Ensure.IsNotNull(session, nameof(session))))
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CoreSessionHandle"/> class.
+        /// </summary>
+        /// <param name="wrapped">The wrapped.</param>
+        internal CoreSessionHandle(ReferenceCountedCoreSession wrapped)
+            : base(Ensure.IsNotNull(wrapped, nameof(wrapped)), ownsWrapped: false)
+        {
+            _wrapped = wrapped;
+        }
+
+        // public methods
+        /// <inheritdoc />
+        public ICoreSessionHandle Fork()
+        {
+            ThrowIfDisposed();
+            _wrapped.IncrementReferenceCount();
+            return new CoreSessionHandle(_wrapped);
+        }
+
+        // protected methods
+        /// <inheritdoc />
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                if (!IsDisposed())
+                {
+                    _wrapped.DecrementReferenceCount();
+                }
+            }
+            base.Dispose(disposing);
+        }
+    }
+}

+ 70 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreSessionOptions.cs

@@ -0,0 +1,70 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    /// <summary>
+    /// Core session options.
+    /// </summary>
+    public class CoreSessionOptions
+    {
+        // private fields
+        private readonly TransactionOptions _defaultTransactionOptions;
+        private readonly bool _isCausallyConsistent;
+        private readonly bool _isImplicit;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CoreSessionOptions" /> class.
+        /// </summary>
+        /// <param name="isCausallyConsistent">if set to <c>true</c> this session is causally consistent]</param>
+        /// <param name="isImplicit">if set to <c>true</c> this session is an implicit session.</param>
+        /// <param name="defaultTransactionOptions">The default transaction options.</param>
+        public CoreSessionOptions(
+            bool isCausallyConsistent = false,
+            bool isImplicit = false,
+            TransactionOptions defaultTransactionOptions = null)
+        {
+            _isCausallyConsistent = isCausallyConsistent;
+            _isImplicit = isImplicit;
+            _defaultTransactionOptions = defaultTransactionOptions;
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the default transaction options.
+        /// </summary>
+        /// <value>
+        /// The default transaction options.
+        /// </value>
+        public TransactionOptions DefaultTransactionOptions => _defaultTransactionOptions;
+
+        /// <summary>
+        /// Gets a value indicating whether this session is causally consistent.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if this session is causally consistent; otherwise, <c>false</c>.
+        /// </value>
+        public bool IsCausallyConsistent => _isCausallyConsistent;
+
+        /// <summary>
+        /// Gets a value indicating whether this session is an implicit session.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if this session is an implicit session; otherwise, <c>false</c>.
+        /// </value>
+        public bool IsImplicit => _isImplicit;
+    }
+}

+ 86 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreTransaction.cs

@@ -0,0 +1,86 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    /// <summary>
+    /// The state of a transaction.
+    /// </summary>
+    public class CoreTransaction
+    {
+        // private fields
+        private bool _isEmpty;
+        private CoreTransactionState _state;
+        private readonly long _transactionNumber;
+        private readonly TransactionOptions _transactionOptions;
+
+        // public constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CoreTransaction" /> class.
+        /// </summary>
+        /// <param name="transactionNumber">The transaction number.</param>
+        /// <param name="transactionOptions">The transaction options.</param>
+        public CoreTransaction(long transactionNumber, TransactionOptions transactionOptions)
+        {
+            _transactionNumber = transactionNumber;
+            _transactionOptions = transactionOptions;
+            _state = CoreTransactionState.Starting;
+            _isEmpty = true;
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets a value indicating whether the transaction is empty.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if the transaction is empty; otherwise, <c>false</c>.
+        /// </value>
+        public bool IsEmpty => _isEmpty;
+
+        /// <summary>
+        /// Gets the transaction state.
+        /// </summary>
+        /// <value>
+        /// The transaction state.
+        /// </value>
+        public CoreTransactionState State => _state;
+
+        /// <summary>
+        /// Gets the transaction number.
+        /// </summary>
+        /// <value>
+        /// The transaction number.
+        /// </value>
+        public long TransactionNumber => _transactionNumber;
+
+        /// <summary>
+        /// Gets the transaction options.
+        /// </summary>
+        /// <value>
+        /// The transaction options.
+        /// </value>
+        public TransactionOptions TransactionOptions => _transactionOptions;
+
+        // internal methods
+        internal void SetState(CoreTransactionState state)
+        {
+            _state = state;
+            if (state == CoreTransactionState.InProgress)
+            {
+                _isEmpty = false;
+            }
+        }
+    }
+}

+ 43 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/CoreTransactionState.cs

@@ -0,0 +1,43 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    /// <summary>
+    /// Represents the current state of a Core transaction.
+    /// </summary>
+    public enum CoreTransactionState
+    {
+        /// <summary>
+        /// StartTransaction has been called but no operations have been performed yet.
+        /// </summary>
+        Starting = 1,
+
+        /// <summary>
+        /// The transaction is in progress.
+        /// </summary>
+        InProgress,
+
+        /// <summary>
+        /// CommitTransaction has been called.
+        /// </summary>
+        Committed,
+
+        /// <summary>
+        /// AbortTransaction has been called.
+        /// </summary>
+        Aborted
+    }
+}

+ 36 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/ICoreServerSessionPool.cs

@@ -0,0 +1,36 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver
+{
+    /// <summary>
+    /// A server session pool.
+    /// </summary>
+    internal interface ICoreServerSessionPool
+    {
+        // methods
+        /// <summary>
+        /// Acquires a server session.
+        /// </summary>
+        /// <returns>A server session.</returns>
+        ICoreServerSession AcquireSession();
+
+        /// <summary>
+        /// Releases a server session.
+        /// </summary>
+        /// <param name="serverSession">The server session.</param>
+        void ReleaseSession(ICoreServerSession serverSession);
+    }
+}

+ 55 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/ICoreServerSesssion.cs

@@ -0,0 +1,55 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using MongoDB.Bson;
+
+namespace MongoDB.Driver
+{
+    /// <summary>
+    /// The interface for a core server session.
+    /// </summary>
+    public interface ICoreServerSession : IDisposable
+    {
+        // properties
+        /// <summary>
+        /// Gets the session Id.
+        /// </summary>
+        /// <value>
+        /// The session Id.
+        /// </value>
+        BsonDocument Id { get; }
+
+        /// <summary>
+        /// Gets the time this server session was last used (in UTC).
+        /// </summary>
+        /// <value>
+        /// The time this server session was last used (in UTC).
+        /// </value>
+        DateTime? LastUsedAt { get; }
+
+        /// <summary>
+        /// Gets the next transaction number.
+        /// </summary>
+        /// <returns>The transaction number.</returns>
+        long AdvanceTransactionNumber();
+
+        // methods
+        /// <summary>
+        /// Called by the driver when the session is used (i.e. sent to the server).
+        /// </summary>
+        void WasUsed();
+    }
+}

+ 176 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/ICoreSession.cs

@@ -0,0 +1,176 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Clusters;
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    /// <summary>
+    /// The interface for a session in Core.
+    /// </summary>
+    public interface ICoreSession : IDisposable
+    {
+        // properties
+        /// <summary>
+        /// Gets the cluster time.
+        /// </summary>
+        /// <value>
+        /// The cluster time.
+        /// </value>
+        BsonDocument ClusterTime { get; }
+
+        /// <summary>
+        /// Gets the current transaction.
+        /// </summary>
+        /// <value>
+        /// The current transaction.
+        /// </value>
+        CoreTransaction CurrentTransaction { get; }
+
+        /// <summary>
+        /// Gets the session Id.
+        /// </summary>
+        /// <value>
+        /// The session Id.
+        /// </value>
+        BsonDocument Id { get; }
+
+        /// <summary>
+        /// Gets a value indicate whether this instance is causally consistent.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if the session is causally consistent.
+        /// </value>
+        bool IsCausallyConsistent { get; }
+
+        /// <summary>
+        /// Gets a value indicating whether this instance is implicit session.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if this instance is implicit session; otherwise, <c>false</c>.
+        /// </value>
+        bool IsImplicit { get; }
+
+        /// <summary>
+        /// Gets a value indicating whether this instance is in a transaction.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if this instance is in a transaction; otherwise, <c>false</c>.
+        /// </value>
+        bool IsInTransaction { get; }
+
+        /// <summary>
+        /// Gets the operation time.
+        /// </summary>
+        /// <value>
+        /// The operation time.
+        /// </value>
+        BsonTimestamp OperationTime { get; }
+
+        /// <summary>
+        /// Gets the session options.
+        /// </summary>
+        /// <value>
+        /// The session options.
+        /// </value>
+        CoreSessionOptions Options { get; }
+
+        /// <summary>
+        /// Gets the server session.
+        /// </summary>
+        /// <value>
+        /// The server session.
+        /// </value>
+        ICoreServerSession ServerSession { get; }
+
+        // methods
+        /// <summary>
+        /// Aborts the transaction.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        void AbortTransaction(CancellationToken cancellationToken = default(CancellationToken));
+
+        /// <summary>
+        /// Aborts the transaction.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A Task.</returns>
+        Task AbortTransactionAsync(CancellationToken cancellationToken = default(CancellationToken));
+
+        /// <summary>
+        /// The driver is about to send a command on this session. Called to track session state.
+        /// </summary>
+        void AboutToSendCommand();
+
+        /// <summary>
+        /// Advances the cluster time.
+        /// </summary>
+        /// <param name="newClusterTime">The new cluster time.</param>
+        void AdvanceClusterTime(BsonDocument newClusterTime);
+
+        /// <summary>
+        /// Advances the operation time.
+        /// </summary>
+        /// <param name="newOperationTime">The new operation time.</param>
+        void AdvanceOperationTime(BsonTimestamp newOperationTime);
+
+        /// <summary>
+        /// Advances the transaction id.
+        /// </summary>
+        /// <returns>The transaction id.</returns>
+        long AdvanceTransactionNumber();
+
+        /// <summary>
+        /// Commits the transaction.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        void CommitTransaction(CancellationToken cancellationToken = default(CancellationToken));
+
+        /// <summary>
+        /// Commits the transaction.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A Task.</returns>
+        Task CommitTransactionAsync(CancellationToken cancellationToken = default(CancellationToken));
+
+        /// <summary>
+        /// Starts a transaction.
+        /// </summary>
+        /// <param name="transactionOptions">The transaction options.</param>
+        void StartTransaction(TransactionOptions transactionOptions = null);
+
+        /// <summary>
+        /// Called by the driver when the session is used (i.e. sent to the server).
+        /// </summary>
+        void WasUsed();
+    }
+
+    /// <summary>
+    /// A handle to a reference counted core session.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Bindings.ICoreSession" />
+    public interface ICoreSessionHandle : ICoreSession
+    {
+        /// <summary>
+        /// Increments the reference count of the underlying session and returns a new handle to it.
+        /// </summary>
+        /// <returns>A new handle.</returns>
+        ICoreSessionHandle Fork();
+    }
+}

+ 48 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/NoCoreServerSession.cs

@@ -0,0 +1,48 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using MongoDB.Bson;
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    internal class NoCoreServerSession : ICoreServerSession
+    {
+        #region static
+        // private static fields
+        private static readonly ICoreServerSession __instance = new NoCoreServerSession();
+
+        // public static properties
+        public static ICoreServerSession Instance => __instance;
+        #endregion
+
+        public BsonDocument Id => null;
+
+        public DateTime? LastUsedAt => null;
+
+        public long AdvanceTransactionNumber()
+        {
+            return -1;
+        }
+
+        public void Dispose()
+        {
+        }
+
+        public void WasUsed()
+        {
+        }
+    }
+}

+ 144 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/NoCoreSession.cs

@@ -0,0 +1,144 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Clusters;
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    /// <summary>
+    /// An object that represents no core session.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Bindings.ICoreSession" />
+    public sealed class NoCoreSession : ICoreSession
+    {
+        #region static
+        // private static fields
+        private static readonly ICoreSession __instance = new NoCoreSession();
+
+        // public static properties
+        /// <summary>
+        /// Gets the pre-created instance.
+        /// </summary>
+        /// <value>
+        /// The instance.
+        /// </value>
+        public static ICoreSession Instance => __instance;
+
+        // public static methods
+        /// <summary>
+        /// Returns a new handle to a NoCoreSession object.
+        /// </summary>
+        /// <returns>A new handle to the NoCoreSession object.</returns>
+        public static ICoreSessionHandle NewHandle()
+        {
+            return new CoreSessionHandle(__instance);
+        }
+        #endregion
+
+        // public properties
+        /// <inheritdoc />
+        public BsonDocument ClusterTime => null;
+
+        /// <inheritdoc />
+        public CoreTransaction CurrentTransaction => null;
+
+        /// <inheritdoc />
+        public BsonDocument Id => null;
+
+        /// <inheritdoc />
+        public bool IsCausallyConsistent => false;
+
+        /// <inheritdoc />
+        public bool IsImplicit => true;
+
+        /// <inheritdoc />
+        public bool IsInTransaction => false;
+
+        /// <inheritdoc />
+        public BsonTimestamp OperationTime => null;
+
+        /// <inheritdoc />
+        public CoreSessionOptions Options => null;
+
+        /// <inheritdoc />
+        public ICoreServerSession ServerSession => NoCoreServerSession.Instance;
+
+        // public methods
+        /// <inheritdoc />
+        public void AbortTransaction(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            throw new NotSupportedException("NoCoreSession does not support AbortTransaction.");
+        }
+
+        /// <inheritdoc />
+        public Task AbortTransactionAsync(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            throw new NotSupportedException("NoCoreSession does not support AbortTransactionAsync.");
+        }
+
+        /// <inheritdoc />
+        public void AboutToSendCommand()
+        {
+        }
+
+        /// <inheritdoc />
+        public void AdvanceClusterTime(BsonDocument newClusterTime)
+        {
+        }
+
+        /// <inheritdoc />
+        public void AdvanceOperationTime(BsonTimestamp newOperationTime)
+        {
+        }
+
+        /// <inheritdoc />
+        public long AdvanceTransactionNumber()
+        {
+            return -1;
+        }
+
+        /// <inheritdoc />
+        public void CommitTransaction(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            throw new NotSupportedException("NoCoreSession does not support CommitTransaction.");
+        }
+
+        /// <inheritdoc />
+        public Task CommitTransactionAsync(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            throw new NotSupportedException("NoCoreSession does not support CommitTransactionAsync.");
+        }
+
+        /// <inheritdoc />
+        public void Dispose()
+        {
+        }
+
+        /// <inheritdoc />
+        public void StartTransaction(TransactionOptions transactionOptions = null)
+        {
+            throw new NotSupportedException("NoCoreSession does not support StartTransaction.");
+        }
+
+        /// <inheritdoc />
+        public void WasUsed()
+        {
+        }
+    }
+}

+ 53 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/NonDisposingCoreSessionHandle.cs

@@ -0,0 +1,53 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    /// <summary>
+    /// A handle to a core session that should not be disposed when the handle is disposed.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Bindings.ICoreSessionHandle" />
+    internal sealed class NonDisposingCoreSessionHandle : WrappingCoreSession, ICoreSessionHandle
+    {
+        // private fields
+        private readonly ICoreSession _wrapped;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="NonDisposingCoreSessionHandle" /> class.
+        /// </summary>
+        /// <param name="wrapped">The wrapped session.</param>
+        public NonDisposingCoreSessionHandle(ICoreSession wrapped)
+            : base(wrapped, ownsWrapped: false)
+        {
+            _wrapped = wrapped;
+        }
+
+        // public methods
+        /// <inheritdoc />
+        public ICoreSessionHandle Fork()
+        {
+            ThrowIfDisposed();
+            return new NonDisposingCoreSessionHandle(_wrapped);
+        }
+
+        // protected methods
+        /// <inheritdoc />
+        protected override void Dispose(bool disposing)
+        {
+            base.Dispose(disposing);
+        }
+    }
+}

+ 67 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/ReferenceCountedCoreSession.cs

@@ -0,0 +1,67 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    /// <summary>
+    /// A reference counted core session.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Bindings.WrappingCoreSession" />
+    internal sealed class ReferenceCountedCoreSession : WrappingCoreSession
+    {
+        // private fields
+        private readonly object _lock = new object();
+        private int _referenceCount;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ReferenceCountedCoreSession"/> class.
+        /// </summary>
+        /// <param name="wrapped">The wrapped.</param>
+        public ReferenceCountedCoreSession(ICoreSession wrapped)
+            : base(wrapped, ownsWrapped: true)
+        {
+            _referenceCount = 1;
+        }
+
+        // public methods
+        /// <summary>
+        /// Decrements the reference count.
+        /// </summary>
+        public void DecrementReferenceCount()
+        {
+            lock (_lock)
+            {
+                ThrowIfDisposed();
+                if (--_referenceCount == 0)
+                {
+                    Dispose();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Increments the reference count.
+        /// </summary>
+        public void IncrementReferenceCount()
+        {
+            lock (_lock)
+            {
+                ThrowIfDisposed();
+                _referenceCount++;
+            }
+        }
+    }
+}

+ 107 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/WrappingCoreServerSession.cs

@@ -0,0 +1,107 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver
+{
+    internal abstract class WrappingCoreServerSession : ICoreServerSession
+    {
+        // private fields
+        protected bool _disposed;
+        private readonly bool _ownsWrapped;
+        private readonly ICoreServerSession _wrapped;
+
+        // constructors
+        public WrappingCoreServerSession(ICoreServerSession wrapped, bool ownsWrapped)
+        {
+            _wrapped = Ensure.IsNotNull(wrapped, nameof(wrapped));
+            _ownsWrapped = ownsWrapped;
+        }
+
+        // public properties
+        public BsonDocument Id
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.Id;
+            }
+        }
+
+        public DateTime? LastUsedAt
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.LastUsedAt;
+            }
+        }
+
+        public ICoreServerSession Wrapped
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped;
+            }
+        }
+
+        // public methods
+        public long AdvanceTransactionNumber()
+        {
+            ThrowIfDisposed();
+            return _wrapped.AdvanceTransactionNumber();
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        public void WasUsed()
+        {
+            ThrowIfDisposed();
+            _wrapped.WasUsed();
+        }
+
+        // protected methods
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_disposed)
+            {
+                if (disposing)
+                {
+                    if (_ownsWrapped)
+                    {
+                        _wrapped.Dispose();
+                    }
+                }
+                _disposed = true;
+            }
+        }
+
+        protected void ThrowIfDisposed()
+        {
+            if (_disposed)
+            {
+                throw new ObjectDisposedException(GetType().FullName);
+            }
+        }
+    }
+}

+ 271 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Bindings/WrappingCoreSession.cs

@@ -0,0 +1,271 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Clusters;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.Bindings
+{
+    /// <summary>
+    /// An abstract base class for a core session that wraps another core session.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Bindings.ICoreSession" />
+    public abstract class WrappingCoreSession : ICoreSession
+    {
+        // private fields
+        private bool _disposed;
+        private readonly bool _ownsWrapped;
+        private readonly ICoreSession _wrapped;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="WrappingCoreSession" /> class.
+        /// </summary>
+        /// <param name="wrapped">The wrapped.</param>
+        /// <param name="ownsWrapped">if set to <c>true</c> [owns wrapped].</param>
+        public WrappingCoreSession(ICoreSession wrapped, bool ownsWrapped)
+        {
+            _wrapped = Ensure.IsNotNull(wrapped, nameof(wrapped));
+            _ownsWrapped = ownsWrapped;
+        }
+
+        // public properties
+        /// <inheritdoc />
+        public virtual BsonDocument ClusterTime
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.ClusterTime;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual CoreTransaction CurrentTransaction
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.CurrentTransaction;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual BsonDocument Id
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.Id;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual bool IsCausallyConsistent
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.IsCausallyConsistent;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual bool IsImplicit
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.IsImplicit;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual bool IsInTransaction
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.IsInTransaction;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual BsonTimestamp OperationTime
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.OperationTime;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual CoreSessionOptions Options
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.Options;
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual ICoreServerSession ServerSession
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped.ServerSession;
+            }
+        }
+
+        /// <summary>
+        /// Gets the wrapped session.
+        /// </summary>
+        /// <value>
+        /// The wrapped session.
+        /// </value>
+        public ICoreSession Wrapped
+        {
+            get
+            {
+                ThrowIfDisposed();
+                return _wrapped;
+            }
+        }
+
+        // public methods
+        /// <inheritdoc />
+        public virtual void AbortTransaction(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            ThrowIfDisposed();
+            _wrapped.AbortTransaction(cancellationToken);
+        }
+
+        /// <inheritdoc />
+        public virtual Task AbortTransactionAsync(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            ThrowIfDisposed();
+            return _wrapped.AbortTransactionAsync(cancellationToken);
+        }
+
+        /// <inheritdoc />
+        public virtual void AboutToSendCommand()
+        {
+            ThrowIfDisposed();
+            _wrapped.AboutToSendCommand();
+        }
+
+        /// <inheritdoc />
+        public virtual void AdvanceClusterTime(BsonDocument newClusterTime)
+        {
+            ThrowIfDisposed();
+            _wrapped.AdvanceClusterTime(newClusterTime);
+        }
+
+        /// <inheritdoc />
+        public virtual void AdvanceOperationTime(BsonTimestamp newOperationTime)
+        {
+            ThrowIfDisposed();
+            _wrapped.AdvanceOperationTime(newOperationTime);
+        }
+
+        /// <inheritdoc />
+        public long AdvanceTransactionNumber()
+        {
+            return _wrapped.AdvanceTransactionNumber();
+        }
+
+        /// <inheritdoc />
+        public virtual void CommitTransaction(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            ThrowIfDisposed();
+            _wrapped.CommitTransaction(cancellationToken);
+        }
+
+        /// <inheritdoc />
+        public virtual Task CommitTransactionAsync(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            ThrowIfDisposed();
+            return _wrapped.CommitTransactionAsync(cancellationToken);
+        }
+
+        /// <inheritdoc />
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        /// <inheritdoc />
+        public virtual void StartTransaction(TransactionOptions transactionOptions = null)
+        {
+            ThrowIfDisposed();
+            _wrapped.StartTransaction(transactionOptions);
+        }
+
+        /// <inheritdoc />
+        public virtual void WasUsed()
+        {
+            ThrowIfDisposed();
+            _wrapped.WasUsed();
+        }
+
+        // protected methods
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources.
+        /// </summary>
+        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (!_disposed)
+            {
+                if (disposing)
+                {
+                    if (_ownsWrapped)
+                    {
+                        _wrapped.Dispose();
+                    }
+                }
+                _disposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether this instance is disposed.
+        /// </summary>
+        /// <returns>
+        ///   <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
+        /// </returns>
+        protected bool IsDisposed() => _disposed;
+
+        /// <summary>
+        /// Throws if disposed.
+        /// </summary>
+        /// <exception cref="ObjectDisposedException"></exception>
+        protected void ThrowIfDisposed()
+        {
+            if (_disposed)
+            {
+                throw new ObjectDisposedException(GetType().FullName);
+            }
+        }
+    }
+}

+ 84 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Clusters/ClusterClock.cs

@@ -0,0 +1,84 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.Clusters
+{
+    /// <summary>
+    /// A cluster clock.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Clusters.IClusterClock" />
+    internal class ClusterClock : IClusterClock
+    {
+        #region static
+        // public static methods
+        /// <summary>
+        /// Returns the greater of two cluster times.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>The greater cluster time.</returns>
+        public static BsonDocument GreaterClusterTime(BsonDocument x, BsonDocument y)
+        {
+            if (x == null)
+            {
+                return y;
+            }
+            else if (y == null)
+            {
+                return x;
+            }
+            else
+            {
+                var xTimestamp = x["clusterTime"].AsBsonTimestamp;
+                var yTimestamp = y["clusterTime"].AsBsonTimestamp;
+                return xTimestamp > yTimestamp ? x : y;
+            }
+        }
+        #endregion
+
+        // private fields
+        private BsonDocument _clusterTime;
+
+        // public properties
+        /// <inheritdoc />
+        public BsonDocument ClusterTime => _clusterTime;
+
+        // public methods
+        /// <inheritdoc />
+        public void AdvanceClusterTime(BsonDocument newClusterTime)
+        {
+            Ensure.IsNotNull(newClusterTime, nameof(newClusterTime));
+            _clusterTime = GreaterClusterTime(_clusterTime, newClusterTime);
+        }
+    }
+
+    /// <summary>
+    /// An object that represents no cluster clock.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Clusters.IClusterClock" />
+    internal sealed class NoClusterClock : IClusterClock
+    {
+        /// <inheritdoc />
+        public BsonDocument ClusterTime => null;
+
+        /// <inheritdoc />
+        public void AdvanceClusterTime(BsonDocument newClusterTime)
+        {
+        }
+    }
+}

+ 41 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Clusters/IClusterClock.cs

@@ -0,0 +1,41 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+
+namespace MongoDB.Driver.Core.Clusters
+{
+    /// <summary>
+    /// A cluster clock.
+    /// </summary>
+    public interface IClusterClock
+    {
+        // properties
+        /// <summary>
+        /// Gets the cluster time.
+        /// </summary>
+        /// <value>
+        /// The cluster time.
+        /// </value>
+        BsonDocument ClusterTime { get; }
+
+        // methods
+        /// <summary>
+        /// Advances the cluster time.
+        /// </summary>
+        /// <param name="newClusterTime">The new cluster time.</param>
+        void AdvanceClusterTime(BsonDocument newClusterTime);
+    }
+}

+ 61 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Configuration/SdamLoggingSettings.cs

@@ -0,0 +1,61 @@
+/* Copyright 2018–present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver.Core.Configuration
+{
+    /// <summary>
+    /// Represents settings for SDAM logging.
+    /// </summary>
+    public class SdamLoggingSettings
+    {   
+        private readonly string _logFilename;
+        
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SdamLoggingSettings"/> class.
+        /// </summary>
+        /// <param name="logFilename">The filename to log to. An empty string or null  will disable logging.
+        /// "stdout" sneds output to stdout. </param>
+        public SdamLoggingSettings(Optional<string> logFilename = default(Optional<string>))
+        {
+            _logFilename = logFilename.WithDefault(null);
+        }
+        
+        /// <summary>
+        /// The filename to log to.
+        /// </summary>
+        public string LogFilename => _logFilename;
+        
+        // methods
+        /// <summary>
+        /// Returns a new SdamLoggingSettings instance with some settings changed.
+        /// </summary>
+        /// <param name="logFilename">The filename.</param>
+        /// <returns>A new SdamLoggingSettings instance.</returns>
+        public SdamLoggingSettings With(Optional<string> logFilename = default(Optional<string>))
+        {
+            return new SdamLoggingSettings(logFilename: logFilename.WithDefault(_logFilename));
+        }
+        
+        /// <summary>
+        /// Whether or not SDAM logging is enabled.
+        /// </summary>
+        internal bool IsLoggingEnabled => !string.IsNullOrEmpty(_logFilename);
+
+        /// <summary>
+        /// Whether or not logging should be written to stdout.
+        /// </summary>
+        internal bool ShouldLogToStdout => _logFilename == "stdout";
+    }
+}

+ 92 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Connections/IsMasterHelper.cs

@@ -0,0 +1,92 @@
+/* Copyright 2018–present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Authentication;
+using MongoDB.Driver.Core.WireProtocol;
+
+namespace MongoDB.Driver.Core.Connections
+{
+    internal static class IsMasterHelper
+    {   
+        internal static BsonDocument AddClientDocumentToCommand(BsonDocument command, BsonDocument clientDocument)
+        {
+            return command.Add("client", clientDocument, clientDocument != null); 
+        }
+        
+        internal static BsonDocument CreateCommand()
+        {
+            return new BsonDocument { { "isMaster", 1 } };
+        }
+        
+        internal static BsonDocument CustomizeCommand(BsonDocument command, IReadOnlyList<IAuthenticator> authenticators)
+        {
+            return authenticators.Count == 1 ? authenticators[0].CustomizeInitialIsMasterCommand(command) : command;
+        }
+
+        internal static CommandWireProtocol<BsonDocument> CreateProtocol(BsonDocument isMasterCommand)
+        {    
+            return new CommandWireProtocol<BsonDocument>(
+                databaseNamespace: DatabaseNamespace.Admin,
+                command: isMasterCommand,
+                slaveOk: true,
+                resultSerializer: BsonDocumentSerializer.Instance,
+                messageEncoderSettings: null);
+        }
+        
+        internal static IsMasterResult GetResult(
+            IConnection connection,
+            CommandWireProtocol<BsonDocument> isMasterProtocol,
+            CancellationToken cancellationToken)
+        {
+            try
+            {
+                return new IsMasterResult(isMasterProtocol.Execute(connection, cancellationToken));
+            }
+            catch (MongoCommandException ex) when (ex.Code == 11)
+            {
+                // If the isMaster command fails with error code 11 (UserNotFound), drivers must consider authentication
+                // to have failed.In such a case, drivers MUST raise an error that is equivalent to what they would have
+                // raised if the authentication mechanism were specified and the server responded the same way.
+                throw new MongoAuthenticationException(connection.ConnectionId, "User not found.", ex);
+            }
+        }
+        
+        internal static async Task<IsMasterResult> GetResultAsync(
+            IConnection connection,
+            CommandWireProtocol<BsonDocument> isMasterProtocol,
+            CancellationToken cancellationToken)
+        {
+            try
+            {
+                var isMasterResult = await isMasterProtocol.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false);
+                return new IsMasterResult(isMasterResult);
+            }
+            catch (MongoCommandException ex) when (ex.Code == 11)
+            {
+                // If the isMaster command fails with error code 11 (UserNotFound), drivers must consider authentication
+                // to have failed.In such a case, drivers MUST raise an error that is equivalent to what they would have
+                // raised if the authentication mechanism were specified and the server responded the same way.
+                throw new MongoAuthenticationException(connection.ConnectionId, "User not found.", ex);
+            }
+        }
+    }
+}

+ 37 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Connections/KeepAliveValues.cs

@@ -0,0 +1,37 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+
+namespace MongoDB.Driver.Core.Connections
+{
+    internal struct KeepAliveValues
+    {
+        public ulong OnOff { get; set; }
+        public ulong KeepAliveTime { get; set; }
+        public ulong KeepAliveInterval { get; set; }
+
+        public byte[] ToBytes()
+        {
+            // set the tcp_keepalive struct at the following page for documentation of the buffer layout
+            // https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx
+            var bytes = new byte[24];
+            Array.Copy(BitConverter.GetBytes(OnOff), 0, bytes, 0, 8);
+            Array.Copy(BitConverter.GetBytes(KeepAliveTime), 0, bytes, 8, 8);
+            Array.Copy(BitConverter.GetBytes(KeepAliveInterval), 0, bytes, 16, 8);
+            return bytes;
+        }
+    }
+}

+ 158 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Events/Diagnostics/TraceSourceSdamEventSubscriber.cs

@@ -0,0 +1,158 @@
+/* Copyright 2018–present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Diagnostics;
+using System.Reflection;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.Events.Diagnostics
+{
+    /// <summary>
+    /// An event subscriber that writes SDAM events to a trace source.
+    /// </summary>
+    public sealed class TraceSourceSdamEventSubscriber : IEventSubscriber
+    {
+        private readonly TraceSource _traceSource;
+        private readonly ReflectionEventSubscriber _subscriber;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TraceSourceSdamEventSubscriber"/> class.
+        /// </summary>
+        /// <param name="traceSource">The trace source.</param>
+        public TraceSourceSdamEventSubscriber(TraceSource traceSource)
+        {
+            _traceSource = Ensure.IsNotNull(traceSource, nameof(traceSource));
+            _subscriber = new ReflectionEventSubscriber(this, bindingFlags: BindingFlags.Instance | BindingFlags.NonPublic);
+        }
+
+        /// <inheritdoc />
+        public bool TryGetEventHandler<TEvent>(out Action<TEvent> handler)
+        {
+            return _subscriber.TryGetEventHandler(out handler);
+        }
+
+        // Clusters
+        private void Handle(ClusterOpeningEvent @event)
+        {
+            Info(TraceSourceEventHelper.ClusterIdBase, "{0}: opening.", TraceSourceEventHelper.Label(@event.ClusterId));
+        }
+
+        private void Handle(ClusterOpenedEvent @event)
+        {
+            Debug(TraceSourceEventHelper.ClusterIdBase + 1, "{0}: opened in {1}ms.", TraceSourceEventHelper.Label(@event.ClusterId), @event.Duration.TotalMilliseconds);
+        }
+
+        private void Handle(ClusterClosingEvent @event)
+        {
+            Debug(TraceSourceEventHelper.ClusterIdBase + 2, "{0}: closing.", TraceSourceEventHelper.Label(@event.ClusterId));
+        }
+
+        private void Handle(ClusterClosedEvent @event)
+        {
+            Info(TraceSourceEventHelper.ClusterIdBase + 3, "{0}: closed in {1}ms.", TraceSourceEventHelper.Label(@event.ClusterId), @event.Duration.TotalMilliseconds);
+        }
+
+        private void Handle(ClusterAddingServerEvent @event)
+        {
+            Info(TraceSourceEventHelper.ClusterIdBase + 4, "{0}: adding server at endpoint {1}.", TraceSourceEventHelper.Label(@event.ClusterId), TraceSourceEventHelper.Format(@event.EndPoint));
+        }
+
+        private void Handle(ClusterAddedServerEvent @event)
+        {
+            Debug(TraceSourceEventHelper.ClusterIdBase + 5, "{0}: added server {1} in {2}ms.", TraceSourceEventHelper.Label(@event.ServerId.ClusterId), TraceSourceEventHelper.Format(@event.ServerId), @event.Duration.TotalMilliseconds);
+        }
+
+        private void Handle(ClusterRemovingServerEvent @event)
+        {
+            Debug(TraceSourceEventHelper.ClusterIdBase + 6, "{0}: removing server {1}. Reason: {2}", TraceSourceEventHelper.Label(@event.ServerId.ClusterId), TraceSourceEventHelper.Format(@event.ServerId), @event.Reason);
+        }
+
+        private void Handle(ClusterRemovedServerEvent @event)
+        {
+            Info(TraceSourceEventHelper.ClusterIdBase + 7, "{0}: removed server {1} in {2}ms. Reason: {3}", TraceSourceEventHelper.Label(@event.ServerId.ClusterId), TraceSourceEventHelper.Format(@event.ServerId), @event.Duration.TotalMilliseconds, @event.Reason);
+        }
+
+        private void Handle(ClusterDescriptionChangedEvent @event)
+        {
+            Info(TraceSourceEventHelper.ClusterIdBase + 8, "{0}: {1}", TraceSourceEventHelper.Label(@event.OldDescription.ClusterId), @event.NewDescription);
+        }
+        
+        private void Handle(SdamInformationEvent @event)
+        {
+            Info(TraceSourceEventHelper.ClusterIdBase + 9, "{0}", @event);
+        }
+
+        // Servers
+        private void Handle(ServerOpeningEvent @event)
+        {
+            Info(TraceSourceEventHelper.ServerIdBase, "{0}: opening.", TraceSourceEventHelper.Label(@event.ServerId));
+        }
+
+        private void Handle(ServerOpenedEvent @event)
+        {
+            Debug(TraceSourceEventHelper.ServerIdBase + 1, "{0}: opened in {1}ms.", TraceSourceEventHelper.Label(@event.ServerId), @event.Duration.TotalMilliseconds);
+        }
+
+        private void Handle(ServerClosingEvent @event)
+        {
+            Debug(TraceSourceEventHelper.ServerIdBase + 2, "{0}: closing.", TraceSourceEventHelper.Label(@event.ServerId));
+        }
+
+        private void Handle(ServerClosedEvent @event)
+        {
+            Info(TraceSourceEventHelper.ServerIdBase + 3, "{0}: closed in {1}ms.", TraceSourceEventHelper.Label(@event.ServerId), @event.Duration.TotalMilliseconds);
+        }
+
+        private void Handle(ServerHeartbeatStartedEvent @event)
+        {
+            Debug(TraceSourceEventHelper.ServerIdBase + 4, "{0}: sending heartbeat.", TraceSourceEventHelper.Label(@event.ConnectionId));
+        }
+
+        private void Handle(ServerHeartbeatSucceededEvent @event)
+        {
+            Debug(TraceSourceEventHelper.ServerIdBase + 5, "{0}: sent heartbeat in {1}ms.", TraceSourceEventHelper.Label(@event.ConnectionId), @event.Duration.TotalMilliseconds);
+        }
+
+        private void Handle(ServerHeartbeatFailedEvent @event)
+        {
+            Error(TraceSourceEventHelper.ServerIdBase + 6, @event.Exception, "{0}: error sending heartbeat.", TraceSourceEventHelper.Label(@event.ConnectionId));
+        }
+
+        private void Handle(ServerDescriptionChangedEvent @event)
+        {
+            Debug(TraceSourceEventHelper.ServerIdBase + 7, "{0}: {1}", TraceSourceEventHelper.Label(@event.OldDescription.ServerId), @event.NewDescription);
+        }
+
+        private void Debug(int id, string message, params object[] args)
+        {
+            _traceSource.TraceEvent(TraceEventType.Verbose, id, message, args);
+        }
+
+        private void Info(int id, string message, params object[] args)
+        {
+            _traceSource.TraceEvent(TraceEventType.Information, id, message, args);
+        }
+
+        private void Error(int id, Exception ex, string message, params object[] args)
+        {
+            _traceSource.TraceEvent(
+                TraceEventType.Error,
+                id,
+                message + Environment.NewLine + ex.ToString(),
+                args);
+        }
+    }
+}

+ 57 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Events/SdamInformationEvent.cs

@@ -0,0 +1,57 @@
+/* Copyright 2018–present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+
+namespace MongoDB.Driver.Core.Events
+{
+    /// <preliminary/>
+    /// <summary>
+    /// An informational event used for logging Server Discovery and Monitoring (SDAM) events. 
+    /// </summary>
+    public struct SdamInformationEvent
+    {
+        private readonly Lazy<string> _message;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SdamInformationEvent"/> struct.
+        /// </summary>
+        /// <param name="createMessage">Function that creates the message to log.</param>
+        public SdamInformationEvent(Func<string> createMessage) 
+            : this(new Lazy<string>(createMessage))
+        {
+        }
+        
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SdamInformationEvent"/> struct.
+        /// </summary>
+        /// <param name="message">The message to log.</param>
+        public SdamInformationEvent(Lazy<string> message)
+        {
+            _message = message;
+        }
+        
+        /// <summary>
+        /// Gets the message.
+        /// </summary>
+        public string Message => _message.Value;
+
+        /// <inheritdoc />
+        public override string ToString()
+        {
+            return $@"{{type: ""{GetType().Name}"", message: ""{Message}"" }}";
+        }
+    }
+}

+ 69 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Misc/FixedCountBatchableSourceSerializer.cs

@@ -0,0 +1,69 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+
+namespace MongoDB.Driver.Core.Misc
+{
+    /// <summary>
+    /// A serializer for BatchableSource that serializes a fixed count of items.
+    /// </summary>
+    /// <typeparam name="TItem">The type of the items.</typeparam>
+    public class FixedCountBatchableSourceSerializer<TItem> : SerializerBase<BatchableSource<TItem>>
+    {
+        // private fields
+        private readonly int _count;
+        private readonly IElementNameValidator _itemElementNameValidator;
+        private readonly IBsonSerializer<TItem> _itemSerializer;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="FixedCountBatchableSourceSerializer{TITem}" /> class.
+        /// </summary>
+        /// <param name="itemSerializer">The item serializer.</param>
+        /// <param name="itemElementNameValidator">The item element name validator.</param>
+        /// <param name="count">The count.</param>
+        public FixedCountBatchableSourceSerializer(IBsonSerializer<TItem> itemSerializer, IElementNameValidator itemElementNameValidator, int count)
+        {
+            _itemSerializer = Ensure.IsNotNull(itemSerializer, nameof(itemSerializer));
+            _itemElementNameValidator = Ensure.IsNotNull(itemElementNameValidator, nameof(itemElementNameValidator));
+            _count = Ensure.IsBetween(count, 0, int.MaxValue, nameof(count));
+        }
+
+        // public methods
+        /// <inheritdoc />
+        public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, BatchableSource<TItem> value)
+        {
+            Ensure.IsNotNull(value, nameof(value));
+            var writer = context.Writer;
+
+            writer.PushElementNameValidator(_itemElementNameValidator);
+            try
+            {
+                for (var i = 0; i < _count; i++)
+                {
+                    var item = value.Items[value.Offset + i];
+                    _itemSerializer.Serialize(context, item);
+                }
+            }
+            finally
+            {
+                writer.PopElementNameValidator();
+            }
+        }
+    }
+}

+ 113 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Misc/IBatchableSource.cs

@@ -0,0 +1,113 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace MongoDB.Driver.Core.Misc
+{
+    /// <summary>
+    /// Represents a batch of items that can be split if not all items can be processed at once.
+    /// </summary>
+    /// <typeparam name="T">The type of the items.</typeparam>
+    public interface IBatchableSource<out T>
+    {
+        // properties
+        /// <summary>
+        /// Gets a value indicating whether all items were processed.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if all items were processed; otherwise, <c>false</c>.
+        /// </value>
+        bool AllItemsWereProcessed { get; }
+
+        /// <summary>
+        /// Gets a value indicating whether the batch can be split.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if the batch can be split; otherwise, <c>false</c>.
+        /// </value>
+        bool CanBeSplit { get; }
+
+        /// <summary>
+        /// Gets the count.
+        /// </summary>
+        /// <value>
+        /// The count.
+        /// </value>
+        int Count { get; }
+
+        /// <summary>
+        /// Gets the items.
+        /// </summary>
+        /// <value>
+        /// The items.
+        /// </value>
+        IReadOnlyList<T> Items { get; }
+
+        /// <summary>
+        /// Gets the offset.
+        /// </summary>
+        /// <value>
+        /// The offset.
+        /// </value>
+        int Offset { get; }
+
+        /// <summary>
+        /// Gets the count of processed items. Equal to zero until SetProcessedCount has been called.
+        /// </summary>
+        /// <value>
+        /// The count of processed items.
+        /// </value>
+        int ProcessedCount { get; }
+
+        // methods
+        /// <summary>
+        /// Advances past the processed items.
+        /// </summary>
+        void AdvancePastProcessedItems();
+
+        /// <summary>
+        /// Gets the items in the batch.
+        /// </summary>
+        /// <returns>
+        /// The items in the batch.
+        /// </returns>
+        IReadOnlyList<T> GetBatchItems();
+
+        /// <summary>
+        /// Gets the items that were processed.
+        /// </summary>
+        /// <returns>
+        /// The items that were processed.
+        /// </returns>
+        IReadOnlyList<T> GetProcessedItems();
+
+        /// <summary>
+        /// Gets the items that were not processed.
+        /// </summary>
+        /// <returns>
+        /// The items that were not processed.
+        /// </returns>
+        IReadOnlyList<T> GetUnprocessedItems();
+
+        /// <summary>
+        /// Sets the processed count.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        void SetProcessedCount(int value);
+    }
+}

+ 120 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Misc/SizeLimitingBatchableSourceSerializer.cs

@@ -0,0 +1,120 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+
+namespace MongoDB.Driver.Core.Misc
+{
+    /// <summary>
+    /// A serializer for BatchableSource that serializes as much of the BatchableSource as fits in the max batch count and size.
+    /// </summary>
+    /// <typeparam name="TItem">The type of the items.</typeparam>
+    public class SizeLimitingBatchableSourceSerializer<TItem> : SerializerBase<BatchableSource<TItem>>
+    {
+        // private fields
+        private readonly IElementNameValidator _itemElementNameValidator;
+        private readonly IBsonSerializer<TItem> _itemSerializer;
+        private readonly int _maxBatchCount;
+        private readonly int _maxBatchSize;
+        private readonly int _maxItemSize;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="SizeLimitingBatchableSourceSerializer{TItem}" /> class.
+        /// </summary>
+        /// <param name="itemSerializer">The item serializer.</param>
+        /// <param name="itemElementNameValidator">The item element name validator.</param>
+        /// <param name="maxBatchCount">The maximum batch count.</param>
+        /// <param name="maxItemSize">The maximum size of a serialized item.</param>
+        /// <param name="maxBatchSize">The maximum size of the batch.</param>
+        public SizeLimitingBatchableSourceSerializer(
+            IBsonSerializer<TItem> itemSerializer, 
+            IElementNameValidator itemElementNameValidator, 
+            int maxBatchCount,
+            int maxItemSize, 
+            int maxBatchSize)
+        {
+            _itemSerializer = Ensure.IsNotNull(itemSerializer, nameof(itemSerializer));
+            _itemElementNameValidator = Ensure.IsNotNull(itemElementNameValidator, nameof(itemElementNameValidator));
+            _maxBatchCount = Ensure.IsGreaterThanZero(maxBatchCount, nameof(maxBatchCount));
+            _maxItemSize = Ensure.IsGreaterThanZero(maxItemSize, nameof(maxItemSize));
+            _maxBatchSize = Ensure.IsGreaterThanZero(maxBatchSize, nameof(maxBatchSize));
+        }
+
+        // public methods
+        /// <inheritdoc />
+        public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, BatchableSource<TItem> value)
+        {
+            Ensure.IsNotNull(value, nameof(value));
+
+            var writer = context.Writer;
+            while (writer is WrappingBsonWriter)
+            {
+                writer = ((WrappingBsonWriter)writer).Wrapped;
+            }
+
+            var binaryWriter = writer as BsonBinaryWriter;
+            var startPosition = binaryWriter?.Position;
+
+            writer.PushSettings(s => { var bs = s as BsonBinaryWriterSettings; if (bs != null) { bs.MaxDocumentSize = _maxItemSize; } });
+            writer.PushElementNameValidator(_itemElementNameValidator);
+            try
+            {
+                var batchCount = Math.Min(value.Count, _maxBatchCount);
+                if (batchCount != value.Count && !value.CanBeSplit)
+                {
+                    throw new ArgumentException("Batch is too large.");
+                }
+
+                for (var i = 0; i < batchCount; i++)
+                {
+                    var itemPosition = binaryWriter?.Position;
+
+                    var item = value.Items[value.Offset + i];
+                    _itemSerializer.Serialize(context, args, item);
+
+                    // always process at least one item
+                    if (i > 0)
+                    {
+                        var batchSize = binaryWriter?.Position - startPosition;
+                        if (batchSize > _maxBatchSize)
+                        {
+                            if (value.CanBeSplit)
+                            {
+                                binaryWriter.BaseStream.Position = itemPosition.Value; // remove the last item
+                                binaryWriter.BaseStream.SetLength(itemPosition.Value);
+                                value.SetProcessedCount(i);
+                                return;
+                            }
+                            else
+                            {
+                                throw new ArgumentException("Batch is too large.");
+                            }
+                        }
+                    }
+                }
+                value.SetProcessedCount(batchCount);
+            }
+            finally
+            {
+                writer.PopElementNameValidator();
+                writer.PopSettings();
+            }
+        }
+    }
+}

+ 187 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/ChangeStreamCursor.cs

@@ -0,0 +1,187 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Misc;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// A change stream cursor.
+    /// </summary>
+    /// <typeparam name="TDocument">The type of the output documents.</typeparam>
+    /// <seealso cref="MongoDB.Driver.IAsyncCursor{TOutput}" />
+    internal sealed class ChangeStreamCursor<TDocument> : IAsyncCursor<TDocument>
+    {
+        // private fields
+        private readonly IReadBinding _binding;
+        private readonly IChangeStreamOperation<TDocument> _changeStreamOperation;
+        private IEnumerable<TDocument> _current;
+        private IAsyncCursor<RawBsonDocument> _cursor;
+        private bool _disposed;
+        private IBsonSerializer<TDocument> _documentSerializer;
+
+        // public properties
+        /// <inheritdoc />
+        public IEnumerable<TDocument> Current => _current;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ChangeStreamCursor{TDocument}" /> class.
+        /// </summary>
+        /// <param name="cursor">The cursor.</param>
+        /// <param name="documentSerializer">The document serializer.</param>
+        /// <param name="binding">The binding.</param>
+        /// <param name="changeStreamOperation">The change stream operation.</param>
+        public ChangeStreamCursor(
+            IAsyncCursor<RawBsonDocument> cursor,
+            IBsonSerializer<TDocument> documentSerializer,
+            IReadBinding binding,
+            IChangeStreamOperation<TDocument> changeStreamOperation)
+        {
+            _cursor = Ensure.IsNotNull(cursor, nameof(cursor));
+            _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer));
+            _binding = Ensure.IsNotNull(binding, nameof(binding));
+            _changeStreamOperation = Ensure.IsNotNull(changeStreamOperation, nameof(changeStreamOperation));
+        }
+
+        // public methods
+        /// <inheritdoc />
+        public void Dispose()
+        {
+            if (!_disposed)
+            {
+                _disposed = true;
+                _cursor.Dispose();
+                _binding.Dispose();
+            }
+        }
+
+        /// <inheritdoc/>
+        public bool MoveNext(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            bool hasMore;
+            while (true)
+            {
+                try
+                {
+                    hasMore = _cursor.MoveNext(cancellationToken);
+                    break;
+                }
+                catch (Exception ex) when (RetryabilityHelper.IsResumableChangeStreamException(ex))
+                {
+                    var newCursor = _changeStreamOperation.Resume(_binding, cancellationToken);
+                    _cursor.Dispose();
+                    _cursor = newCursor;
+                }
+            }
+
+            ProcessBatch(hasMore);
+            return hasMore;
+        }
+
+        /// <inheritdoc/>
+        public async Task<bool> MoveNextAsync(CancellationToken cancellationToken = default(CancellationToken))
+        {          
+            bool hasMore;
+            while (true)
+            {
+                try
+                {
+                    hasMore = await _cursor.MoveNextAsync(cancellationToken).ConfigureAwait(false);
+                    break;
+                }
+                catch (Exception ex) when (RetryabilityHelper.IsResumableChangeStreamException(ex))
+                {
+                    var newCursor = await _changeStreamOperation.ResumeAsync(_binding, cancellationToken).ConfigureAwait(false);
+                    _cursor.Dispose();
+                    _cursor = newCursor;
+                }
+            }
+
+            ProcessBatch(hasMore);
+            return hasMore;
+        }
+
+        // private methods
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
+        private TDocument DeserializeDocument(RawBsonDocument rawDocument)
+        {
+            using (var stream = new ByteBufferStream(rawDocument.Slice, ownsBuffer: false))
+            using (var reader = new BsonBinaryReader(stream))
+            {
+                var context = BsonDeserializationContext.CreateRoot(reader);
+                return _documentSerializer.Deserialize(context);
+            }
+        }
+
+        private IEnumerable<TDocument> DeserializeDocuments(IEnumerable<RawBsonDocument> rawDocuments)
+        {
+            var documents = new List<TDocument>();
+            RawBsonDocument lastRawDocument = null;
+
+            foreach (var rawDocument in rawDocuments)
+            {
+                if (!rawDocument.Contains("_id"))
+                {
+                    throw new MongoClientException("Cannot provide resume functionality when the resume token is missing.");
+                }
+
+                var document = DeserializeDocument(rawDocument);
+                documents.Add(document);
+
+                lastRawDocument = rawDocument;
+            }
+
+            if (lastRawDocument != null)
+            {
+                _changeStreamOperation.ResumeAfter = lastRawDocument["_id"].DeepClone().AsBsonDocument;
+                _changeStreamOperation.StartAtOperationTime = null;
+            }
+
+            return documents;
+        }
+
+        private void ProcessBatch(bool hasMore)
+        {
+            if (hasMore)
+            {
+                try
+                {
+                    _current = DeserializeDocuments(_cursor.Current);
+                }
+                finally
+                {
+                    foreach (var rawDocument in _cursor.Current)
+                    {
+                        rawDocument.Dispose();
+                    }
+                }
+            }
+            else
+            {
+                _current = null;
+            }
+        }
+    }
+}

+ 383 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/ChangeStreamOperation.cs

@@ -0,0 +1,383 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// A change stream operation.
+    /// </summary>
+    /// <typeparam name="TResult">The type of the result.</typeparam>
+    public interface IChangeStreamOperation<TResult> : IReadOperation<IAsyncCursor<TResult>>
+    {
+        // properties
+        /// <summary>
+        /// Gets or sets the resume after value.
+        /// </summary>
+        /// <value>
+        /// The resume after value.
+        /// </value>
+        BsonDocument ResumeAfter { get; set; }
+
+        /// <summary>
+        /// Gets or sets the start at operation time.
+        /// </summary>
+        /// <value>
+        /// The start at operation time.
+        /// </value>
+        BsonTimestamp StartAtOperationTime { get; set; }
+
+        // methods
+        /// <summary>
+        /// Resumes the operation after a resume token.
+        /// </summary>
+        /// <param name="binding">The binding.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A cursor.</returns>
+        IAsyncCursor<RawBsonDocument> Resume(IReadBinding binding, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Resumes the operation after a resume token.
+        /// </summary>
+        /// <param name="binding">The binding.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A Task whose result is a cursor.</returns>
+        Task<IAsyncCursor<RawBsonDocument>> ResumeAsync(IReadBinding binding, CancellationToken cancellationToken);
+    }
+
+    /// <summary>
+    /// A change stream operation.
+    /// </summary>
+    /// <typeparam name="TResult">The type of the result values.</typeparam>
+    public class ChangeStreamOperation<TResult> : IChangeStreamOperation<TResult>
+    {
+        // private fields
+        private int? _batchSize;
+        private Collation _collation;
+        private readonly CollectionNamespace _collectionNamespace;
+        private readonly DatabaseNamespace _databaseNamespace;
+        private ChangeStreamFullDocumentOption _fullDocument = ChangeStreamFullDocumentOption.Default;
+        private TimeSpan? _maxAwaitTime;
+        private readonly MessageEncoderSettings _messageEncoderSettings;
+        private readonly IReadOnlyList<BsonDocument> _pipeline;
+        private ReadConcern _readConcern = ReadConcern.Default;
+        private readonly IBsonSerializer<TResult> _resultSerializer;
+        private BsonDocument _resumeAfter;
+        private BsonTimestamp _startAtOperationTime;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ChangeStreamOperation{TResult}"/> class.
+        /// </summary>
+        /// <param name="pipeline">The pipeline.</param>
+        /// <param name="resultSerializer">The result value serializer.</param>
+        /// <param name="messageEncoderSettings">The message encoder settings.</param>
+        public ChangeStreamOperation(
+            IEnumerable<BsonDocument> pipeline, 
+            IBsonSerializer<TResult> resultSerializer, 
+            MessageEncoderSettings messageEncoderSettings)
+        {
+            _pipeline = Ensure.IsNotNull(pipeline, nameof(pipeline)).ToList();
+            _resultSerializer = Ensure.IsNotNull(resultSerializer, nameof(resultSerializer));
+            _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings));
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ChangeStreamOperation{TResult}"/> class.
+        /// </summary>
+        /// <param name="databaseNamespace">The database namespace.</param>
+        /// <param name="pipeline">The pipeline.</param>
+        /// <param name="resultSerializer">The result value serializer.</param>
+        /// <param name="messageEncoderSettings">The message encoder settings.</param>
+        public ChangeStreamOperation(
+            DatabaseNamespace databaseNamespace,
+            IEnumerable<BsonDocument> pipeline,
+            IBsonSerializer<TResult> resultSerializer,
+            MessageEncoderSettings messageEncoderSettings)
+            : this(pipeline, resultSerializer, messageEncoderSettings)
+        {
+            _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace));
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ChangeStreamOperation{TResult}"/> class.
+        /// </summary>
+        /// <param name="collectionNamespace">The collection namespace.</param>
+        /// <param name="pipeline">The pipeline.</param>
+        /// <param name="resultSerializer">The result value serializer.</param>
+        /// <param name="messageEncoderSettings">The message encoder settings.</param>
+        public ChangeStreamOperation(
+            CollectionNamespace collectionNamespace,
+            IEnumerable<BsonDocument> pipeline,
+            IBsonSerializer<TResult> resultSerializer,
+            MessageEncoderSettings messageEncoderSettings)
+            : this(pipeline, resultSerializer, messageEncoderSettings)
+        {
+            _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets or sets the size of the batch.
+        /// </summary>
+        /// <value>
+        /// The size of the batch.
+        /// </value>
+        public int? BatchSize
+        {
+            get { return _batchSize; }
+            set { _batchSize = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the collation.
+        /// </summary>
+        /// <value>
+        /// The collation.
+        /// </value>
+        public Collation Collation
+        {
+            get { return _collation; }
+            set { _collation = value; }
+        }
+
+        /// <summary>
+        /// Gets the collection namespace.
+        /// </summary>
+        /// <value>
+        /// The collection namespace.
+        /// </value>
+        public CollectionNamespace CollectionNamespace => _collectionNamespace;
+
+        /// <summary>
+        /// Gets the database namespace.
+        /// </summary>
+        /// <value>
+        /// The database namespace.
+        /// </value>
+        public DatabaseNamespace DatabaseNamespace => _databaseNamespace;
+
+        /// <summary>
+        /// Gets or sets the full document option.
+        /// </summary>
+        /// <value>
+        /// The full document option.
+        /// </value>
+        public ChangeStreamFullDocumentOption FullDocument
+        {
+            get { return _fullDocument; }
+            set { _fullDocument = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the maximum await time.
+        /// </summary>
+        /// <value>
+        /// The maximum await time.
+        /// </value>
+        public TimeSpan? MaxAwaitTime
+        {
+            get { return _maxAwaitTime; }
+            set { _maxAwaitTime = value; }
+        }
+
+        /// <summary>
+        /// Gets the message encoder settings.
+        /// </summary>
+        /// <value>
+        /// The message encoder settings.
+        /// </value>
+        public MessageEncoderSettings MessageEncoderSettings => _messageEncoderSettings;
+
+        /// <summary>
+        /// Gets the pipeline.
+        /// </summary>
+        /// <value>
+        /// The pipeline.
+        /// </value>
+        public IReadOnlyList<BsonDocument> Pipeline => _pipeline;
+
+        /// <summary>
+        /// Gets or sets the read concern.
+        /// </summary>
+        /// <value>
+        /// The read concern.
+        /// </value>
+        public ReadConcern ReadConcern
+        {
+            get { return _readConcern; }
+            set { _readConcern = Ensure.IsNotNull(value, nameof(value)); }
+        }
+
+        /// <summary>
+        /// Gets the result serializer.
+        /// </summary>
+        /// <value>
+        /// The result serializer.
+        /// </value>
+        public IBsonSerializer<TResult> ResultSerializer => _resultSerializer;
+
+        /// <inheritdoc />
+        public BsonDocument ResumeAfter
+        {
+            get { return _resumeAfter; }
+            set { _resumeAfter = value; }
+        }
+
+        /// <inheritdoc />
+        public BsonTimestamp StartAtOperationTime
+        {
+            get { return _startAtOperationTime; }
+            set { _startAtOperationTime = value; }
+        }
+
+        // public methods        
+        /// <inheritdoc />
+        public IAsyncCursor<TResult> Execute(IReadBinding binding, CancellationToken cancellationToken)
+        {
+            var bindingHandle = binding as IReadBindingHandle;
+            if (bindingHandle == null)
+            {
+                throw new ArgumentException("The binding value passed to ChangeStreamOperation.Execute must implement IReadBindingHandle.", nameof(binding));
+            }
+
+            IAsyncCursor<RawBsonDocument> cursor;
+            using (var channelSource = binding.GetReadChannelSource(cancellationToken))
+            using (var channel = channelSource.GetChannel(cancellationToken))
+            using (var channelBinding = new ChannelReadBinding(channelSource.Server, channel, binding.ReadPreference, binding.Session.Fork()))
+            {
+                cursor = Resume(channelBinding, cancellationToken);
+                if (_startAtOperationTime == null && _resumeAfter == null)
+                {
+                    var maxWireVersion = channel.ConnectionDescription.IsMasterResult.MaxWireVersion;
+                    if (maxWireVersion >= 7)
+                    {
+                        _startAtOperationTime = binding.Session.OperationTime;
+                    }
+                }
+            }
+
+            return new ChangeStreamCursor<TResult>(cursor, _resultSerializer, bindingHandle.Fork(), this);
+        }
+
+        /// <inheritdoc />
+        public async Task<IAsyncCursor<TResult>> ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken)
+        {
+            var bindingHandle = binding as IReadBindingHandle;
+            if (bindingHandle == null)
+            {
+                throw new ArgumentException("The binding value passed to ChangeStreamOperation.ExecuteAsync must implement IReadBindingHandle.", nameof(binding));
+            }
+
+            IAsyncCursor<RawBsonDocument> cursor;
+            using (var channelSource = await binding.GetReadChannelSourceAsync(cancellationToken).ConfigureAwait(false))
+            using (var channel = await channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false))
+            using (var channelBinding = new ChannelReadBinding(channelSource.Server, channel, binding.ReadPreference, binding.Session.Fork()))
+            {
+                cursor = await ResumeAsync(channelBinding, cancellationToken).ConfigureAwait(false);
+                if (_startAtOperationTime == null && _resumeAfter == null)
+                {
+                    var maxWireVersion = channel.ConnectionDescription.IsMasterResult.MaxWireVersion;
+                    if (maxWireVersion >= 7)
+                    {
+                        _startAtOperationTime = binding.Session.OperationTime;
+                    }
+                }
+            }
+
+            return new ChangeStreamCursor<TResult>(cursor, _resultSerializer, bindingHandle.Fork(), this);
+        }
+
+        /// <inheritdoc />
+        public IAsyncCursor<RawBsonDocument> Resume(IReadBinding binding, CancellationToken cancellationToken)
+        {
+            var aggregateOperation = CreateAggregateOperation();
+            return aggregateOperation.Execute(binding, cancellationToken);
+        }
+
+        /// <inheritdoc />
+        public Task<IAsyncCursor<RawBsonDocument>> ResumeAsync(IReadBinding binding, CancellationToken cancellationToken)
+        {
+            var aggregateOperation = CreateAggregateOperation();
+            return aggregateOperation.ExecuteAsync(binding, cancellationToken);
+        }
+
+        // private methods
+        private AggregateOperation<RawBsonDocument> CreateAggregateOperation()
+        {
+            var changeStreamStage = CreateChangeStreamStage();
+            var combinedPipeline = CreateCombinedPipeline(changeStreamStage);
+
+            AggregateOperation<RawBsonDocument> operation;
+            if (_collectionNamespace != null)
+            {
+                operation = new AggregateOperation<RawBsonDocument>(_collectionNamespace, combinedPipeline, RawBsonDocumentSerializer.Instance, _messageEncoderSettings);
+            }
+            else
+            {
+                var databaseNamespace = _databaseNamespace ?? DatabaseNamespace.Admin;
+                operation = new AggregateOperation<RawBsonDocument>(databaseNamespace, combinedPipeline, RawBsonDocumentSerializer.Instance, _messageEncoderSettings);
+            }
+
+            operation.BatchSize = _batchSize;
+            operation.Collation = _collation;
+            operation.MaxAwaitTime = _maxAwaitTime;
+            operation.ReadConcern = _readConcern;
+
+            return operation;
+        }
+
+        private BsonDocument CreateChangeStreamStage()
+        {
+            var changeStreamOptions = new BsonDocument
+            {
+                { "fullDocument", ToString(_fullDocument) },
+                { "allChangesForCluster", true, _collectionNamespace == null && _databaseNamespace == null },
+                { "startAtOperationTime", _startAtOperationTime, _startAtOperationTime != null },
+                { "resumeAfter", _resumeAfter, _resumeAfter != null }
+            };
+            return new BsonDocument("$changeStream", changeStreamOptions);
+        }
+
+        private List<BsonDocument> CreateCombinedPipeline(BsonDocument changeStreamStage)
+        {
+            var combinedPipeline = new List<BsonDocument>();
+            combinedPipeline.Add(changeStreamStage);
+            combinedPipeline.AddRange(_pipeline);
+            return combinedPipeline;
+        }
+
+        private string ToString(ChangeStreamFullDocumentOption fullDocument)
+        {
+            switch (fullDocument)
+            {
+                case ChangeStreamFullDocumentOption.Default: return "default";
+                case ChangeStreamFullDocumentOption.UpdateLookup: return "updateLookup";
+                default: throw new ArgumentException($"Invalid FullDocument option: {fullDocument}.", nameof(fullDocument));
+            }
+        }
+    }
+}

+ 238 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/CountDocumentsOperation.cs

@@ -0,0 +1,238 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// Represents a count documents operation.
+    /// </summary>
+    public class CountDocumentsOperation : IReadOperation<long>
+    {
+        // private fields
+        private Collation _collation;
+        private readonly CollectionNamespace _collectionNamespace;
+        private BsonDocument _filter;
+        private BsonValue _hint;
+        private long? _limit;
+        private TimeSpan? _maxTime;
+        private readonly MessageEncoderSettings _messageEncoderSettings;
+        private ReadConcern _readConcern = ReadConcern.Default;
+        private long? _skip;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CountOperation"/> class.
+        /// </summary>
+        /// <param name="collectionNamespace">The collection namespace.</param>
+        /// <param name="messageEncoderSettings">The message encoder settings.</param>
+        public CountDocumentsOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings)
+        {
+            _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace));
+            _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets or sets the collation.
+        /// </summary>
+        /// <value>
+        /// The collation.
+        /// </value>
+        public Collation Collation
+        {
+            get { return _collation; }
+            set { _collation = value; }
+        }
+        /// <summary>
+        /// Gets the collection namespace.
+        /// </summary>
+        /// <value>
+        /// The collection namespace.
+        /// </value>
+        public CollectionNamespace CollectionNamespace
+        {
+            get { return _collectionNamespace; }
+        }
+
+        /// <summary>
+        /// Gets or sets the filter.
+        /// </summary>
+        /// <value>
+        /// The filter.
+        /// </value>
+        public BsonDocument Filter
+        {
+            get { return _filter; }
+            set { _filter = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the index hint.
+        /// </summary>
+        /// <value>
+        /// The index hint.
+        /// </value>
+        public BsonValue Hint
+        {
+            get { return _hint; }
+            set { _hint = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets a limit on the number of matching documents to count.
+        /// </summary>
+        /// <value>
+        /// A limit on the number of matching documents to count.
+        /// </value>
+        public long? Limit
+        {
+            get { return _limit; }
+            set { _limit = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the maximum time the server should spend on this operation.
+        /// </summary>
+        /// <value>
+        /// The maximum time the server should spend on this operation.
+        /// </value>
+        public TimeSpan? MaxTime
+        {
+            get { return _maxTime; }
+            set { _maxTime = Ensure.IsNullOrInfiniteOrGreaterThanOrEqualToZero(value, nameof(value)); }
+        }
+
+        /// <summary>
+        /// Gets the message encoder settings.
+        /// </summary>
+        /// <value>
+        /// The message encoder settings.
+        /// </value>
+        public MessageEncoderSettings MessageEncoderSettings
+        {
+            get { return _messageEncoderSettings; }
+        }
+
+        /// <summary>
+        /// Gets or sets the read concern.
+        /// </summary>
+        /// <value>
+        /// The read concern.
+        /// </value>
+        public ReadConcern ReadConcern
+        {
+            get { return _readConcern; }
+            set { _readConcern = Ensure.IsNotNull(value, nameof(value)); }
+        }
+
+        /// <summary>
+        /// Gets or sets the number of documents to skip before counting the remaining matching documents.
+        /// </summary>
+        /// <value>
+        /// The number of documents to skip before counting the remaining matching documents.
+        /// </value>
+        public long? Skip
+        {
+            get { return _skip; }
+            set { _skip = value; }
+        }
+
+        // public methods
+        /// <inheritdoc/>
+        public long Execute(IReadBinding binding, CancellationToken cancellationToken)
+        {
+            Ensure.IsNotNull(binding, nameof(binding));
+            using (var channelSource = binding.GetReadChannelSource(cancellationToken))
+            using (var channel = channelSource.GetChannel(cancellationToken))
+            using (var channelBinding = new ChannelReadBinding(channelSource.Server, channel, binding.ReadPreference, binding.Session.Fork()))
+            {
+                var operation = CreateOperation();
+                var cursor = operation.Execute(channelBinding, cancellationToken);
+                var result = cursor.ToList(cancellationToken);
+                return ExtractCountFromResult(result);
+            }
+        }
+
+        /// <inheritdoc/>
+        public async Task<long> ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken)
+        {
+            Ensure.IsNotNull(binding, nameof(binding));
+            using (var channelSource = await binding.GetReadChannelSourceAsync(cancellationToken).ConfigureAwait(false))
+            using (var channel = await channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false))
+            using (var channelBinding = new ChannelReadBinding(channelSource.Server, channel, binding.ReadPreference, binding.Session.Fork()))
+            {
+                var operation = CreateOperation();
+                var cursor = await operation.ExecuteAsync(channelBinding, cancellationToken).ConfigureAwait(false);
+                var result = await cursor.ToListAsync(cancellationToken).ConfigureAwait(false);
+                return ExtractCountFromResult(result);
+            }
+        }
+
+        // private methods
+        private AggregateOperation<BsonDocument> CreateOperation()
+        {
+            var pipeline = CreatePipeline();
+            var operation = new AggregateOperation<BsonDocument>(_collectionNamespace, pipeline, BsonDocumentSerializer.Instance, _messageEncoderSettings)
+            {
+                Collation = _collation,
+                Hint = _hint,
+                MaxTime = _maxTime,
+                ReadConcern = _readConcern
+            };
+            return operation;
+        }
+
+        private List<BsonDocument> CreatePipeline()
+        {
+            var pipeline = new List<BsonDocument>();
+            pipeline.Add(new BsonDocument("$match", _filter ?? new BsonDocument()));
+            if (_skip.HasValue)
+            {
+                pipeline.Add(new BsonDocument("$skip", _skip.Value));
+            }
+            if (_limit.HasValue)
+            {
+                pipeline.Add(new BsonDocument("$limit", _limit.Value));
+            }
+            pipeline.Add(new BsonDocument("$group", new BsonDocument { { "_id", BsonNull.Value }, { "n", new BsonDocument("$sum", 1) } }));
+            return pipeline;
+        }
+
+        private long ExtractCountFromResult(List<BsonDocument> result)
+        {
+            switch (result.Count)
+            {
+                case 0:
+                    return 0;
+
+                case 1:
+                    return result[0]["n"].ToInt64();
+
+                default:
+                    throw new MongoClientException($"Expected aggregate command for CountDocuments to return 1 document, but got {result.Count}.");
+            }
+        }
+    }
+}

+ 32 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/DelayedEvaluationWriteConcernSerializer.cs

@@ -0,0 +1,32 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    internal class DelayedEvaluationWriteConcernSerializer : SealedClassSerializerBase<Func<WriteConcern>>
+    {
+        // private fields
+        protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, Func<WriteConcern> value)
+        {
+            var writeConcern = value();
+            var writeConcernDocument = writeConcern.ToBsonDocument();
+            BsonDocumentSerializer.Instance.Serialize(context, args, writeConcernDocument);
+        }
+    }
+}

+ 231 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/EndTransactionOperation.cs

@@ -0,0 +1,231 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// Abstract base class for AbortTransactionOperation and CommitTransactionOperation.
+    /// </summary>
+    public abstract class EndTransactionOperation : IReadOperation<BsonDocument>
+    {
+        // private fields
+        private MessageEncoderSettings _messageEncoderSettings;
+        private readonly WriteConcern _writeConcern;
+
+        // protected constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="EndTransactionOperation"/> class.
+        /// </summary>
+        /// <param name="writeConcern">The write concern.</param>
+        protected EndTransactionOperation(WriteConcern writeConcern)
+        {
+            _writeConcern = Ensure.IsNotNull(writeConcern, nameof(writeConcern));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets or sets the message encoder settings.
+        /// </summary>
+        /// <value>
+        /// The message encoder settings.
+        /// </value>
+        public MessageEncoderSettings MessageEncoderSettings
+        {
+            get { return _messageEncoderSettings; }
+            set { _messageEncoderSettings = value; }
+        }
+
+        /// <summary>
+        /// Gets the write concern.
+        /// </summary>
+        /// <value>
+        /// The write concern.
+        /// </value>
+        public WriteConcern WriteConcern => _writeConcern;
+
+        // protected properties
+        /// <summary>
+        /// Gets the name of the command.
+        /// </summary>
+        /// <value>
+        /// The name of the command.
+        /// </value>
+        protected abstract string CommandName { get; }
+
+        // public methods
+        /// <inheritdoc />
+        public virtual BsonDocument Execute(IReadBinding binding, CancellationToken cancellationToken)
+        {
+            Ensure.IsNotNull(binding, nameof(binding));
+
+            using (var channelSource = binding.GetReadChannelSource(cancellationToken))
+            using (var channel = channelSource.GetChannel(cancellationToken))
+            using (var channelBinding = new ChannelReadWriteBinding(channelSource.Server, channel, binding.Session.Fork()))
+            {
+                var operation = CreateOperation();
+                return operation.Execute(channelBinding, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual async Task<BsonDocument> ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken)
+        {
+            Ensure.IsNotNull(binding, nameof(binding));
+
+            using (var channelSource = await binding.GetReadChannelSourceAsync(cancellationToken).ConfigureAwait(false))
+            using (var channel = await channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false))
+            using (var channelBinding = new ChannelReadWriteBinding(channelSource.Server, channel, binding.Session.Fork()))
+            {
+                var operation = CreateOperation();
+                return await operation.ExecuteAsync(channelBinding, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        // private methods
+        private BsonDocument CreateCommand()
+        {
+            return new BsonDocument
+            {
+                { CommandName, 1 },
+                { "writeConcern", () => _writeConcern.ToBsonDocument(), !_writeConcern.IsServerDefault }
+            };
+        }
+
+        private IReadOperation<BsonDocument> CreateOperation()
+        {
+            var command = CreateCommand();
+            return new ReadCommandOperation<BsonDocument>(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, _messageEncoderSettings);
+        }
+    }
+
+    /// <summary>
+    /// The abort transaction operation.
+    /// </summary>
+    public sealed class AbortTransactionOperation : EndTransactionOperation
+    {
+        // public constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AbortTransactionOperation"/> class.
+        /// </summary>
+        /// <param name="writeConcern">The write concern.</param>
+        public AbortTransactionOperation(WriteConcern writeConcern)
+            : base(writeConcern)
+        {
+        }
+
+        // protected properties
+        /// <inheritdoc />
+        protected override string CommandName => "abortTransaction";
+    }
+
+    /// <summary>
+    /// The commit transaction operation.
+    /// </summary>
+    public sealed class CommitTransactionOperation : EndTransactionOperation
+    {
+        // public constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AbortTransactionOperation"/> class.
+        /// </summary>
+        /// <param name="writeConcern">The write concern.</param>
+        public CommitTransactionOperation(WriteConcern writeConcern)
+            : base(writeConcern)
+        {
+        }
+
+        // protected properties
+        /// <inheritdoc />
+        protected override string CommandName => "commitTransaction";
+
+        // public methods
+        /// <inheritdoc />
+        public override BsonDocument Execute(IReadBinding binding, CancellationToken cancellationToken)
+        {
+            try
+            {
+                return base.Execute(binding, cancellationToken);
+            }
+            catch (MongoException exception) when (ShouldReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(exception))
+            {
+                ReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(exception);
+                throw;
+            }
+        }
+
+        /// <inheritdoc />
+        public override async Task<BsonDocument> ExecuteAsync(IReadBinding binding, CancellationToken cancellationToken)
+        {
+            try
+            {
+                return await base.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+            }
+            catch (MongoException exception) when (ShouldReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(exception))
+            {
+                ReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(exception);
+                throw;
+            }
+        }
+
+        // private methods
+        private void ReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(MongoException exception)
+        {
+            exception.RemoveErrorLabel("TransientTransactionError");
+            exception.AddErrorLabel("UnknownTransactionCommitResult");
+        }
+
+        private bool ShouldReplaceTransientTransactionErrorWithUnknownTransactionCommitResult(MongoException exception)
+        {
+            if (exception is MongoConnectionException)
+            {
+                return true;
+            }
+
+            if (exception is MongoNotPrimaryException || exception is MongoNodeIsRecoveringException)
+            {
+                return true;
+            }
+
+            var writeConcernException = exception as MongoWriteConcernException;
+            if (writeConcernException != null)
+            {
+                var writeConcernError = writeConcernException.WriteConcernResult.Response?.GetValue("writeConcernError", null)?.AsBsonDocument;
+                if (writeConcernError != null)
+                {
+                    var code = (ServerErrorCode)writeConcernError.GetValue("code", -1).ToInt32();
+                    switch (code)
+                    {
+                        case ServerErrorCode.UnsatisfiableWriteConcern:
+                        case ServerErrorCode.UnknownReplWriteConcern:
+                            return false;
+
+                        default:
+                            return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+    }
+}

+ 41 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/IOperationClock.cs

@@ -0,0 +1,41 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// An operation clock.
+    /// </summary>
+    public interface IOperationClock
+    {
+        // properties
+        /// <summary>
+        /// Gets the operation time.
+        /// </summary>
+        /// <value>
+        /// The operation time.
+        /// </value>
+        BsonTimestamp OperationTime { get; }
+
+        // methods
+        /// <summary>
+        /// Advances the operation time.
+        /// </summary>
+        /// <param name="newOperationTime">The new operation time.</param>
+        void AdvanceOperationTime(BsonTimestamp newOperationTime);
+    }
+}

+ 70 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/IRetryableOperation.cs

@@ -0,0 +1,70 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// Represents an operation (that may or may not be retryable) that can be executed in a retryable write context.
+    /// </summary>
+    /// <typeparam name="TResult">The type of the result.</typeparam>
+    public interface IExecutableInRetryableWriteContext<TResult>
+    {
+        /// <summary>
+        /// Executes the first attempt.
+        /// </summary>
+        /// <param name="context">The context.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>The result.</returns>
+        TResult Execute(RetryableWriteContext context, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Executes the first attempt.
+        /// </summary>
+        /// <param name="context">The context.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>The result.</returns>
+        Task<TResult> ExecuteAsync(RetryableWriteContext context, CancellationToken cancellationToken);
+    }
+
+    /// <summary>
+    /// Represents a retryable operation.
+    /// </summary>
+    /// <typeparam name="TResult">The type of the result.</typeparam>
+    public interface IRetryableWriteOperation<TResult> : IExecutableInRetryableWriteContext<TResult>
+    {
+        /// <summary>
+        /// Executes the first attempt.
+        /// </summary>
+        /// <param name="context">The context.</param>
+        /// <param name="attempt">The attempt.</param>
+        /// <param name="transactionNumber">The transaction number.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>The result.</returns>
+        TResult ExecuteAttempt(RetryableWriteContext context, int attempt, long? transactionNumber, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Executes the first attempt.
+        /// </summary>
+        /// <param name="context">The context.</param>
+        /// <param name="attempt">The attempt.</param>
+        /// <param name="transactionNumber">The transaction number.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>The result.</returns>
+        Task<TResult> ExecuteAttemptAsync(RetryableWriteContext context, int attempt, long? transactionNumber, CancellationToken cancellationToken);
+    }
+}

+ 82 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/OperationClock.cs

@@ -0,0 +1,82 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// An operation clock.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Operations.IOperationClock" />
+    internal class OperationClock : IOperationClock
+    {
+        #region static
+        // public static methods
+        /// <summary>
+        /// Returns the greater of two operation times.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>The greater operation time.</returns>
+        public static BsonTimestamp GreaterOperationTime(BsonTimestamp x, BsonTimestamp y)
+        {
+            if (x == null)
+            {
+                return y;
+            }
+            else if (y == null)
+            {
+                return x;
+            }
+            else
+            {
+                return x > y ? x : y;
+            }
+        }
+        #endregion
+
+        // private fields
+        private BsonTimestamp _operationTime;
+
+        // public properties
+        /// <inheritdoc />
+        public BsonTimestamp OperationTime => _operationTime;
+
+        // public methods
+        /// <inheritdoc />
+        public void AdvanceOperationTime(BsonTimestamp newOperationTime)
+        {
+            Ensure.IsNotNull(newOperationTime, nameof(newOperationTime));
+            _operationTime = GreaterOperationTime(_operationTime, newOperationTime);
+        }
+    }
+
+    /// <summary>
+    /// An object that represents no operation clock.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.Operations.IOperationClock" />
+    public sealed class NoOperationClock : IOperationClock
+    {
+        /// <inheritdoc />
+        public BsonTimestamp OperationTime => null;
+
+        /// <inheritdoc />
+        public void AdvanceOperationTime(BsonTimestamp newOperationTime)
+        {
+        }
+    }
+}

+ 55 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/ReadConcernHelper.cs

@@ -0,0 +1,55 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Connections;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    internal static class ReadConcernHelper
+    {
+        public static BsonDocument GetReadConcernForCommand(ICoreSession session, ConnectionDescription connectionDescription, ReadConcern readConcern)
+        {
+            return session.IsInTransaction ? null : ToBsonDocument(session, connectionDescription, readConcern);
+        }
+
+        public static BsonDocument GetReadConcernForFirstCommandInTransaction(ICoreSession session, ConnectionDescription connectionDescription)
+        {
+            var readConcern = session.CurrentTransaction.TransactionOptions.ReadConcern;
+            return ToBsonDocument(session, connectionDescription, readConcern);
+        }
+
+        // private static methods
+        private static BsonDocument ToBsonDocument(ICoreSession session, ConnectionDescription connectionDescription, ReadConcern readConcern)
+        {
+            var sessionsAreSupported = connectionDescription.IsMasterResult.LogicalSessionTimeout != null;
+            var shouldSendAfterClusterTime = sessionsAreSupported && session.IsCausallyConsistent && session.OperationTime != null;
+            var shouldSendReadConcern = !readConcern.IsServerDefault || shouldSendAfterClusterTime;
+
+            if (shouldSendReadConcern)
+            {
+                var readConcernDocument = readConcern.ToBsonDocument();
+                if (shouldSendAfterClusterTime)
+                {
+                    readConcernDocument.Add("afterClusterTime", session.OperationTime);
+                }
+                return readConcernDocument;
+            }
+
+            return null;
+        }
+    }
+}

+ 136 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryabilityHelper.cs

@@ -0,0 +1,136 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    internal static class RetryabilityHelper
+    {
+        // private static fields
+        private static readonly HashSet<ServerErrorCode> __notResumableChangeStreamErrorCodes;
+        private static readonly HashSet<Type> __resumableChangeStreamExceptions;
+        private static readonly HashSet<Type> __retryableWriteExceptions;
+        private static readonly HashSet<ServerErrorCode> __retryableWriteErrorCodes;
+
+        // static constructor
+        static RetryabilityHelper()
+        {
+            var resumableAndRetryableExceptions = new HashSet<Type>()
+            {
+                typeof(MongoConnectionException),
+                typeof(MongoNotPrimaryException),
+                typeof(MongoNodeIsRecoveringException)
+            };
+
+            __resumableChangeStreamExceptions = new HashSet<Type>(resumableAndRetryableExceptions)
+            {
+                typeof(MongoCursorNotFoundException)
+            };
+
+            __retryableWriteExceptions = new HashSet<Type>(resumableAndRetryableExceptions)
+            {
+            };
+
+            var resumableAndRetryableErrorCodes = new HashSet<ServerErrorCode>
+            {
+                ServerErrorCode.HostNotFound,
+                ServerErrorCode.HostUnreachable,
+                ServerErrorCode.NetworkTimeout,
+                ServerErrorCode.SocketException
+            };
+
+            __retryableWriteErrorCodes = new HashSet<ServerErrorCode>(resumableAndRetryableErrorCodes)
+            {
+                ServerErrorCode.WriteConcernFailed
+            };
+
+            __notResumableChangeStreamErrorCodes = new HashSet<ServerErrorCode>()
+            {
+                ServerErrorCode.CappedPositionLost,
+                ServerErrorCode.CursorKilled,
+                ServerErrorCode.Interrupted
+            };
+        }
+
+        // public static methods
+        public static bool IsResumableChangeStreamException(Exception exception)
+        {
+            var commandException = exception as MongoCommandException;
+            if (commandException != null)
+            {
+                var code = (ServerErrorCode)commandException.Code;
+                return !__notResumableChangeStreamErrorCodes.Contains(code);
+            }
+            else
+            {
+                return __resumableChangeStreamExceptions.Contains(exception.GetType());
+            }
+        }
+
+        public static bool IsRetryableWriteException(Exception exception)
+        {
+            if (__retryableWriteExceptions.Contains(exception.GetType()))
+            {
+                return true;
+            }
+
+            var commandException = exception as MongoCommandException;
+            if (commandException != null)
+            {
+                var code = (ServerErrorCode)commandException.Code;
+                if (__retryableWriteErrorCodes.Contains(code))
+                {
+                    return true;
+                }
+            }
+
+            var writeConcernException = exception as MongoWriteConcernException;
+            if (writeConcernException != null)
+            {
+                var writeConcernError = writeConcernException.WriteConcernResult.Response.GetValue("writeConcernError", null)?.AsBsonDocument;
+                if (writeConcernError != null)
+                {
+                    var code = (ServerErrorCode)writeConcernError.GetValue("code", -1).AsInt32;
+                    switch (code)
+                    {
+                        case ServerErrorCode.InterruptedAtShutdown:
+                        case ServerErrorCode.InterruptedDueToReplStateChange:
+                        case ServerErrorCode.NotMaster:
+                        case ServerErrorCode.NotMasterNoSlaveOk:
+                        case ServerErrorCode.NotMasterOrSecondary:
+                        case ServerErrorCode.PrimarySteppedDown:
+                        case ServerErrorCode.ShutdownInProgress:
+                        case ServerErrorCode.HostNotFound:
+                        case ServerErrorCode.HostUnreachable:
+                        case ServerErrorCode.NetworkTimeout:
+                        case ServerErrorCode.SocketException:
+                            return true;
+                    }
+
+                    var message = writeConcernError.GetValue("errmsg", null)?.AsString;
+                    if (message.IndexOf("not master", StringComparison.OrdinalIgnoreCase) != -1 ||
+                        message.IndexOf("node is recovering", StringComparison.OrdinalIgnoreCase) != -1)
+                    {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+    }
+}

+ 142 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableDeleteCommandOperation.cs

@@ -0,0 +1,142 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Connections;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.WireProtocol.Messages;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// Represents a delete command operation.
+    /// </summary>
+    public class RetryableDeleteCommandOperation : RetryableWriteCommandOperationBase
+    {
+        // private fields
+        private readonly CollectionNamespace _collectionNamespace;
+        private readonly BatchableSource<DeleteRequest> _deletes;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RetryableDeleteCommandOperation" /> class.
+        /// </summary>
+        /// <param name="collectionNamespace">The collection namespace.</param>
+        /// <param name="deletes">The deletes.</param>
+        /// <param name="messageEncoderSettings">The message encoder settings.</param>
+        public RetryableDeleteCommandOperation(
+            CollectionNamespace collectionNamespace,
+            BatchableSource<DeleteRequest> deletes,
+            MessageEncoderSettings messageEncoderSettings)
+            : base(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, messageEncoderSettings)
+        {
+            _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace));
+            _deletes = Ensure.IsNotNull(deletes, nameof(deletes));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the collection namespace.
+        /// </summary>
+        /// <value>
+        /// The collection namespace.
+        /// </value>
+        public CollectionNamespace CollectionNamespace
+        {
+            get { return _collectionNamespace; }
+        }
+
+        /// <summary>
+        /// Gets the deletes.
+        /// </summary>
+        /// <value>
+        /// The deletes.
+        /// </value>
+        public BatchableSource<DeleteRequest> Deletes
+        {
+            get { return _deletes; }
+        }
+
+        // protected methods
+        /// <inheritdoc />
+        protected override BsonDocument CreateCommand(ICoreSessionHandle session, ConnectionDescription connectionDescription, int attempt, long? transactionNumber)
+        {
+            if (!Feature.Collation.IsSupported(connectionDescription.ServerVersion))
+            {
+                if (_deletes.Items.Skip(_deletes.Offset).Take(_deletes.Count).Any(d => d.Collation != null))
+                {
+                    throw new NotSupportedException($"Server version {connectionDescription.ServerVersion} does not support collations.");
+                }
+            }
+
+            var writeConcern = WriteConcernHelper.GetWriteConcernForWriteCommand(session, WriteConcern);
+            return new BsonDocument
+            {
+                { "delete", _collectionNamespace.CollectionName },
+                { "ordered", IsOrdered },
+                { "writeConcern", writeConcern, writeConcern != null },
+                { "txnNumber", () => transactionNumber.Value, transactionNumber.HasValue }
+            };
+        }
+
+        /// <inheritdoc />
+        protected override IEnumerable<Type1CommandMessageSection> CreateCommandPayloads(IChannelHandle channel, int attempt)
+        {
+            BatchableSource<DeleteRequest> deletes;
+            if (attempt == 1)
+            {
+                deletes = _deletes;
+            }
+            else
+            {
+                deletes = new BatchableSource<DeleteRequest>(_deletes.Items, _deletes.Offset, _deletes.ProcessedCount, canBeSplit: false);
+            }
+            var maxBatchCount = Math.Min(MaxBatchCount ?? int.MaxValue, channel.ConnectionDescription.MaxBatchCount);
+            var maxDocumentSize = channel.ConnectionDescription.MaxWireDocumentSize;
+            var payload = new Type1CommandMessageSection<DeleteRequest>("deletes", deletes, DeleteRequestSerializer.Instance, NoOpElementNameValidator.Instance, maxBatchCount, maxDocumentSize);
+            return new Type1CommandMessageSection[] { payload };
+        }
+
+        // nested types
+        private class DeleteRequestSerializer : SealedClassSerializerBase<DeleteRequest>
+        {
+            public static readonly IBsonSerializer<DeleteRequest> Instance = new DeleteRequestSerializer();
+
+            protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, DeleteRequest value)
+            {
+                var writer = context.Writer;
+                writer.WriteStartDocument();
+                writer.WriteName("q");
+                BsonDocumentSerializer.Instance.Serialize(context, value.Filter);
+                writer.WriteName("limit");
+                writer.WriteInt32(value.Limit);
+                if (value.Collation != null)
+                {
+                    writer.WriteName("collation");
+                    BsonDocumentSerializer.Instance.Serialize(context, value.Collation.ToBsonDocument());
+                }
+                writer.WriteEndDocument();
+            }
+        }
+    }
+}

+ 181 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableInsertCommandOperation.cs

@@ -0,0 +1,181 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Connections;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.Operations.ElementNameValidators;
+using MongoDB.Driver.Core.WireProtocol.Messages;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// Represents an insert command operation.
+    /// </summary>
+    /// <typeparam name="TDocument">The type of the document.</typeparam>
+    public class RetryableInsertCommandOperation<TDocument> : RetryableWriteCommandOperationBase where TDocument : class
+    {
+        // private fields
+        private bool? _bypassDocumentValidation;
+        private readonly CollectionNamespace _collectionNamespace;
+        private readonly BatchableSource<TDocument> _documents;
+        private readonly IBsonSerializer<TDocument> _documentSerializer;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RetryableInsertCommandOperation{TDocument}"/> class.
+        /// </summary>
+        /// <param name="collectionNamespace">The collection namespace.</param>
+        /// <param name="documents">The documents.</param>
+        /// <param name="documentSerializer">The document serializer.</param>
+        /// <param name="messageEncoderSettings">The message encoder settings.</param>
+        public RetryableInsertCommandOperation(
+            CollectionNamespace collectionNamespace,
+            BatchableSource<TDocument> documents,
+            IBsonSerializer<TDocument> documentSerializer,
+            MessageEncoderSettings messageEncoderSettings)
+            : base(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, messageEncoderSettings)
+        {
+            _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace));
+            _documents = Ensure.IsNotNull(documents, nameof(documents));
+            _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets or sets a value indicating whether to bypass document validation.
+        /// </summary>
+        /// <value>
+        /// A value indicating whether to bypass document validation.
+        /// </value>
+        public bool? BypassDocumentValidation
+        {
+            get { return _bypassDocumentValidation; }
+            set { _bypassDocumentValidation = value; }
+        }
+
+        /// <summary>
+        /// Gets the collection namespace.
+        /// </summary>
+        /// <value>
+        /// The collection namespace.
+        /// </value>
+        public CollectionNamespace CollectionNamespace
+        {
+            get { return _collectionNamespace; }
+        }
+
+        /// <summary>
+        /// Gets the documents.
+        /// </summary>
+        /// <value>
+        /// The documents.
+        /// </value>
+        public BatchableSource<TDocument> Documents
+        {
+            get { return _documents; }
+        }
+
+        /// <summary>
+        /// Gets the document serializer.
+        /// </summary>
+        /// <value>
+        /// The document serializer.
+        /// </value>
+        public IBsonSerializer<TDocument> DocumentSerializer
+        {
+            get { return _documentSerializer; }
+        }
+
+        // protected methods
+        /// <inheritdoc />
+        protected override BsonDocument CreateCommand(ICoreSessionHandle session, ConnectionDescription connectionDescription, int attempt, long? transactionNumber)
+        {
+            var writeConcern = WriteConcernHelper.GetWriteConcernForWriteCommand(session, WriteConcern);
+            return new BsonDocument
+            {
+                { "insert", _collectionNamespace.CollectionName },
+                { "ordered", IsOrdered },
+                { "bypassDocumentValidation", () => _bypassDocumentValidation, _bypassDocumentValidation.HasValue },
+                { "writeConcern", writeConcern, writeConcern != null },
+                { "txnNumber", () => transactionNumber.Value, transactionNumber.HasValue }
+            };
+        }
+
+        /// <inheritdoc />
+        protected override IEnumerable<Type1CommandMessageSection> CreateCommandPayloads(IChannelHandle channel, int attempt)
+        {
+            BatchableSource<TDocument> documents;
+            if (attempt == 1)
+            {
+                documents = _documents;
+            }
+            else
+            {
+                documents = new BatchableSource<TDocument>(_documents.Items, _documents.Offset, _documents.ProcessedCount, canBeSplit: false);
+            }
+            var isSystemIndexesCollection = _collectionNamespace.Equals(CollectionNamespace.DatabaseNamespace.SystemIndexesCollection);
+            var elementNameValidator = isSystemIndexesCollection ? (IElementNameValidator)NoOpElementNameValidator.Instance : CollectionElementNameValidator.Instance;
+            var maxBatchCount = Math.Min(MaxBatchCount ?? int.MaxValue, channel.ConnectionDescription.MaxBatchCount);
+            var maxDocumentSize = channel.ConnectionDescription.MaxDocumentSize;
+            var payload = new Type1CommandMessageSection<TDocument>("documents", documents, _documentSerializer, elementNameValidator, maxBatchCount, maxDocumentSize);
+            return new Type1CommandMessageSection[] { payload };
+        }
+
+        // nested types
+        private class InsertSerializer : SerializerBase<TDocument>
+        {
+            // private fields
+            private IBsonSerializer _cachedSerializer;
+            private readonly IBsonSerializer<TDocument> _documentSerializer;
+
+            // constructors
+            public InsertSerializer(IBsonSerializer<TDocument> documentSerializer)
+            {
+                _documentSerializer = documentSerializer;
+                _cachedSerializer = documentSerializer;
+            }
+
+            // public methods
+            public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TDocument value)
+            {
+                IBsonSerializer serializer;
+
+                var actualType = value.GetType();
+                if (actualType == typeof(TDocument))
+                {
+                    serializer = _documentSerializer;
+                }
+                else
+                {
+                    if (_cachedSerializer.ValueType != actualType)
+                    {
+                        _cachedSerializer = BsonSerializer.LookupSerializer(actualType);
+                    }
+                    serializer = _cachedSerializer;
+                }
+
+                serializer.Serialize(context, value);
+            }
+        }
+    }
+}

+ 203 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableUpdateCommandOperation.cs

@@ -0,0 +1,203 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Connections;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.Operations.ElementNameValidators;
+using MongoDB.Driver.Core.WireProtocol.Messages;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// Represents an update command operation.
+    /// </summary>
+    public class RetryableUpdateCommandOperation : RetryableWriteCommandOperationBase
+    {
+        // private fields
+        private bool? _bypassDocumentValidation;
+        private readonly CollectionNamespace _collectionNamespace;
+        private readonly BatchableSource<UpdateRequest> _updates;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RetryableUpdateCommandOperation" /> class.
+        /// </summary>
+        /// <param name="collectionNamespace">The collection namespace.</param>
+        /// <param name="updates">The updates.</param>
+        /// <param name="messageEncoderSettings">The message encoder settings.</param>
+        public RetryableUpdateCommandOperation(
+            CollectionNamespace collectionNamespace,
+            BatchableSource<UpdateRequest> updates,
+            MessageEncoderSettings messageEncoderSettings)
+            : base(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, messageEncoderSettings)
+        {
+            _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace));
+            _updates = Ensure.IsNotNull(updates, nameof(updates));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets or sets a value indicating whether to bypass document validation.
+        /// </summary>
+        /// <value>A value indicating whether to bypass document validation.</value>
+        public bool? BypassDocumentValidation
+        {
+            get { return _bypassDocumentValidation; }
+            set { _bypassDocumentValidation = value; }
+        }
+
+        /// <summary>
+        /// Gets the collection namespace.
+        /// </summary>
+        /// <value>
+        /// The collection namespace.
+        /// </value>
+        public CollectionNamespace CollectionNamespace
+        {
+            get { return _collectionNamespace; }
+        }
+
+        /// <summary>
+        /// Gets the updates.
+        /// </summary>
+        /// <value>
+        /// The updates.
+        /// </value>
+        public BatchableSource<UpdateRequest> Updates
+        {
+            get { return _updates; }
+        }
+
+        // protected methods
+        /// <inheritdoc />
+        protected override BsonDocument CreateCommand(ICoreSessionHandle session, ConnectionDescription connectionDescription, int attempt, long? transactionNumber)
+        {
+            var serverVersion = connectionDescription.ServerVersion;
+            if (!Feature.Collation.IsSupported(serverVersion))
+            {
+                if (_updates.Items.Skip(_updates.Offset).Take(_updates.Count).Any(u => u.Collation != null))
+                {
+                    throw new NotSupportedException($"Server version {serverVersion} does not support collations.");
+                }
+            }
+            if (!Feature.ArrayFilters.IsSupported(serverVersion))
+            {
+                if (_updates.Items.Skip(_updates.Offset).Take(_updates.Count).Any(u => u.ArrayFilters != null))
+                {
+                    throw new NotSupportedException($"Server version {serverVersion} does not support arrayFilters.");
+                }
+            }
+
+            var writeConcern = WriteConcernHelper.GetWriteConcernForWriteCommand(session, WriteConcern);
+            return new BsonDocument
+            {
+                { "update", _collectionNamespace.CollectionName },
+                { "ordered", IsOrdered },
+                { "bypassDocumentValidation", () => _bypassDocumentValidation.Value, _bypassDocumentValidation.HasValue },
+                { "writeConcern", writeConcern, writeConcern != null },
+                { "txnNumber", () => transactionNumber.Value, transactionNumber.HasValue }
+            };
+        }
+
+        /// <inheritdoc />
+        protected override IEnumerable<Type1CommandMessageSection> CreateCommandPayloads(IChannelHandle channel, int attempt)
+        {
+            BatchableSource<UpdateRequest> updates;
+            if (attempt == 1)
+            {
+                updates = _updates;
+            }
+            else
+            {
+                updates = new BatchableSource<UpdateRequest>(_updates.Items, _updates.Offset, _updates.ProcessedCount, canBeSplit: false);
+            }
+            var maxBatchCount = Math.Min(MaxBatchCount ?? int.MaxValue, channel.ConnectionDescription.MaxBatchCount);
+            var maxDocumentSize = channel.ConnectionDescription.MaxWireDocumentSize;
+            var payload = new Type1CommandMessageSection<UpdateRequest>("updates", _updates, UpdateRequestSerializer.Instance, NoOpElementNameValidator.Instance, maxBatchCount, maxDocumentSize);
+            return new Type1CommandMessageSection[] { payload };
+        }
+
+        // nested types
+        private class UpdateRequestSerializer : SealedClassSerializerBase<UpdateRequest>
+        {
+            public static readonly IBsonSerializer<UpdateRequest> Instance = new UpdateRequestSerializer();
+
+            protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, UpdateRequest value)
+            {
+                var writer = context.Writer;
+                writer.WriteStartDocument();
+                writer.WriteName("q");
+                BsonDocumentSerializer.Instance.Serialize(context, value.Filter);
+                writer.WriteName("u");
+                SerializeUpdate(context, args, value);
+                if (value.IsMulti)
+                {
+                    writer.WriteName("multi");
+                    writer.WriteBoolean(value.IsMulti);
+                }
+                if (value.IsUpsert)
+                {
+                    writer.WriteName("upsert");
+                    writer.WriteBoolean(value.IsUpsert);
+                }
+                if (value.Collation != null)
+                {
+                    writer.WriteName("collation");
+                    BsonDocumentSerializer.Instance.Serialize(context, value.Collation.ToBsonDocument());
+                }
+                if (value.ArrayFilters != null)
+                {
+                    writer.WriteName("arrayFilters");
+                    writer.WriteStartArray();
+                    foreach (var arrayFilter in value.ArrayFilters)
+                    {
+                        BsonDocumentSerializer.Instance.Serialize(context, arrayFilter);
+                    }
+                    writer.WriteEndArray();
+                }
+                writer.WriteEndDocument();
+            }
+
+            // private methods
+            private void SerializeUpdate(BsonSerializationContext context, BsonSerializationArgs args, UpdateRequest request)
+            {
+                var writer = context.Writer;
+                writer.PushElementNameValidator(ElementNameValidatorFactory.ForUpdateType(request.UpdateType));
+                try
+                {
+                    var position = writer.Position;
+                    BsonDocumentSerializer.Instance.Serialize(context, request.Update);
+                    if (request.UpdateType == UpdateType.Update && writer.Position == position + 8)
+                    {
+                        throw new BsonSerializationException("Update documents cannot be empty.");
+                    }
+                }
+                finally
+                {
+                    writer.PopElementNameValidator();
+                }
+            }
+        }
+    }
+}

+ 276 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableWriteCommandOperationBase.cs

@@ -0,0 +1,276 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Connections;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.WireProtocol;
+using MongoDB.Driver.Core.WireProtocol.Messages;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// Represents a base class for a delete, insert or update command operation.
+    /// </summary>
+    public abstract class RetryableWriteCommandOperationBase : IWriteOperation<BsonDocument>, IRetryableWriteOperation<BsonDocument>
+    {
+        // private fields
+        private readonly DatabaseNamespace _databaseNamespace;
+        private bool _isOrdered = true;
+        private int? _maxBatchCount;
+        private readonly MessageEncoderSettings _messageEncoderSettings;
+        private bool _retryRequested;
+        private WriteConcern _writeConcern = WriteConcern.Acknowledged;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RetryableWriteCommandOperationBase" /> class.
+        /// </summary>
+        /// <param name="databaseNamespace">The database namespace.</param>
+        /// <param name="messageEncoderSettings">The message encoder settings.</param>
+        public RetryableWriteCommandOperationBase(
+            DatabaseNamespace databaseNamespace,
+            MessageEncoderSettings messageEncoderSettings)
+        {
+            _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace));
+            _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the database namespace.
+        /// </summary>
+        /// <value>
+        /// The database namespace.
+        /// </value>
+        public DatabaseNamespace DatabaseNamespace
+        {
+            get { return _databaseNamespace; }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the server should process the requests in order.
+        /// </summary>
+        /// <value>A value indicating whether the server should process the requests in order.</value>
+        public bool IsOrdered
+        {
+            get { return _isOrdered; }
+            set { _isOrdered = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the maximum batch count.
+        /// </summary>
+        /// <value>
+        /// The maximum batch count.
+        /// </value>
+        public int? MaxBatchCount
+        {
+            get { return _maxBatchCount; }
+            set { _maxBatchCount = Ensure.IsNullOrGreaterThanZero(value, nameof(value)); }
+        }
+
+        /// <summary>
+        /// Gets the message encoder settings.
+        /// </summary>
+        /// <value>
+        /// The message encoder settings.
+        /// </value>
+        public MessageEncoderSettings MessageEncoderSettings
+        {
+            get { return _messageEncoderSettings; }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether retry is enabled for the operation.
+        /// </summary>
+        /// <value>A value indicating whether retry is enabled.</value>
+        public bool RetryRequested
+        {
+            get { return _retryRequested; }
+            set { _retryRequested = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the write concern.
+        /// </summary>
+        /// <value>
+        /// The write concern.
+        /// </value>
+        public WriteConcern WriteConcern
+        {
+            get { return _writeConcern; }
+            set { _writeConcern = value; }
+        }
+
+        // public methods
+        /// <inheritdoc />
+        public virtual BsonDocument Execute(IWriteBinding binding, CancellationToken cancellationToken)
+        {
+            using (var context = RetryableWriteContext.Create(binding, _retryRequested, cancellationToken))
+            {
+                return Execute(context, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual BsonDocument Execute(RetryableWriteContext context, CancellationToken cancellationToken)
+        {
+            return RetryableWriteOperationExecutor.Execute(this, context, cancellationToken);
+        }
+
+        /// <inheritdoc />
+        public virtual async Task<BsonDocument> ExecuteAsync(IWriteBinding binding, CancellationToken cancellationToken)
+        {
+            using (var context = await RetryableWriteContext.CreateAsync(binding, _retryRequested, cancellationToken).ConfigureAwait(false))
+            {
+                return Execute(context, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public virtual Task<BsonDocument> ExecuteAsync(RetryableWriteContext context, CancellationToken cancellationToken)
+        {
+            return RetryableWriteOperationExecutor.ExecuteAsync(this, context, cancellationToken);
+        }
+
+        /// <inheritdoc />
+        public BsonDocument ExecuteAttempt(RetryableWriteContext context, int attempt, long? transactionNumber, CancellationToken cancellationToken)
+        {
+            var args = GetCommandArgs(context, attempt, transactionNumber);
+
+            return context.Channel.Command<BsonDocument>(
+                context.ChannelSource.Session,
+                ReadPreference.Primary,
+                _databaseNamespace,
+                args.Command,
+                args.CommandPayloads,
+                NoOpElementNameValidator.Instance,
+                null, // additionalOptions,
+                args.PostWriteAction,
+                args.ResponseHandling,
+                BsonDocumentSerializer.Instance,
+                args.MessageEncoderSettings,
+                cancellationToken);
+        }
+
+        /// <inheritdoc />
+        public Task<BsonDocument> ExecuteAttemptAsync(RetryableWriteContext context, int attempt, long? transactionNumber, CancellationToken cancellationToken)
+        {
+            var args = GetCommandArgs(context, attempt, transactionNumber);
+
+            return context.Channel.CommandAsync<BsonDocument>(
+                context.ChannelSource.Session,
+                ReadPreference.Primary,
+                _databaseNamespace,
+                args.Command,
+                args.CommandPayloads,
+                NoOpElementNameValidator.Instance,
+                null, // additionalOptions,
+                args.PostWriteAction,
+                args.ResponseHandling,
+                BsonDocumentSerializer.Instance,
+                args.MessageEncoderSettings,
+                cancellationToken);
+        }
+
+        // protected methods
+        /// <summary>
+        /// Creates the command.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <param name="connectionDescription">The connection description.</param>
+        /// <param name="attempt">The attempt.</param>
+        /// <param name="transactionNumber">The transaction number.</param>
+        /// <returns>
+        /// A command.
+        /// </returns>
+        protected abstract BsonDocument CreateCommand(ICoreSessionHandle session, ConnectionDescription connectionDescription, int attempt, long? transactionNumber);
+
+        /// <summary>
+        /// Creates the command payloads.
+        /// </summary>
+        /// <param name="channel">The channel.</param>
+        /// <param name="attempt">The attempt.</param>
+        /// <returns>
+        /// The command payloads.
+        /// </returns>
+        protected abstract IEnumerable<Type1CommandMessageSection> CreateCommandPayloads(IChannelHandle channel, int attempt);
+
+        // private methods
+        private MessageEncoderSettings CreateMessageEncoderSettings(IChannelHandle channel)
+        {
+            var clone = _messageEncoderSettings.Clone();
+            clone.Add(MessageEncoderSettingsName.MaxDocumentSize, channel.ConnectionDescription.MaxDocumentSize);
+            clone.Add(MessageEncoderSettingsName.MaxMessageSize, channel.ConnectionDescription.MaxMessageSize);
+            clone.Add(MessageEncoderSettingsName.MaxWireDocumentSize, channel.ConnectionDescription.MaxWireDocumentSize);
+            return clone;
+        }
+
+        private CommandArgs GetCommandArgs(RetryableWriteContext context, int attempt, long? transactionNumber)
+        {
+            var args = new CommandArgs();
+            args.Command = CreateCommand(context.Binding.Session, context.Channel.ConnectionDescription, attempt, transactionNumber);
+            args.CommandPayloads = CreateCommandPayloads(context.Channel, attempt).ToList();
+            args.PostWriteAction = GetPostWriteAction(args.CommandPayloads);
+            args.ResponseHandling = GetResponseHandling();
+            args.MessageEncoderSettings = CreateMessageEncoderSettings(context.Channel);
+            return args;
+        }
+
+        private Action<IMessageEncoderPostProcessor> GetPostWriteAction(List<Type1CommandMessageSection> commandPayloads)
+        {
+            if (!_writeConcern.IsAcknowledged && _isOrdered)
+            {
+                return encoder =>
+                {
+                    var requestsPayload = commandPayloads.Single();
+                    if (!requestsPayload.Documents.AllItemsWereProcessed)
+                    {
+                        encoder.ChangeWriteConcernFromW0ToW1();
+                    }
+                };
+            }
+            else
+            {
+                return null;
+            }
+        }
+
+        private CommandResponseHandling GetResponseHandling()
+        {
+            return _writeConcern.IsAcknowledged ? CommandResponseHandling.Return : CommandResponseHandling.NoResponseExpected;
+        }
+
+        // nested types
+        private class CommandArgs
+        {
+            public BsonDocument Command { get; set; }
+            public List<Type1CommandMessageSection> CommandPayloads { get; set; }
+            public Action<IMessageEncoderPostProcessor> PostWriteAction { get; set; }
+            public CommandResponseHandling ResponseHandling { get; set; }
+            public MessageEncoderSettings MessageEncoderSettings { get; set; }
+        }
+    }
+}

+ 195 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableWriteContext.cs

@@ -0,0 +1,195 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    /// <summary>
+    /// Represents a context for retryable writes.
+    /// </summary>
+    /// <seealso cref="System.IDisposable" />
+    public sealed class RetryableWriteContext : IDisposable
+    {
+        #region static
+        // public static methods
+        /// <summary>
+        /// Creates and initializes a retryable write operation context.
+        /// </summary>
+        /// <param name="binding">The binding.</param>
+        /// <param name="retryRequested">if set to <c>true</c> [retry requested].</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A retryable write context.</returns>
+        public static RetryableWriteContext Create(IWriteBinding binding, bool retryRequested, CancellationToken cancellationToken)
+        {
+            var context = new RetryableWriteContext(binding, retryRequested);
+            try
+            {
+                context.Initialize(cancellationToken);
+                return context;
+            }
+            catch
+            {
+                context.Dispose();
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// Creates and initializes a retryable write operation context.
+        /// </summary>
+        /// <param name="binding">The binding.</param>
+        /// <param name="retryRequested">if set to <c>true</c> [retry requested].</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A retryable write context.</returns>
+        public static async Task<RetryableWriteContext> CreateAsync(IWriteBinding binding, bool retryRequested, CancellationToken cancellationToken)
+        {
+            var context = new RetryableWriteContext(binding, retryRequested);
+            try
+            {
+                await context.InitializeAsync(cancellationToken).ConfigureAwait(false);
+                return context;
+            }
+            catch
+            {
+                context.Dispose();
+                throw;
+            }
+        }
+        #endregion
+
+        // private fields
+        private readonly IWriteBinding _binding;
+        private IChannelHandle _channel;
+        private IChannelSourceHandle _channelSource;
+        private bool _disposed;
+        private bool _retryRequested;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RetryableWriteContext"/> class.
+        /// </summary>
+        /// <param name="binding">The binding.</param>
+        /// <param name="retryRequested">if set to <c>true</c> the operation can be retried.</param>
+        public RetryableWriteContext(IWriteBinding binding, bool retryRequested)
+        {
+            _binding = Ensure.IsNotNull(binding, nameof(binding));
+            _retryRequested = retryRequested;
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the binding.
+        /// </summary>
+        /// <value>
+        /// The binding.
+        /// </value>
+        public IWriteBinding Binding => _binding;
+
+        /// <summary>
+        /// Gets the channel.
+        /// </summary>
+        /// <value>
+        /// The channel.
+        /// </value>
+        public IChannelHandle Channel => _channel;
+
+        /// <summary>
+        /// Gets the channel source.
+        /// </summary>
+        /// <value>
+        /// The channel source.
+        /// </value>
+        public IChannelSourceHandle ChannelSource => _channelSource;
+
+        /// <summary>
+        /// Gets a value indicating whether the operation can be retried.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if the operation can be retried; otherwise, <c>false</c>.
+        /// </value>
+        public bool RetryRequested => _retryRequested;
+
+        // public methods
+        /// <summary>
+        /// Disables retries.
+        /// </summary>
+        /// <param name="requests">The requests.</param>
+        public void DisableRetriesIfAnyWriteRequestIsNotRetryable(IEnumerable<WriteRequest> requests)
+        {
+            if (_retryRequested)
+            {
+                if (requests.Any(r => !r.IsRetryable(_channel.ConnectionDescription)))
+                {
+                    _retryRequested = false;
+                }
+            }
+        }
+
+        /// <inheritdoc />
+        public void Dispose()
+        {
+            if (!_disposed)
+            {
+                _channelSource?.Dispose();
+                _channel?.Dispose();
+                _disposed = true;
+            }
+        }
+
+        /// <summary>
+        /// Replaces the channel.
+        /// </summary>
+        /// <param name="channel">The channel.</param>
+        public void ReplaceChannel(IChannelHandle channel)
+        {
+            Ensure.IsNotNull(channel, nameof(channel));
+            _channel?.Dispose();
+            _channel = channel;
+        }
+
+        /// <summary>
+        /// Replaces the channel source.
+        /// </summary>
+        /// <param name="channelSource">The channel source.</param>
+        public void ReplaceChannelSource(IChannelSourceHandle channelSource)
+        {
+            Ensure.IsNotNull(channelSource, nameof(channelSource));
+            _channelSource?.Dispose();
+            _channel?.Dispose();
+            _channelSource = channelSource;
+            _channel = null;
+        }
+
+        // private methods
+        private void Initialize(CancellationToken cancellationToken)
+        {
+            _channelSource = _binding.GetWriteChannelSource(cancellationToken);
+            _channel = _channelSource.GetChannel(cancellationToken);
+        }
+
+        private async Task InitializeAsync(CancellationToken cancellationToken)
+        {
+            _channelSource = await _binding.GetWriteChannelSourceAsync(cancellationToken).ConfigureAwait(false);
+            _channel = await _channelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false);
+        }
+    }
+}

+ 143 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/RetryableWriteOperationExecutor.cs

@@ -0,0 +1,143 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Connections;
+using MongoDB.Driver.Core.Servers;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    internal static class RetryableWriteOperationExecutor
+    {
+        // public static methods
+        public static TResult Execute<TResult>(IRetryableWriteOperation<TResult> operation, IWriteBinding binding, bool retryRequested, CancellationToken cancellationToken)
+        {
+            using (var context = RetryableWriteContext.Create(binding, retryRequested, cancellationToken))
+            {
+                return Execute(operation, context, cancellationToken);
+            }
+        }
+
+        public static TResult Execute<TResult>(IRetryableWriteOperation<TResult> operation, RetryableWriteContext context, CancellationToken cancellationToken)
+        {
+            if (!context.RetryRequested || !AreRetryableWritesSupported(context.Channel.ConnectionDescription) || context.Binding.Session.IsInTransaction)
+            {
+                return operation.ExecuteAttempt(context, 1, null, cancellationToken);
+            }
+
+            var transactionNumber = context.Binding.Session.AdvanceTransactionNumber();
+            Exception originalException;
+            try
+            {
+                return operation.ExecuteAttempt(context, 1, transactionNumber, cancellationToken);
+            }
+            catch (Exception ex) when (RetryabilityHelper.IsRetryableWriteException(ex))
+            {
+                originalException = ex;
+            }
+
+            try
+            {
+                context.ReplaceChannelSource(context.Binding.GetWriteChannelSource(cancellationToken));
+                context.ReplaceChannel(context.ChannelSource.GetChannel(cancellationToken));
+            }
+            catch
+            {
+                throw originalException;
+            }
+
+            if (!AreRetryableWritesSupported(context.Channel.ConnectionDescription))
+            {
+                throw originalException;
+            }
+
+            try
+            {
+                return operation.ExecuteAttempt(context, 2, transactionNumber, cancellationToken);
+            }
+            catch (Exception ex) when (ShouldThrowOriginalException(ex))
+            {
+                throw originalException;
+            }
+        }
+
+        public async static Task<TResult> ExecuteAsync<TResult>(IRetryableWriteOperation<TResult> operation, IWriteBinding binding, bool retryRequested, CancellationToken cancellationToken)
+        {
+            using (var context = await RetryableWriteContext.CreateAsync(binding, retryRequested, cancellationToken).ConfigureAwait(false))
+            {
+                return await ExecuteAsync(operation, context, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        public static async Task<TResult> ExecuteAsync<TResult>(IRetryableWriteOperation<TResult> operation, RetryableWriteContext context, CancellationToken cancellationToken)
+        {
+            if (!context.RetryRequested || !AreRetryableWritesSupported(context.Channel.ConnectionDescription) || context.Binding.Session.IsInTransaction)
+            {
+                return await operation.ExecuteAttemptAsync(context, 1, null, cancellationToken).ConfigureAwait(false);
+            }
+
+            var transactionNumber = context.Binding.Session.AdvanceTransactionNumber();
+            Exception originalException;
+            try
+            {
+                return await operation.ExecuteAttemptAsync(context, 1, transactionNumber, cancellationToken).ConfigureAwait(false);
+            }
+            catch (Exception ex) when (RetryabilityHelper.IsRetryableWriteException(ex))
+            {
+                originalException = ex;
+            }
+
+            try
+            {
+                context.ReplaceChannelSource(await context.Binding.GetWriteChannelSourceAsync(cancellationToken).ConfigureAwait(false));
+                context.ReplaceChannel(await context.ChannelSource.GetChannelAsync(cancellationToken).ConfigureAwait(false));
+            }
+            catch
+            {
+                throw originalException;
+            }
+
+            if (!AreRetryableWritesSupported(context.Channel.ConnectionDescription))
+            {
+                throw originalException;
+            }
+
+            try
+            {
+                return await operation.ExecuteAttemptAsync(context, 2, transactionNumber, cancellationToken).ConfigureAwait(false);
+            }
+            catch (Exception ex) when (ShouldThrowOriginalException(ex))
+            {
+                throw originalException;
+            }
+        }
+
+        // privates static methods
+        private static bool AreRetryableWritesSupported(ConnectionDescription connectionDescription)
+        {
+            return
+                connectionDescription.IsMasterResult.LogicalSessionTimeout != null &&
+                connectionDescription.IsMasterResult.ServerType != ServerType.Standalone;
+        }
+
+        private static bool ShouldThrowOriginalException(Exception retryException)
+        {
+            return retryException is MongoException && !(retryException is MongoConnectionException);
+        }
+    }
+}

+ 49 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Operations/WriteConcernHelper.cs

@@ -0,0 +1,49 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.Operations
+{
+    internal static class WriteConcernHelper
+    {
+        public static BsonDocument GetWriteConcernForCommand(ICoreSession session, WriteConcern writeConcern, SemanticVersion serverVersion, Feature requiredFeature)
+        {
+            if (!session.IsInTransaction && writeConcern != null && !writeConcern.IsServerDefault && requiredFeature.IsSupported(serverVersion))
+            {
+                return writeConcern.ToBsonDocument();
+            }
+
+            return null;
+        }
+
+        public static BsonDocument GetWriteConcernForCommandThatWrites(ICoreSession session, WriteConcern writeConcern, SemanticVersion serverVersion)
+        {
+            return GetWriteConcernForCommand(session, writeConcern, serverVersion, Feature.CommandsThatWriteAcceptWriteConcern);
+        }
+
+        public static BsonDocument GetWriteConcernForWriteCommand(ICoreSession session, WriteConcern writeConcern)
+        {
+            if (!session.IsInTransaction && writeConcern != null && !writeConcern.IsServerDefault)
+            {
+                return writeConcern.ToBsonDocument();
+            }
+
+            return null;
+        }
+    }
+}

+ 41 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/Servers/ClusterClockAdvancingCoreSession.cs

@@ -0,0 +1,41 @@
+/* Copyright 2017-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Clusters;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.Servers
+{
+    internal  sealed class ClusterClockAdvancingCoreSession : WrappingCoreSession
+    {
+        private readonly IClusterClock _clusterClock;
+
+        public ClusterClockAdvancingCoreSession(ICoreSession wrapped, IClusterClock clusterClock)
+            : base(wrapped, ownsWrapped: false)
+        {
+            _clusterClock = Ensure.IsNotNull(clusterClock, nameof(clusterClock));
+        }
+
+        public override BsonDocument ClusterTime => ClusterClock.GreaterClusterTime(base.ClusterTime, _clusterClock.ClusterTime);
+
+        public override void AdvanceClusterTime(BsonDocument newClusterTime)
+        {
+            base.AdvanceClusterTime(newClusterTime);
+            _clusterClock.AdvanceClusterTime(newClusterTime);
+        }
+    }
+}

+ 339 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs

@@ -0,0 +1,339 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Connections;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.Operations;
+using MongoDB.Driver.Core.WireProtocol.Messages;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.Core.WireProtocol
+{
+    internal class CommandUsingCommandMessageWireProtocol<TCommandResult> : IWireProtocol<TCommandResult>
+    {
+        // private fields
+        private readonly BsonDocument _additionalOptions; // TODO: can these be supported when using CommandMessage?
+        private readonly BsonDocument _command;
+        private readonly List<Type1CommandMessageSection> _commandPayloads;
+        private readonly IElementNameValidator _commandValidator; // TODO: how can this be supported when using CommandMessage?
+        private readonly DatabaseNamespace _databaseNamespace;
+        private readonly MessageEncoderSettings _messageEncoderSettings;
+        private readonly Action<IMessageEncoderPostProcessor> _postWriteAction;
+        private readonly ReadPreference _readPreference;
+        private readonly CommandResponseHandling _responseHandling;
+        private readonly IBsonSerializer<TCommandResult> _resultSerializer;
+        private readonly ICoreSession _session;
+
+        // constructors
+        public CommandUsingCommandMessageWireProtocol(
+            ICoreSession session,
+            ReadPreference readPreference,
+            DatabaseNamespace databaseNamespace,
+            BsonDocument command,
+            IEnumerable<Type1CommandMessageSection> commandPayloads,
+            IElementNameValidator commandValidator,
+            BsonDocument additionalOptions,
+            CommandResponseHandling responseHandling,
+            IBsonSerializer<TCommandResult> resultSerializer,
+            MessageEncoderSettings messageEncoderSettings,
+            Action<IMessageEncoderPostProcessor> postWriteAction)
+        {
+            if (responseHandling != CommandResponseHandling.Return && responseHandling != CommandResponseHandling.NoResponseExpected)
+            {
+                throw new ArgumentException("CommandResponseHandling must be Return or NoneExpected.", nameof(responseHandling));
+            }
+
+            _session = Ensure.IsNotNull(session, nameof(session));
+            _readPreference = readPreference;
+            _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace));
+            _command = Ensure.IsNotNull(command, nameof(command));
+            _commandPayloads = commandPayloads?.ToList(); // can be null
+            _commandValidator = Ensure.IsNotNull(commandValidator, nameof(commandValidator));
+            _additionalOptions = additionalOptions; // can be null
+            _responseHandling = responseHandling;
+            _resultSerializer = Ensure.IsNotNull(resultSerializer, nameof(resultSerializer));
+            _messageEncoderSettings = messageEncoderSettings;
+            _postWriteAction = postWriteAction; // can be null
+        }
+
+        // public methods
+        public TCommandResult Execute(IConnection connection, CancellationToken cancellationToken)
+        {
+            try
+            {
+                var message = CreateCommandMessage(connection.Description);
+
+                try
+                {
+                    connection.SendMessage(message, _messageEncoderSettings, cancellationToken);
+                }
+                finally
+                {
+                    MessageWasProbablySent(message);
+                }
+
+                if (message.WrappedMessage.ResponseExpected)
+                {
+                    var encoderSelector = new CommandResponseMessageEncoderSelector();
+                    var response = (CommandResponseMessage)connection.ReceiveMessage(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken);
+                    return ProcessResponse(connection.ConnectionId, response.WrappedMessage);
+                }
+                else
+                {
+                    return default(TCommandResult);
+                }
+            }
+            catch (MongoException exception) when (ShouldAddTransientTransactionError(exception))
+            {
+                exception.AddErrorLabel("TransientTransactionError");
+                throw;
+            }
+        }
+
+        public async Task<TCommandResult> ExecuteAsync(IConnection connection, CancellationToken cancellationToken)
+        {
+            try
+            {
+                var message = CreateCommandMessage(connection.Description);
+
+                try
+                {
+                    await connection.SendMessageAsync(message, _messageEncoderSettings, cancellationToken).ConfigureAwait(false);
+                }
+                finally
+                {
+                    MessageWasProbablySent(message);
+                }
+
+                if (message.WrappedMessage.ResponseExpected)
+                {
+                    var encoderSelector = new CommandResponseMessageEncoderSelector();
+                    var response = (CommandResponseMessage)await connection.ReceiveMessageAsync(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken).ConfigureAwait(false);
+                    return ProcessResponse(connection.ConnectionId, response.WrappedMessage);
+                }
+                else
+                {
+                    return default(TCommandResult);
+                }
+            }
+            catch (MongoException exception) when (ShouldAddTransientTransactionError(exception))
+            {
+                exception.AddErrorLabel("TransientTransactionError");
+                throw;
+            }
+        }
+
+        // private methods
+        private CommandRequestMessage CreateCommandMessage(ConnectionDescription connectionDescription)
+        {
+            var requestId = RequestMessage.GetNextRequestId();
+            var responseTo = 0;
+            var sections = CreateSections(connectionDescription);
+            var moreToCome = _responseHandling == CommandResponseHandling.NoResponseExpected;
+            var wrappedMessage = new CommandMessage(requestId, responseTo, sections, moreToCome)
+            {
+                PostWriteAction = _postWriteAction
+            };
+            var shouldBeSent = (Func<bool>)(() => true);
+
+            return new CommandRequestMessage(wrappedMessage, shouldBeSent);
+        }
+
+        private IEnumerable<CommandMessageSection> CreateSections(ConnectionDescription connectionDescription)
+        {
+            var type0Section = CreateType0Section(connectionDescription);
+            if (_commandPayloads == null)
+            {
+                return new[] { type0Section };
+            }
+            else
+            {
+                return new CommandMessageSection[] { type0Section }.Concat(_commandPayloads);
+            }
+        }
+
+        private Type0CommandMessageSection<BsonDocument> CreateType0Section(ConnectionDescription connectionDescription)
+        {
+            var extraElements = new List<BsonElement>();
+
+            var dbElement = new BsonElement("$db", _databaseNamespace.DatabaseName);
+            extraElements.Add(dbElement);
+
+            if (_readPreference != null && _readPreference != ReadPreference.Primary)
+            {
+                var readPreferenceDocument = QueryHelper.CreateReadPreferenceDocument(_readPreference);
+                var readPreferenceElement = new BsonElement("$readPreference", readPreferenceDocument);
+                extraElements.Add(readPreferenceElement);
+            }
+
+            if (_session.Id != null)
+            {
+                var lsidElement = new BsonElement("lsid", _session.Id);
+                extraElements.Add(lsidElement);
+            }
+
+            if (_session.ClusterTime != null)
+            {
+                var clusterTimeElement = new BsonElement("$clusterTime", _session.ClusterTime);
+                extraElements.Add(clusterTimeElement);
+            }
+            Action<BsonWriterSettings> writerSettingsConfigurator = s => s.GuidRepresentation = GuidRepresentation.Unspecified;
+
+            _session.AboutToSendCommand();
+            if (_session.IsInTransaction)
+            {
+                var transaction = _session.CurrentTransaction;
+                extraElements.Add(new BsonElement("txnNumber", transaction.TransactionNumber));
+                if (transaction.State == CoreTransactionState.Starting)
+                {
+                    extraElements.Add(new BsonElement("startTransaction", true));
+                    var readConcern = ReadConcernHelper.GetReadConcernForFirstCommandInTransaction(_session, connectionDescription);
+                    if (readConcern != null)
+                    {
+                        extraElements.Add(new BsonElement("readConcern", readConcern));
+                    }
+                }
+                extraElements.Add(new BsonElement("autocommit", false));
+            }
+
+            var elementAppendingSerializer = new ElementAppendingSerializer<BsonDocument>(BsonDocumentSerializer.Instance, extraElements, writerSettingsConfigurator);
+            return new Type0CommandMessageSection<BsonDocument>(_command, elementAppendingSerializer);
+        }
+
+        private void MessageWasProbablySent(CommandRequestMessage message)
+        {
+            if (_session.Id != null)
+            {
+                _session.WasUsed();
+            }
+
+            var transaction = _session.CurrentTransaction;
+            if (transaction != null && transaction.State == CoreTransactionState.Starting)
+            {
+                transaction.SetState(CoreTransactionState.InProgress);
+            }
+        }
+
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
+        private TCommandResult ProcessResponse(ConnectionId connectionId, CommandMessage responseMessage)
+        {
+            using (new CommandMessageDisposer(responseMessage))
+            {
+                var rawDocument = responseMessage.Sections.OfType<Type0CommandMessageSection<RawBsonDocument>>().Single().Document;
+
+                var binaryReaderSettings = new BsonBinaryReaderSettings();
+                if (_messageEncoderSettings != null)
+                {
+                    binaryReaderSettings.Encoding = _messageEncoderSettings.GetOrDefault<UTF8Encoding>(MessageEncoderSettingsName.ReadEncoding, Utf8Encodings.Strict);
+                    binaryReaderSettings.GuidRepresentation = _messageEncoderSettings.GetOrDefault<GuidRepresentation>(MessageEncoderSettingsName.GuidRepresentation, GuidRepresentation.CSharpLegacy);
+                };
+
+                BsonValue clusterTime;
+                if (rawDocument.TryGetValue("$clusterTime", out clusterTime))
+                {
+                    // note: we are assuming that _session is an instance of ClusterClockAdvancingClusterTime
+                    // and that calling _session.AdvanceClusterTime will have the side effect of advancing the cluster's ClusterTime also
+                    var materializedClusterTime = ((RawBsonDocument)clusterTime).Materialize(binaryReaderSettings);
+                    _session.AdvanceClusterTime(materializedClusterTime);
+                }
+
+                BsonValue operationTime;
+                if (rawDocument.TryGetValue("operationTime", out operationTime))
+                {
+                    _session.AdvanceOperationTime(operationTime.AsBsonTimestamp);
+                }
+
+                if (!rawDocument.GetValue("ok", false).ToBoolean())
+                {
+                    var materializedDocument = rawDocument.Materialize(binaryReaderSettings);
+
+                    var commandName = _command.GetElement(0).Name;
+                    if (commandName == "$query")
+                    {
+                        commandName = _command["$query"].AsBsonDocument.GetElement(0).Name;
+                    }
+
+                    var notPrimaryOrNodeIsRecoveringException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, _command, materializedDocument, "errmsg");
+                    if (notPrimaryOrNodeIsRecoveringException != null)
+                    {
+                        throw notPrimaryOrNodeIsRecoveringException;
+                    }
+
+                    var mappedException = ExceptionMapper.Map(connectionId, materializedDocument);
+                    if (mappedException != null)
+                    {
+                        throw mappedException;
+                    }
+
+                    string message;
+                    BsonValue errmsgBsonValue;
+                    if (materializedDocument.TryGetValue("errmsg", out errmsgBsonValue) && errmsgBsonValue.IsString)
+                    {
+                        var errmsg = errmsgBsonValue.ToString();
+                        message = string.Format("Command {0} failed: {1}.", commandName, errmsg);
+                    }
+                    else
+                    {
+                        message = string.Format("Command {0} failed.", commandName);
+                    }
+
+                    throw new MongoCommandException(connectionId, message, _command, materializedDocument);
+                }
+
+                if (rawDocument.Contains("writeConcernError"))
+                {
+                    var materializedDocument = rawDocument.Materialize(binaryReaderSettings);
+                    var writeConcernError = materializedDocument["writeConcernError"].AsBsonDocument;
+                    var message = writeConcernError.AsBsonDocument.GetValue("errmsg", null)?.AsString;
+                    var writeConcernResult = new WriteConcernResult(materializedDocument);
+                    throw new MongoWriteConcernException(connectionId, message, writeConcernResult);
+                }
+
+                using (var stream = new ByteBufferStream(rawDocument.Slice, ownsBuffer: false))
+                {
+                    using (var reader = new BsonBinaryReader(stream, binaryReaderSettings))
+                    {
+                        var context = BsonDeserializationContext.CreateRoot(reader);
+                        return _resultSerializer.Deserialize(context);
+                    }
+                }
+            }
+        }
+
+        private bool ShouldAddTransientTransactionError(MongoException exception)
+        {
+            if (_session.IsInTransaction)
+            {
+                if (exception is MongoConnectionException)
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+}

+ 405 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/CommandUsingQueryMessageWireProtocol.cs

@@ -0,0 +1,405 @@
+/* Copyright 2013-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Connections;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.Operations;
+using MongoDB.Driver.Core.WireProtocol.Messages;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders;
+
+namespace MongoDB.Driver.Core.WireProtocol
+{
+    internal class CommandUsingQueryMessageWireProtocol<TCommandResult> : IWireProtocol<TCommandResult>
+    {
+        // fields
+        private readonly BsonDocument _additionalOptions;
+        private readonly BsonDocument _command;
+        private readonly List<Type1CommandMessageSection> _commandPayloads;
+        private readonly IElementNameValidator _commandValidator;
+        private readonly DatabaseNamespace _databaseNamespace;
+        private readonly Action<IMessageEncoderPostProcessor> _postWriteAction;
+        private readonly MessageEncoderSettings _messageEncoderSettings;
+        private readonly ReadPreference _readPreference;
+        private readonly CommandResponseHandling _responseHandling;
+        private readonly IBsonSerializer<TCommandResult> _resultSerializer;
+        private readonly ICoreSession _session;
+
+        // constructors
+        public CommandUsingQueryMessageWireProtocol(
+            ICoreSession session,
+            ReadPreference readPreference,
+            DatabaseNamespace databaseNamespace,
+            BsonDocument command,
+            IEnumerable<Type1CommandMessageSection> commandPayloads,
+            IElementNameValidator commandValidator,
+            BsonDocument additionalOptions,
+            CommandResponseHandling responseHandling,
+            IBsonSerializer<TCommandResult> resultSerializer,
+            MessageEncoderSettings messageEncoderSettings,
+            Action<IMessageEncoderPostProcessor> postWriteAction)
+        {
+            if (responseHandling != CommandResponseHandling.Return && responseHandling != CommandResponseHandling.Ignore)
+            {
+                throw new ArgumentException("CommandResponseHandling must be Return or Ignore.", nameof(responseHandling));
+            }
+
+            _session = Ensure.IsNotNull(session, nameof(session));
+            _readPreference = readPreference;
+            _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace));
+            _command = Ensure.IsNotNull(command, nameof(command));
+            _commandPayloads = commandPayloads?.ToList(); // can be null
+            _commandValidator = Ensure.IsNotNull(commandValidator, nameof(commandValidator));
+            _additionalOptions = additionalOptions; // can be null
+            _responseHandling = responseHandling;
+            _resultSerializer = Ensure.IsNotNull(resultSerializer, nameof(resultSerializer));
+            _messageEncoderSettings = messageEncoderSettings;
+            _postWriteAction = postWriteAction; // can be null
+        }
+
+        // methods
+        private QueryMessage CreateMessage(ConnectionDescription connectionDescription, out bool messageContainsSessionId)
+        {
+            var commandWithPayloads = CombineCommandWithPayloads(connectionDescription);
+            var wrappedCommand = WrapCommandForQueryMessage(commandWithPayloads, connectionDescription, out messageContainsSessionId);
+            var slaveOk = _readPreference != null && _readPreference.ReadPreferenceMode != ReadPreferenceMode.Primary;
+
+            return new QueryMessage(
+                RequestMessage.GetNextRequestId(),
+                _databaseNamespace.CommandCollection,
+                wrappedCommand,
+                null,
+                _commandValidator,
+                0,
+                -1,
+                slaveOk,
+                false,
+                false,
+                false,
+                false,
+                false)
+            {
+                PostWriteAction = _postWriteAction,
+                ResponseHandling = _responseHandling
+            };
+        }
+
+        public TCommandResult Execute(IConnection connection, CancellationToken cancellationToken)
+        {
+            bool messageContainsSessionId;
+            var message = CreateMessage(connection.Description, out messageContainsSessionId);
+            connection.SendMessage(message, _messageEncoderSettings, cancellationToken);
+            if (messageContainsSessionId)
+            {
+                _session.WasUsed();
+            }
+
+            switch (message.ResponseHandling)
+            {
+                case CommandResponseHandling.Ignore:
+                    IgnoreResponse(connection, message, cancellationToken);
+                    return default(TCommandResult);
+                default:
+                    var encoderSelector = new ReplyMessageEncoderSelector<RawBsonDocument>(RawBsonDocumentSerializer.Instance);
+                    var reply = connection.ReceiveMessage(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken);
+                    return ProcessReply(connection.ConnectionId, (ReplyMessage<RawBsonDocument>)reply);
+            }
+        }
+
+        public async Task<TCommandResult> ExecuteAsync(IConnection connection, CancellationToken cancellationToken)
+        {
+            bool messageContainsSessionId;
+            var message = CreateMessage(connection.Description, out messageContainsSessionId);
+            await connection.SendMessageAsync(message, _messageEncoderSettings, cancellationToken).ConfigureAwait(false);
+            if (messageContainsSessionId)
+            {
+                _session.WasUsed();
+            }
+
+            switch (message.ResponseHandling)
+            {
+                case CommandResponseHandling.Ignore:
+                    IgnoreResponse(connection, message, cancellationToken);
+                    return default(TCommandResult);
+                default:
+                    var encoderSelector = new ReplyMessageEncoderSelector<RawBsonDocument>(RawBsonDocumentSerializer.Instance);
+                    var reply = await connection.ReceiveMessageAsync(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken).ConfigureAwait(false);
+                    return ProcessReply(connection.ConnectionId, (ReplyMessage<RawBsonDocument>)reply);
+            }
+        }
+
+        // private methods
+        private BsonDocument CombineCommandWithPayloads(ConnectionDescription connectionDescription)
+        {
+            if (_commandPayloads == null || _commandPayloads.Count == 0)
+            {
+                return _command;
+            }
+
+            var extraElements = new List<BsonElement>();
+            foreach (var type1Section in _commandPayloads)
+            {
+                var name = type1Section.Identifier;
+                var value = CreatePayloadArray(type1Section, connectionDescription);
+                var element = new BsonElement(name, value);
+                extraElements.Add(element);
+            }
+
+            var payloadAppendingSerializer = new ElementAppendingSerializer<BsonDocument>(BsonDocumentSerializer.Instance, extraElements);
+            return new BsonDocumentWrapper(_command, payloadAppendingSerializer);
+        }
+
+        private BsonArray CreatePayloadArray(Type1CommandMessageSection payload, ConnectionDescription connectionDescription)
+        {
+            IBsonSerializer payloadSerializer;
+            if (payload.Documents.CanBeSplit)
+            {
+                payloadSerializer = CreateSizeLimitingPayloadSerializer(payload, connectionDescription);
+            }
+            else
+            {
+                payloadSerializer = CreateFixedCountPayloadSerializer(payload);
+            }
+
+            var documents = new BsonDocumentWrapper(payload.Documents, payloadSerializer);
+            return new BsonArray { documents };
+        }
+
+        private IBsonSerializer CreateFixedCountPayloadSerializer(Type1CommandMessageSection payload)
+        {
+            var documentType = payload.DocumentType;
+            var serializerType = typeof(FixedCountBatchableSourceSerializer<>).MakeGenericType(documentType);
+            var itemSerializerType = typeof(IBsonSerializer<>).MakeGenericType(documentType);
+            var constructorParameterTypes = new[] { itemSerializerType, typeof(IElementNameValidator), typeof(int) };
+            var constructorInfo = serializerType.GetTypeInfo().GetConstructor(constructorParameterTypes);
+            var itemSerializer = payload.DocumentSerializer;
+            var itemElementNameValidator = payload.ElementNameValidator;
+            var count = payload.Documents.Count;
+            return (IBsonSerializer)constructorInfo.Invoke(new object[] { itemSerializer, itemElementNameValidator, count });
+        }
+
+        private IBsonSerializer CreateSizeLimitingPayloadSerializer(Type1CommandMessageSection payload, ConnectionDescription connectionDescription)
+        {
+            var documentType = payload.DocumentType;
+            var serializerType = typeof(SizeLimitingBatchableSourceSerializer<>).MakeGenericType(documentType);
+            var itemSerializerType = typeof(IBsonSerializer<>).MakeGenericType(documentType);
+            var constructorParameterTypes = new[] { itemSerializerType, typeof(IElementNameValidator), typeof(int), typeof(int), typeof(int) };
+            var constructorInfo = serializerType.GetTypeInfo().GetConstructor(constructorParameterTypes);
+            var itemSerializer = payload.DocumentSerializer;
+            var itemElementNameValidator = payload.ElementNameValidator;
+            var maxBatchCount = Math.Min(payload.MaxBatchCount ?? int.MaxValue, connectionDescription.MaxBatchCount);
+            var maxItemSize = payload.MaxDocumentSize ?? connectionDescription.MaxDocumentSize;
+            var maxBatchSize = connectionDescription.MaxDocumentSize;
+            return (IBsonSerializer)constructorInfo.Invoke(new object[] { itemSerializer, itemElementNameValidator, maxBatchCount, maxItemSize, maxBatchSize });
+        }
+
+        private void IgnoreResponse(IConnection connection, QueryMessage message, CancellationToken cancellationToken)
+        {
+            var encoderSelector = new ReplyMessageEncoderSelector<IgnoredReply>(IgnoredReplySerializer.Instance);
+            connection.ReceiveMessageAsync(message.RequestId, encoderSelector, _messageEncoderSettings, cancellationToken).IgnoreExceptions();
+        }
+
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
+        private TCommandResult ProcessReply(ConnectionId connectionId, ReplyMessage<RawBsonDocument> reply)
+        {
+            if (reply.NumberReturned == 0)
+            {
+                throw new MongoCommandException(connectionId, "Command returned no documents.", _command);
+            }
+            if (reply.NumberReturned > 1)
+            {
+                throw new MongoCommandException(connectionId, "Command returned multiple documents.", _command);
+            }
+            if (reply.QueryFailure)
+            {
+                var failureDocument = reply.QueryFailureDocument;
+                throw ExceptionMapper.Map(connectionId, failureDocument) ?? new MongoCommandException(connectionId, "Command failed.", _command, failureDocument);
+            }
+
+            using (var rawDocument = reply.Documents[0])
+            {
+                var binaryReaderSettings = new BsonBinaryReaderSettings();
+                if (_messageEncoderSettings != null)
+                {
+                    binaryReaderSettings.Encoding = _messageEncoderSettings.GetOrDefault<UTF8Encoding>(MessageEncoderSettingsName.ReadEncoding, Utf8Encodings.Strict);
+                    binaryReaderSettings.GuidRepresentation = _messageEncoderSettings.GetOrDefault<GuidRepresentation>(MessageEncoderSettingsName.GuidRepresentation, GuidRepresentation.CSharpLegacy);
+                };
+
+                BsonValue clusterTime;
+                if (rawDocument.TryGetValue("$clusterTime", out clusterTime))
+                {
+                    // note: we are assuming that _session is an instance of ClusterClockAdvancingClusterTime
+                    // and that calling _session.AdvanceClusterTime will have the side effect of advancing the cluster's ClusterTime also
+                    var materializedClusterTime = ((RawBsonDocument)clusterTime).Materialize(binaryReaderSettings);
+                    _session.AdvanceClusterTime(materializedClusterTime);
+                }
+                BsonValue operationTime;
+                if (rawDocument.TryGetValue("operationTime", out operationTime))
+                {
+                    _session.AdvanceOperationTime(operationTime.AsBsonTimestamp);
+                }
+
+                if (!rawDocument.GetValue("ok", false).ToBoolean())
+                {
+                    var materializedDocument = rawDocument.Materialize(binaryReaderSettings);
+
+                    var commandName = _command.GetElement(0).Name;
+                    if (commandName == "$query")
+                    {
+                        commandName = _command["$query"].AsBsonDocument.GetElement(0).Name;
+                    }
+
+                    var notPrimaryOrNodeIsRecoveringException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, _command, materializedDocument, "errmsg");
+                    if (notPrimaryOrNodeIsRecoveringException != null)
+                    {
+                        throw notPrimaryOrNodeIsRecoveringException;
+                    }
+
+                    string message;
+                    BsonValue errmsgBsonValue;
+                    if (materializedDocument.TryGetValue("errmsg", out errmsgBsonValue) && errmsgBsonValue.IsString)
+                    {
+                        var errmsg = errmsgBsonValue.ToString();
+                        message = string.Format("Command {0} failed: {1}.", commandName, errmsg);
+                    }
+                    else
+                    {
+                        message = string.Format("Command {0} failed.", commandName);
+                    }
+
+                    var mappedException = ExceptionMapper.Map(connectionId, materializedDocument);
+                    if (mappedException != null)
+                    {
+                        throw mappedException;
+                    }
+
+                    throw new MongoCommandException(connectionId, message, _command, materializedDocument);
+                }
+
+                if (rawDocument.Contains("writeConcernError"))
+                {
+                    var materializedDocument = rawDocument.Materialize(binaryReaderSettings);
+                    var writeConcernError = materializedDocument["writeConcernError"].AsBsonDocument;
+                    var message = writeConcernError.AsBsonDocument.GetValue("errmsg", null)?.AsString;
+                    var writeConcernResult = new WriteConcernResult(materializedDocument);
+                    throw new MongoWriteConcernException(connectionId, message, writeConcernResult);
+                }
+
+                using (var stream = new ByteBufferStream(rawDocument.Slice, ownsBuffer: false))
+                {
+                    var encoderFactory = new BinaryMessageEncoderFactory(stream, _messageEncoderSettings);
+                    var encoder = (ReplyMessageBinaryEncoder<TCommandResult>)encoderFactory.GetReplyMessageEncoder<TCommandResult>(_resultSerializer);
+                    using (var reader = encoder.CreateBinaryReader())
+                    {
+                        var context = BsonDeserializationContext.CreateRoot(reader);
+                        return _resultSerializer.Deserialize(context);
+                    }
+                }
+            }
+        }
+
+        private BsonDocument WrapCommandForQueryMessage(BsonDocument command, ConnectionDescription connectionDescription, out bool messageContainsSessionId)
+        {
+            messageContainsSessionId = false;
+            var extraElements = new List<BsonElement>();
+            if (_session.Id != null)
+            {
+                var areSessionsSupported = connectionDescription.IsMasterResult.LogicalSessionTimeout.HasValue;
+                if (areSessionsSupported)
+                {
+                    var lsid = new BsonElement("lsid", _session.Id);
+                    extraElements.Add(lsid);
+                    messageContainsSessionId = true;
+                }
+                else
+                {
+                    if (!_session.IsImplicit)
+                    {
+                        throw new MongoClientException("Sessions are not supported.");
+                    }
+                }
+            }
+            if (_session.ClusterTime != null)
+            {
+                var clusterTime = new BsonElement("$clusterTime", _session.ClusterTime);
+                extraElements.Add(clusterTime);
+            }
+            Action<BsonWriterSettings> writerSettingsConfigurator = s => s.GuidRepresentation = GuidRepresentation.Unspecified;
+            var appendExtraElementsSerializer = new ElementAppendingSerializer<BsonDocument>(BsonDocumentSerializer.Instance, extraElements, writerSettingsConfigurator);
+            var commandWithExtraElements = new BsonDocumentWrapper(command, appendExtraElementsSerializer);
+
+            BsonDocument readPreferenceDocument = null;
+            if (connectionDescription != null)
+            {
+                var serverType = connectionDescription.IsMasterResult.ServerType;
+                readPreferenceDocument = QueryHelper.CreateReadPreferenceDocument(serverType, _readPreference);
+            }
+
+            var wrappedCommand = new BsonDocument
+            {
+                { "$query", commandWithExtraElements },
+                { "$readPreference", readPreferenceDocument, readPreferenceDocument != null }
+            };
+            if (_additionalOptions != null)
+            {
+                wrappedCommand.Merge(_additionalOptions, overwriteExistingElements: false);
+            }
+
+            if (wrappedCommand.ElementCount == 1)
+            {
+                return wrappedCommand["$query"].AsBsonDocument;
+            }
+            else
+            {
+                return wrappedCommand;
+            }
+        }
+
+        // nested types
+        private class IgnoredReply
+        {
+            public static IgnoredReply Instance = new IgnoredReply();
+        }
+
+        private class IgnoredReplySerializer : SerializerBase<IgnoredReply>
+        {
+            public static IgnoredReplySerializer Instance = new IgnoredReplySerializer();
+
+            public override IgnoredReply Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
+            {
+                context.Reader.ReadStartDocument();
+                while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
+                {
+                    context.Reader.SkipName();
+                    context.Reader.SkipValue();
+                }
+                context.Reader.ReadEndDocument();
+                return IgnoredReply.Instance;
+            }
+        }
+    }
+}

+ 129 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/CommandMessage.cs

@@ -0,0 +1,129 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages
+{
+    /// <summary>
+    /// Represents a command message.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.MongoDBMessage" />
+    public sealed class CommandMessage : MongoDBMessage
+    {
+        // fields
+        private bool _moreToCome;
+        private Action<IMessageEncoderPostProcessor> _postWriteAction;
+        private readonly int _requestId;
+        private readonly int _responseTo;
+        private readonly List<CommandMessageSection> _sections;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CommandMessage" /> class.
+        /// </summary>
+        /// <param name="requestId">The request identifier.</param>
+        /// <param name="responseTo">The response to.</param>
+        /// <param name="sections">The sections.</param>
+        /// <param name="moreToCome">if set to <c>true</c> [more to come].</param>
+        public CommandMessage(
+            int requestId,
+            int responseTo,
+            IEnumerable<CommandMessageSection> sections,
+            bool moreToCome)
+        {
+            _requestId = requestId;
+            _responseTo = responseTo;
+            _sections = Ensure.IsNotNull(sections, nameof(sections)).ToList();
+            _moreToCome = moreToCome;
+
+            if (_sections.Count(s => s.PayloadType == PayloadType.Type0) != 1)
+            {
+                throw new ArgumentException("There must be exactly one type 0 payload.", nameof(sections));
+            }
+        }
+
+        // public properties
+        /// <inheritdoc />
+        public override MongoDBMessageType MessageType => MongoDBMessageType.Command;
+
+        /// <summary>
+        /// Gets or sets a value indicating whether another message immediately follows this one with no response expected.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if another message immediately follows this one; otherwise, <c>false</c>.
+        /// </value>
+        public bool MoreToCome
+        {
+            get { return _moreToCome; }
+            set { _moreToCome = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the delegate called to after the message has been written by the encoder.
+        /// </summary>
+        /// <value>
+        /// The post write delegate.
+        /// </value>
+        public Action<IMessageEncoderPostProcessor> PostWriteAction
+        {
+            get { return _postWriteAction; }
+            set { _postWriteAction = value; }
+        }
+
+        /// <summary>
+        /// Gets the request identifier.
+        /// </summary>
+        /// <value>
+        /// The request identifier.
+        /// </value>
+        public int RequestId => _requestId;
+
+        /// <summary>
+        /// Gets a value indicating whether a response is expected.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if a response is expected; otherwise, <c>false</c>.
+        /// </value>
+        public bool ResponseExpected => !_moreToCome;
+
+        /// <summary>
+        /// Gets the response to.
+        /// </summary>
+        /// <value>
+        /// The response to.
+        /// </value>
+        public int ResponseTo => _responseTo;
+
+        /// <summary>
+        /// Gets the sections.
+        /// </summary>
+        /// <value>
+        /// The sections.
+        /// </value>
+        public IReadOnlyList<CommandMessageSection> Sections => _sections;
+
+        // public methods
+        /// <inheritdoc />
+        public override IMessageEncoder GetEncoder(IMessageEncoderFactory encoderFactory)
+        {
+            return encoderFactory.GetCommandMessageEncoder();
+        }
+    }
+}

+ 69 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/CommandMessageDisposer.cs

@@ -0,0 +1,69 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using MongoDB.Bson;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages
+{
+    internal sealed class CommandMessageDisposer : IDisposable
+    {
+        // private fields
+        private CommandMessage _message;
+
+        // constructors
+        public CommandMessageDisposer(CommandMessage message)
+        {
+            _message = message;
+        }
+
+        // public methods
+        public void Dispose()
+        {
+            foreach (var section in _message.Sections)
+            {
+                DisposeSection(section);
+            }
+        }
+
+        // private methods
+        private void DisposeSection(CommandMessageSection section)
+        {
+            switch (section.PayloadType)
+            {
+                case PayloadType.Type0:
+                    DisposeType0Section((Type0CommandMessageSection<RawBsonDocument>)section);
+                    break;
+
+                case PayloadType.Type1:
+                    DisposeType1Section((Type1CommandMessageSection<RawBsonDocument>)section);
+                    break;
+            }
+        }
+
+        private void DisposeType0Section(Type0CommandMessageSection<RawBsonDocument> section)
+        {
+            section.Document.Dispose();
+        }
+
+        private void DisposeType1Section(Type1CommandMessageSection<RawBsonDocument> section)
+        {
+            foreach (var document in section.Documents.GetBatchItems())
+            {
+                document.Dispose();
+            }
+        }
+    }
+}

+ 293 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/CommandMessageSection.cs

@@ -0,0 +1,293 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages
+{
+    /// <summary>
+    /// Represents the payload type.
+    /// </summary>
+    public enum PayloadType
+    {
+        /// <summary>
+        /// Payload type 0.
+        /// </summary>
+        Type0 = 0,
+        /// <summary>
+        /// Payload type 1.
+        /// </summary>
+        Type1 = 1
+    }
+
+    /// <summary>
+    /// Represents a CommandMessage section.
+    /// </summary>
+    public abstract class CommandMessageSection
+    {
+        /// <summary>
+        /// Gets the type of the payload.
+        /// </summary>
+        /// <value>
+        /// The type of the payload.
+        /// </value>
+        public abstract PayloadType PayloadType { get; }
+    }
+
+    /// <summary>
+    /// Represents a Type 0 CommandMessage section.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.CommandMessageSection" />
+    public abstract class Type0CommandMessageSection : CommandMessageSection
+    {
+        // private fields
+        private readonly object _document;
+        private readonly IBsonSerializer _documentSerializer;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Type0CommandMessageSection{TDocument}"/> class.
+        /// </summary>
+        /// <param name="document">The document.</param>
+        /// <param name="documentSerializer">The document serializer.</param>
+        public Type0CommandMessageSection(object document, IBsonSerializer documentSerializer)
+        {
+            Ensure.IsNotNull((object)document, nameof(document));
+            _document = document;
+            _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the document.
+        /// </summary>
+        /// <value>
+        /// The document.
+        /// </value>
+        public object Document => _document;
+
+        /// <summary>
+        /// Gets the document serializer.
+        /// </summary>
+        /// <value>
+        /// The document serializer.
+        /// </value>
+        public IBsonSerializer DocumentSerializer => _documentSerializer;
+
+        /// <inheritdoc />
+        public override PayloadType PayloadType => PayloadType.Type0;
+    }
+
+    /// <summary>
+    /// Represents a Type 0 CommandMessage section.
+    /// </summary>
+    /// <typeparam name="TDocument">The type of the document.</typeparam>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.Type0CommandMessageSection" />
+    public sealed class Type0CommandMessageSection<TDocument> : Type0CommandMessageSection
+    {
+        // private fields
+        private readonly TDocument _document;
+        private readonly IBsonSerializer<TDocument> _documentSerializer;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Type0CommandMessageSection{TDocument}"/> class.
+        /// </summary>
+        /// <param name="document">The document.</param>
+        /// <param name="documentSerializer">The document serializer.</param>
+        public Type0CommandMessageSection(TDocument document, IBsonSerializer<TDocument> documentSerializer)
+            : base(document, documentSerializer)
+        {
+            Ensure.IsNotNull((object)document, nameof(document));
+            _document = document;
+            _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the document.
+        /// </summary>
+        /// <value>
+        /// The document.
+        /// </value>
+        public new TDocument Document => _document;
+
+        /// <summary>
+        /// Gets the document serializer.
+        /// </summary>
+        /// <value>
+        /// The document serializer.
+        /// </value>
+        public new IBsonSerializer<TDocument> DocumentSerializer => _documentSerializer;
+    }
+
+    /// <summary>
+    /// Represents a Type 1 CommandMessage section.
+    /// </summary>
+    public abstract class Type1CommandMessageSection : CommandMessageSection
+    {
+        // private fields
+        private readonly IBatchableSource<object> _documents;
+        private readonly IBsonSerializer _documentSerializer;
+        private readonly IElementNameValidator _elementNameValidator;
+        private readonly string _identifier;
+        private readonly int? _maxBatchCount;
+        private readonly int? _maxDocumentSize;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Type1CommandMessageSection{TDocument}" /> class.
+        /// </summary>
+        /// <param name="identifier">The identifier.</param>
+        /// <param name="documents">The documents.</param>
+        /// <param name="documentSerializer">The document serializer.</param>
+        /// <param name="elementNameValidator">The element name validator.</param>
+        /// <param name="maxBatchCount">The maximum batch count.</param>
+        /// <param name="maxDocumentSize">Maximum size of the document.</param>
+        public Type1CommandMessageSection(
+            string identifier,
+            IBatchableSource<object> documents,
+            IBsonSerializer documentSerializer,
+            IElementNameValidator elementNameValidator,
+            int? maxBatchCount,
+            int? maxDocumentSize)
+        {
+            _identifier = Ensure.IsNotNull(identifier, nameof(identifier));
+            _documents = Ensure.IsNotNull(documents, nameof(documents));
+            _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer));
+            _elementNameValidator = Ensure.IsNotNull(elementNameValidator, nameof(elementNameValidator));
+            _maxBatchCount = Ensure.IsNullOrGreaterThanZero(maxBatchCount, nameof(maxBatchCount));
+            _maxDocumentSize = Ensure.IsNullOrGreaterThanZero(maxDocumentSize, nameof(maxDocumentSize));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the documents.
+        /// </summary>
+        /// <value>
+        /// The documents.
+        /// </value>
+        public IBatchableSource<object> Documents => _documents;
+
+        /// <summary>
+        /// Gets the document serializer.
+        /// </summary>
+        /// <value>
+        /// The document serializer.
+        /// </value>
+        public IBsonSerializer DocumentSerializer => _documentSerializer;
+
+        /// <summary>
+        /// Gets the type of the document.
+        /// </summary>
+        /// <value>
+        /// The type of the document.
+        /// </value>
+        public abstract Type DocumentType { get; }
+
+        /// <summary>
+        /// Gets the element name validator.
+        /// </summary>
+        /// <value>
+        /// The element name validator.
+        /// </value>
+        public IElementNameValidator ElementNameValidator => _elementNameValidator;
+
+        /// <summary>
+        /// Gets the identifier.
+        /// </summary>
+        /// <value>
+        /// The identifier.
+        /// </value>
+        public string Identifier => _identifier;
+
+        /// <summary>
+        /// Gets the maximum batch count.
+        /// </summary>
+        /// <value>
+        /// The maximum batch count.
+        /// </value>
+        public int? MaxBatchCount => _maxBatchCount;
+
+        /// <summary>
+        /// Gets the maximum size of the document.
+        /// </summary>
+        /// <value>
+        /// The maximum size of the document.
+        /// </value>
+        public int? MaxDocumentSize => _maxDocumentSize;
+
+        /// <inheritdoc />
+        public override PayloadType PayloadType => PayloadType.Type1;
+    }
+
+    /// <summary>
+    /// Represents a Type 1 CommandMessage section.
+    /// </summary>
+    /// <typeparam name="TDocument">The type of the document.</typeparam>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.CommandMessageSection" />
+    public class Type1CommandMessageSection<TDocument> : Type1CommandMessageSection where TDocument : class
+    {
+        // private fields
+        private readonly IBatchableSource<TDocument> _documents;
+        private readonly IBsonSerializer<TDocument> _documentSerializer;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Type1CommandMessageSection{TDocument}" /> class.
+        /// </summary>
+        /// <param name="identifier">The identifier.</param>
+        /// <param name="documents">The documents.</param>
+        /// <param name="documentSerializer">The document serializer.</param>
+        /// <param name="elementNameValidator">The element name validator.</param>
+        /// <param name="maxBatchCount">The maximum batch count.</param>
+        /// <param name="maxDocumentSize">Maximum size of the document.</param>
+        public Type1CommandMessageSection(
+            string identifier,
+            IBatchableSource<TDocument> documents,
+            IBsonSerializer<TDocument> documentSerializer,
+            IElementNameValidator elementNameValidator,
+            int? maxBatchCount,
+            int? maxDocumentSize)
+            : base(identifier, documents, documentSerializer, elementNameValidator, maxBatchCount, maxDocumentSize)
+        {
+            _documents = Ensure.IsNotNull(documents, nameof(documents));
+            _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer));
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the documents.
+        /// </summary>
+        /// <value>
+        /// The documents.
+        /// </value>
+        public new IBatchableSource<TDocument> Documents => _documents;
+
+        /// <summary>
+        /// Gets the document serializer.
+        /// </summary>
+        /// <value>
+        /// The document serializer.
+        /// </value>
+        public new IBsonSerializer<TDocument> DocumentSerializer => _documentSerializer;
+
+        /// <inheritdoc />
+        public override Type DocumentType => typeof(TDocument);
+    }
+}

+ 66 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/CommandRequestMessage.cs

@@ -0,0 +1,66 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages
+{
+    /// <summary>
+    /// Represents a command request message.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.RequestMessage" />
+    public class CommandRequestMessage : RequestMessage
+    {
+        // private fields
+        private readonly CommandMessage _wrappedMessage;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CommandRequestMessage" /> class.
+        /// </summary>
+        /// <param name="wrappedMessage">The wrapped message.</param>
+        /// <param name="shouldBeSent">The should be sent.</param>
+        public CommandRequestMessage(CommandMessage wrappedMessage, Func<bool> shouldBeSent)
+            : base(Ensure.IsNotNull(wrappedMessage, nameof(wrappedMessage)).RequestId, shouldBeSent)
+        {
+            _wrappedMessage = Ensure.IsNotNull(wrappedMessage, nameof(wrappedMessage));
+        }
+
+        // public properties
+        /// <inheritdoc />
+        public override MongoDBMessageType MessageType => _wrappedMessage.MessageType;
+
+        /// <summary>
+        /// Gets the wrapped message.
+        /// </summary>
+        /// <value>
+        /// The wrapped message.
+        /// </value>
+        public CommandMessage WrappedMessage => _wrappedMessage;
+
+        // public methods
+        /// <inheritdoc />
+        public override IMessageEncoder GetEncoder(IMessageEncoderFactory encoderFactory)
+        {
+            return encoderFactory.GetCommandRequestMessageEncoder();
+        }
+    }
+}

+ 65 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/CommandResponseMessage.cs

@@ -0,0 +1,65 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages
+{
+    /// <summary>
+    /// Represents a command response message.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.RequestMessage" />
+    public class CommandResponseMessage : ResponseMessage
+    {
+        // private fields
+        private readonly CommandMessage _wrappedMessage;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CommandRequestMessage" /> class.
+        /// </summary>
+        /// <param name="wrappedMessage">The wrapped message.</param>
+        public CommandResponseMessage(CommandMessage wrappedMessage)
+            : base(Ensure.IsNotNull(wrappedMessage, nameof(wrappedMessage)).RequestId, wrappedMessage.ResponseTo)
+        {
+            _wrappedMessage = Ensure.IsNotNull(wrappedMessage, nameof(wrappedMessage));
+        }
+
+        // public properties
+        /// <inheritdoc />
+        public override MongoDBMessageType MessageType => _wrappedMessage.MessageType;
+
+        /// <summary>
+        /// Gets the wrapped message.
+        /// </summary>
+        /// <value>
+        /// The wrapped message.
+        /// </value>
+        public CommandMessage WrappedMessage => _wrappedMessage;
+
+        // public methods
+        /// <inheritdoc />
+        public override IMessageEncoder GetEncoder(IMessageEncoderFactory encoderFactory)
+        {
+            return encoderFactory.GetCommandResponseMessageEncoder();
+        }
+    }
+}

+ 450 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs

@@ -0,0 +1,450 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing per
+* ssions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders
+{
+    /// <summary>
+    /// Represents a binary encoder for a CommandMessage.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders.MessageBinaryEncoderBase" />
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.Encoders.IMessageEncoder" />
+    public class CommandMessageBinaryEncoder : MessageBinaryEncoderBase, IMessageEncoder
+    {
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CommandMessageBinaryEncoder" /> class.
+        /// </summary>
+        /// <param name="stream">The stream.</param>
+        /// <param name="encoderSettings">The encoder settings.</param>
+        public CommandMessageBinaryEncoder(Stream stream, MessageEncoderSettings encoderSettings)
+            : base(stream, encoderSettings)
+        {
+        }
+
+        // public methods
+        /// <summary>
+        /// Reads the message.
+        /// </summary>
+        /// <returns>A message.</returns>
+        public CommandMessage ReadMessage()
+        {
+            var reader = CreateBinaryReader();
+            var stream = reader.BsonStream;
+            var messageStartPosition = stream.Position;
+
+            var messageLength = stream.ReadInt32();
+            EnsureMessageLengthIsValid(messageLength);
+            var messageEndPosition = messageStartPosition + messageLength;
+
+            var requestId = stream.ReadInt32();
+            var responseTo = stream.ReadInt32();
+            var opcode = (Opcode)stream.ReadInt32();
+            EnsureOpcodeIsValid(opcode);
+            var flags = (OpMsgFlags)stream.ReadInt32();
+            EnsureFlagsAreValid(flags);
+            var moreToCome = (flags & OpMsgFlags.MoreToCome) != 0;
+            var sections = ReadSections(reader, messageEndPosition);
+            EnsureExactlyOneType0SectionIsPresent(sections);
+            EnsureMessageEndedAtEndPosition(stream, messageEndPosition);
+
+            return new CommandMessage(requestId, responseTo, sections, moreToCome);
+        }
+
+        /// <summary>
+        /// Writes the message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void WriteMessage(CommandMessage message)
+        {
+            Ensure.IsNotNull(message, nameof(message));
+
+            var writer = CreateBinaryWriter();
+            var stream = writer.BsonStream;
+            var messageStartPosition = stream.Position;
+
+            stream.WriteInt32(0); // messageLength
+            stream.WriteInt32(message.RequestId);
+            stream.WriteInt32(message.ResponseTo);
+            stream.WriteInt32((int)Opcode.OpMsg);
+            stream.WriteInt32((int)CreateFlags(message));
+            WriteSections(writer, message.Sections, messageStartPosition);
+            stream.BackpatchSize(messageStartPosition);
+
+            message.PostWriteAction?.Invoke(new PostProcessor(message, stream, messageStartPosition));
+        }
+
+        // explicit interface implementations
+        MongoDBMessage IMessageEncoder.ReadMessage()
+        {
+            return ReadMessage();
+        }
+
+        void IMessageEncoder.WriteMessage(MongoDBMessage message)
+        {
+            WriteMessage((CommandMessage)message);
+        }
+
+        // private methods
+        private OpMsgFlags CreateFlags(CommandMessage message)
+        {
+            var flags = (OpMsgFlags)0;
+            if (message.MoreToCome)
+            {
+                flags |= OpMsgFlags.MoreToCome;
+            }
+            return flags;
+        }
+
+        private void EnsureExactlyOneType0SectionIsPresent(List<CommandMessageSection> sections)
+        {
+            var count = sections.Count(s => s.PayloadType == PayloadType.Type0);
+            switch (count)
+            {
+                case 0:
+                    throw new FormatException("Command message has no type 0 section.");
+
+                case 1:
+                    return;
+
+                default:
+                    throw new FormatException("Command message has more than one type 0 section.");
+            }
+        }
+
+        private void EnsureFlagsAreValid(OpMsgFlags flags)
+        {
+            var invalidFlags = ~OpMsgFlags.All;
+            if ((flags & invalidFlags) != 0)
+            {
+                throw new FormatException("Command message has invalid flags.");
+            }
+            if ((flags & OpMsgFlags.ChecksumPresent) != 0)
+            {
+                throw new FormatException("Command message CheckSumPresent flag not supported.");
+            }
+        }
+
+        private void EnsureMessageEndedAtEndPosition(BsonStream stream, long messageEndPosition)
+        {
+            if (stream.Position != messageEndPosition)
+            {
+                throw new FormatException("Command message did not end at the expected end position.");
+            }
+        }
+
+        private void EnsureMessageLengthIsValid(int messageLength)
+        {
+            if (messageLength < 0)
+            {
+                throw new FormatException("Command message length is negative.");
+            }
+        }
+
+        private void EnsureOpcodeIsValid(Opcode opcode)
+        {
+            if (opcode != Opcode.OpMsg)
+            {
+                throw new FormatException("Command message opcode is not OP_MSG.");
+            }
+        }
+
+        private void EnsurePayloadEndedAtEndPosition(BsonStream stream, long sectionEndPosition)
+        {
+            if (stream.Position != sectionEndPosition)
+            {
+                throw new FormatException("Command message payload did not end at the expected end position.");
+            }
+        }
+
+        private void EnsureType1PayloadLengthIsValid(int sectionLength)
+        {
+            if (sectionLength < 0)
+            {
+                throw new FormatException("Command message type 1 payload length is negative.");
+            }
+        }
+
+        private CommandMessageSection ReadSection(BsonBinaryReader reader)
+        {
+            var payloadType = reader.BsonStream.ReadByte();
+            if (payloadType == -1)
+            {
+                throw new EndOfStreamException();
+            }
+
+            switch (payloadType)
+            {
+                case 0:
+                    return ReadType0Section(reader);
+
+                case 1:
+                    return ReadType1Section(reader);
+
+                default:
+                    throw new FormatException($"Command message invalid payload type: {payloadType}.");
+            }
+        }
+
+        private List<CommandMessageSection> ReadSections(BsonBinaryReader reader, long messageEndPosition)
+        {
+            var sections = new List<CommandMessageSection>();
+            while (reader.BsonStream.Position < messageEndPosition)
+            {
+                var section = ReadSection(reader);
+                sections.Add(section);
+            }
+            return sections;
+        }
+
+        private Type0CommandMessageSection<RawBsonDocument> ReadType0Section(IBsonReader reader)
+        {
+            var serializer = RawBsonDocumentSerializer.Instance;
+            var context = BsonDeserializationContext.CreateRoot(reader);
+            var document = serializer.Deserialize(context);
+            return new Type0CommandMessageSection<RawBsonDocument>(document, serializer);
+        }
+
+        private Type1CommandMessageSection<RawBsonDocument> ReadType1Section(BsonBinaryReader reader)
+        {
+            var stream = reader.BsonStream;
+
+            var payloadStartPosition = stream.Position;
+            var payloadLength = stream.ReadInt32();
+            EnsureType1PayloadLengthIsValid(payloadLength);
+            var payloadEndPosition = payloadStartPosition + payloadLength;
+            var identifier = stream.ReadCString(Utf8Encodings.Strict);
+            var serializer = RawBsonDocumentSerializer.Instance;
+            var context = BsonDeserializationContext.CreateRoot(reader);
+            var documents = new List<RawBsonDocument>();
+            while (stream.Position < payloadEndPosition)
+            {
+                var document = serializer.Deserialize(context);
+                documents.Add(document);
+            }
+            EnsurePayloadEndedAtEndPosition(stream, payloadEndPosition);
+            var batch = new BatchableSource<RawBsonDocument>(documents, canBeSplit: false);
+
+            return new Type1CommandMessageSection<RawBsonDocument>(identifier, batch, serializer, NoOpElementNameValidator.Instance, null, null);
+        }
+
+        private void WriteSection(BsonBinaryWriter writer, CommandMessageSection section, long messageStartPosition)
+        {
+            writer.BsonStream.WriteByte((byte)section.PayloadType);
+
+            switch (section.PayloadType)
+            {
+                case PayloadType.Type0:
+                    WriteType0Section(writer, (Type0CommandMessageSection)section);
+                    break;
+
+                case PayloadType.Type1:
+                    WriteType1Section(writer, (Type1CommandMessageSection)section, messageStartPosition);
+                    break;
+
+                default:
+                    throw new ArgumentException("Invalid payload type.", nameof(section));
+            }
+        }
+
+        private void WriteSections(BsonBinaryWriter writer, IEnumerable<CommandMessageSection> sections, long messageStartPosition)
+        {
+            foreach (var section in sections)
+            {
+                WriteSection(writer, section, messageStartPosition);
+            }
+        }
+
+        private void WriteType0Section(BsonBinaryWriter writer, Type0CommandMessageSection section)
+        {
+            var serializer = section.DocumentSerializer;
+            var context = BsonSerializationContext.CreateRoot(writer);
+            serializer.Serialize(context, section.Document);
+        }
+
+        private void WriteType1Section(BsonBinaryWriter writer, Type1CommandMessageSection section, long messageStartPosition)
+        {
+            var stream = writer.BsonStream;
+            var serializer = section.DocumentSerializer;
+            var context = BsonSerializationContext.CreateRoot(writer);
+            var maxMessageSize = MaxMessageSize;
+
+            var payloadStartPosition = stream.Position;
+            stream.WriteInt32(0); // size
+            stream.WriteCString(section.Identifier);
+
+            var batch = section.Documents;
+            var maxDocumentSize = section.MaxDocumentSize ?? writer.Settings.MaxDocumentSize;
+            writer.PushSettings(s => ((BsonBinaryWriterSettings)s).MaxDocumentSize = maxDocumentSize);
+            writer.PushElementNameValidator(section.ElementNameValidator);
+            try
+            {
+                var maxBatchCount = Math.Min(batch.Count, section.MaxBatchCount ?? int.MaxValue);
+                var processedCount = maxBatchCount;
+                for (var i = 0; i < maxBatchCount; i++)
+                {
+                    var documentStartPosition = stream.Position;
+                    var document = batch.Items[batch.Offset + i];
+                    serializer.Serialize(context, document);
+
+                    var messageSize = stream.Position - messageStartPosition;
+                    if (messageSize > maxMessageSize && batch.CanBeSplit)
+                    {
+                        stream.Position = documentStartPosition;
+                        stream.SetLength(documentStartPosition);
+                        processedCount = i;
+                        break;
+                    }
+                }
+                batch.SetProcessedCount(processedCount);
+            }
+            finally
+            {
+                writer.PopElementNameValidator();
+                writer.PopSettings();
+            }
+            stream.BackpatchSize(payloadStartPosition);
+        }
+
+        // nested types
+        private class PostProcessor : IMessageEncoderPostProcessor
+        {
+            // private fields
+            private readonly CommandMessage _message;
+            private readonly long _messageStartPosition;
+            private readonly BsonStream _stream;
+
+            // constructors
+            public PostProcessor(CommandMessage message, BsonStream stream, long messageStartPosition)
+            {
+                _message = message;
+                _stream = stream;
+                _messageStartPosition = messageStartPosition;
+            }
+
+            // public methods
+            public void ChangeWriteConcernFromW0ToW1()
+            {
+                ChangeMoreToComeFromTrueToFalse();
+                ChangeWFrom0To1();
+                _message.MoreToCome = false;
+            }
+
+            // private methods
+            private void ChangeMoreToComeFromTrueToFalse()
+            {
+                var flagsPosition = _messageStartPosition + 16;
+                _stream.Position = flagsPosition;
+                var flags = (OpMsgFlags)_stream.ReadInt32();
+                if ((flags & OpMsgFlags.MoreToCome) == 0)
+                {
+                    throw new InvalidOperationException("MoreToCome was not true.");
+                }
+                flags = flags & ~OpMsgFlags.MoreToCome;
+                _stream.Position = flagsPosition;
+                _stream.WriteInt32((int)flags);
+            }
+
+            private void ChangeWFrom0To1()
+            {
+                var wPosition = FindWPosition();
+                _stream.Position = wPosition;
+                var w = _stream.ReadInt32();
+                if (w != 0)
+                {
+                    throw new InvalidOperationException("w was not 0.");
+                }
+                _stream.Position = wPosition;
+                _stream.WriteInt32(1);
+            }
+
+            private long FindType0SectionPosition()
+            {
+                _stream.Position = _messageStartPosition;
+                var messageLength = _stream.ReadInt32();
+
+                _stream.Position = _messageStartPosition + 20;
+                var messageEndPosition = _messageStartPosition + messageLength;
+                while (_stream.Position < messageEndPosition)
+                {
+                    var sectionPosition = _stream.Position;
+
+                    var payloadType = (PayloadType)_stream.ReadByte();
+                    if (payloadType == PayloadType.Type0)
+                    {
+                        return sectionPosition;
+                    }
+                    else if (payloadType != PayloadType.Type1)
+                    {
+                        throw new FormatException($"Invalid payload type: {payloadType}.");
+                    }
+
+                    var sectionSize = _stream.ReadInt32();
+                    _stream.Position = sectionPosition + 1 + sectionSize;
+                }
+
+                throw new InvalidOperationException("No type 0 section found.");
+            }
+
+            private long FindWPosition()
+            {
+                var type0SectionPosition = FindType0SectionPosition();
+
+                _stream.Position = type0SectionPosition + 1;
+                using (var reader = new BsonBinaryReader(_stream))
+                {
+                    reader.ReadStartDocument();
+                    while (reader.ReadBsonType() != 0)
+                    {
+                        if (reader.ReadName() == "writeConcern")
+                        {
+                            reader.ReadStartDocument();
+                            while (reader.ReadBsonType() != 0)
+                            {
+                                if (reader.ReadName() == "w")
+                                {
+                                    if (reader.CurrentBsonType == BsonType.Int32)
+                                    {
+                                        return _stream.Position;
+                                    }
+                                    goto notFound;
+                                }
+
+                                reader.SkipValue();
+                            }
+                            goto notFound;
+                        }
+
+                        reader.SkipValue();
+                    }
+                }
+
+                notFound:
+                throw new InvalidOperationException("{ w : <Int32> } not found.");
+            }
+
+        }
+    }
+}

+ 73 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandRequestMessageBinaryEncoder.cs

@@ -0,0 +1,73 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.IO;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders
+{
+    /// <summary>
+    /// Represents a binary encoder for a CommandRequestMessage.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.Encoders.IMessageEncoder" />
+    public class CommandRequestMessageBinaryEncoder : IMessageEncoder
+    {
+        // private fields
+        private readonly CommandMessageBinaryEncoder _wrappedEncoder;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CommandRequestMessageBinaryEncoder" /> class.
+        /// </summary>
+        /// <param name="wrappedEncoder">The wrapped encoder.</param>
+        public CommandRequestMessageBinaryEncoder(CommandMessageBinaryEncoder wrappedEncoder)
+        {
+            _wrappedEncoder = Ensure.IsNotNull(wrappedEncoder, nameof(wrappedEncoder));
+        }
+
+        // public methods
+        /// <summary>
+        /// Reads the message.
+        /// </summary>
+        /// <returns>A message.</returns>
+        public CommandRequestMessage ReadMessage()
+        {
+            var wrappedMessage = (CommandMessage)_wrappedEncoder.ReadMessage();
+            return new CommandRequestMessage(wrappedMessage, null);
+        }
+
+        /// <summary>
+        /// Writes the message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void WriteMessage(CommandRequestMessage message)
+        {
+            var wrappedMessage = message.WrappedMessage;
+            _wrappedEncoder.WriteMessage(wrappedMessage);
+        }
+
+        // explicit interface implementations
+        MongoDBMessage IMessageEncoder.ReadMessage()
+        {
+            return ReadMessage();
+        }
+
+        void IMessageEncoder.WriteMessage(MongoDBMessage message)
+        {
+            WriteMessage((CommandRequestMessage)message);
+        }
+    }
+}

+ 71 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandResponseMessageBinaryEncoder.cs

@@ -0,0 +1,71 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders
+{
+    /// <summary>
+    /// Represents a binary encoder for a CommandResponseMessage.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.Encoders.IMessageEncoder" />
+    public class CommandResponseMessageBinaryEncoder : IMessageEncoder
+    {
+        // private fields
+        private readonly CommandMessageBinaryEncoder _wrappedEncoder;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CommandResponseMessageBinaryEncoder" /> class.
+        /// </summary>
+        /// <param name="wrappedEncoder">The wrapped encoder.</param>
+        public CommandResponseMessageBinaryEncoder(CommandMessageBinaryEncoder wrappedEncoder)
+        {
+            _wrappedEncoder = Ensure.IsNotNull(wrappedEncoder, nameof(wrappedEncoder));
+        }
+
+        // public methods
+        /// <summary>
+        /// Reads the message.
+        /// </summary>
+        /// <returns>A message.</returns>
+        public CommandResponseMessage ReadMessage()
+        {
+            var wrappedMessage = (CommandMessage)_wrappedEncoder.ReadMessage();
+            return new CommandResponseMessage(wrappedMessage);
+        }
+
+        /// <summary>
+        /// Writes the message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void WriteMessage(CommandResponseMessage message)
+        {
+            var wrappedMessage = message.WrappedMessage;
+            _wrappedEncoder.WriteMessage(wrappedMessage);
+        }
+
+        // explicit interface implementations
+        MongoDBMessage IMessageEncoder.ReadMessage()
+        {
+            return ReadMessage();
+        }
+
+        void IMessageEncoder.WriteMessage(MongoDBMessage message)
+        {
+            WriteMessage((CommandResponseMessage)message);
+        }
+    }
+}

+ 12 - 8
Server/ThirdParty/MongodbDriver/MongoDB.Shared/GlobalAssemblyInfo.cs → Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/BinaryEncoders/OpMsgFlags.cs

@@ -1,4 +1,4 @@
-/* Copyright 2015-2017 MongoDB Inc.
+/* Copyright 2018-present MongoDB Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -13,11 +13,15 @@
 * limitations under the License.
 */
 
-using System.Reflection;
+using System;
 
-[assembly: AssemblyCompany("MongoDB Inc.")]
-[assembly: AssemblyVersion("0.0.0.*")]
-[assembly: AssemblyFileVersion("0.0.0.0")]
-[assembly: AssemblyInformationalVersion("0.0.0-unofficial")]
-[assembly: AssemblyCopyright("Copyright © 2010-2017 MongoDB Inc.")]
-[assembly: AssemblyConfiguration("Debug")]
+namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders
+{
+    [Flags]
+    internal enum OpMsgFlags
+    {
+        ChecksumPresent = 1,
+        MoreToCome = 2,
+        All = 3
+    }
+}

+ 30 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/CommandResponseMessageEncoderSelector.cs

@@ -0,0 +1,30 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders
+{
+    /// <summary>
+    /// Represents a message encoder selector for CommandResponseMessages.
+    /// </summary>
+    public class CommandResponseMessageEncoderSelector : IMessageEncoderSelector
+    {
+        // public methods        
+        /// <inheritdoc />
+        public IMessageEncoder GetEncoder(IMessageEncoderFactory encoderFactory)
+        {
+            return encoderFactory.GetCommandResponseMessageEncoder();
+        }
+    }
+}

+ 28 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/IMessageEncoderPostProcessor.cs

@@ -0,0 +1,28 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders
+{
+    /// <summary>
+    /// Represents the changes that can be made to a message after it has been encoded.
+    /// </summary>
+    public interface IMessageEncoderPostProcessor
+    {
+        /// <summary>
+        /// Changes the write concern from w0 to w1.
+        /// </summary>
+        void ChangeWriteConcernFromW0ToW1();
+    }
+}

+ 202 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandMessageJsonEncoder.cs

@@ -0,0 +1,202 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.JsonEncoders
+{
+    /// <summary>
+    /// Represents a JSON encoder for a CommandMessage.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.Encoders.JsonEncoders.MessageJsonEncoderBase" />
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.Encoders.IMessageEncoder" />
+    public class CommandMessageJsonEncoder : MessageJsonEncoderBase, IMessageEncoder
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CommandMessageJsonEncoder"/> class.
+        /// </summary>
+        /// <param name="textReader">The text reader.</param>
+        /// <param name="textWriter">The text writer.</param>
+        /// <param name="encoderSettings">The encoder settings.</param>
+        public CommandMessageJsonEncoder(TextReader textReader, TextWriter textWriter, MessageEncoderSettings encoderSettings)
+            : base(textReader, textWriter, encoderSettings)
+        {
+        }
+
+        // public methods
+        /// <summary>
+        /// Reads the message.
+        /// </summary>
+        /// <returns>A message.</returns>
+        public CommandMessage ReadMessage()
+        {
+            var reader = CreateJsonReader();
+            var context = BsonDeserializationContext.CreateRoot(reader);
+            var messageDocument = BsonDocumentSerializer.Instance.Deserialize(context);
+
+            var opcode = messageDocument["opcode"].AsString;
+            if (opcode != "opmsg")
+            {
+                throw new FormatException($"Command message invalid opcode: \"{opcode}\".");
+            }
+            var requestId = messageDocument["requestId"].ToInt32();
+            var responseTo = messageDocument["responseTo"].ToInt32();
+            var moreToCome = messageDocument.GetValue("moreToCome", false).ToBoolean();
+            var sections = ReadSections(messageDocument["sections"].AsBsonArray.Cast<BsonDocument>());
+
+            return new CommandMessage(requestId, responseTo, sections, moreToCome);
+        }
+
+        /// <summary>
+        /// Writes the message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void WriteMessage(CommandMessage message)
+        {
+            Ensure.IsNotNull(message, nameof(message));
+
+            var writer = CreateJsonWriter();
+
+            writer.WriteStartDocument();
+            writer.WriteString("opcode", "opmsg");
+            writer.WriteInt32("requestId", message.RequestId);
+            writer.WriteInt32("responseTo", message.ResponseTo);
+            if (message.MoreToCome)
+            {
+                writer.WriteBoolean("moreToCome", true);
+            }
+            writer.WriteName("sections");
+            WriteSections(writer, message.Sections);
+            writer.WriteEndDocument();
+        }
+
+        // explicit interface implementations
+        MongoDBMessage IMessageEncoder.ReadMessage()
+        {
+            return ReadMessage();
+        }
+
+        void IMessageEncoder.WriteMessage(MongoDBMessage message)
+        {
+            WriteMessage((CommandMessage)message);
+        }
+
+        // private methods
+        private CommandMessageSection ReadSection(BsonDocument sectionDocument)
+        {
+            var payloadType = sectionDocument["payloadType"].ToInt32();
+            switch (payloadType)
+            {
+                case 0:
+                    return ReadType0Section(sectionDocument);
+
+                case 1:
+                    return ReadType1Section(sectionDocument);
+
+                default:
+                    throw new FormatException($"Command message invalid payload type: {payloadType}.");
+            }
+        }
+
+        private IEnumerable<CommandMessageSection> ReadSections(IEnumerable<BsonDocument> sectionDocuments)
+        {
+            var sections = new List<CommandMessageSection>();
+            foreach (var sectionDocument in sectionDocuments)
+            {
+                var section = ReadSection(sectionDocument);
+                sections.Add(section);
+            }
+            return sections;
+        }
+
+        private CommandMessageSection ReadType0Section(BsonDocument sectionDocument)
+        {
+            var document = sectionDocument["document"].AsBsonDocument;
+            return new Type0CommandMessageSection<BsonDocument>(document, BsonDocumentSerializer.Instance);
+        }
+
+        private CommandMessageSection ReadType1Section(BsonDocument sectionDocument)
+        {
+            var identifier = sectionDocument["identifier"].AsString;
+            var documents = sectionDocument["documents"].AsBsonArray.Cast<BsonDocument>().ToList();
+            var batch = new BatchableSource<BsonDocument>(documents, canBeSplit: false);
+            return new Type1CommandMessageSection<BsonDocument>(identifier, batch, BsonDocumentSerializer.Instance, NoOpElementNameValidator.Instance, null, null);
+        }
+
+        private void WriteSection(IBsonWriter writer, CommandMessageSection section)
+        {
+            writer.WriteStartDocument();
+            writer.WriteInt32("payloadType", (int)section.PayloadType);
+
+            switch (section.PayloadType)
+            {
+                case PayloadType.Type0:
+                    WriteType0Section(writer, (Type0CommandMessageSection)section);
+                    break;
+
+                case PayloadType.Type1:
+                    WriteType1Section(writer, (Type1CommandMessageSection)section);
+                    break;
+
+                default:
+                    throw new ArgumentException($"Invalid payload type: {section.PayloadType}.");
+            }
+
+            writer.WriteEndDocument();
+        }
+
+        private void WriteSections(IBsonWriter writer, IEnumerable<CommandMessageSection> sections)
+        {
+            writer.WriteStartArray();
+            foreach (var section in sections)
+            {
+                WriteSection(writer, section);
+            }
+            writer.WriteEndArray();
+        }
+
+        private void WriteType0Section(IBsonWriter writer, Type0CommandMessageSection section)
+        {
+            writer.WriteName("document");
+            var serializer = section.DocumentSerializer;
+            var context = BsonSerializationContext.CreateRoot(writer);
+            serializer.Serialize(context, section.Document);
+        }
+
+        private void WriteType1Section(IBsonWriter writer, Type1CommandMessageSection section)
+        {
+            writer.WriteString("identifier", section.Identifier);
+            writer.WriteName("documents");
+            writer.WriteStartArray();
+            var batch = section.Documents;
+            var serializer = section.DocumentSerializer;
+            var context = BsonSerializationContext.CreateRoot(writer);
+            for (var i = 0; i < batch.Count; i++)
+            {
+                var document = batch.Items[batch.Offset + i];
+                serializer.Serialize(context, document);
+            }
+            writer.WriteEndArray();
+        }
+    }
+}

+ 71 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandRequestMessageJsonEncoder.cs

@@ -0,0 +1,71 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.JsonEncoders
+{
+    /// <summary>
+    /// Represents a Json encoder for a CommandRequestMessage.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.Encoders.IMessageEncoder" />
+    public class CommandRequestMessageJsonEncoder : IMessageEncoder
+    {
+        // private fields
+        private readonly CommandMessageJsonEncoder _wrappedEncoder;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CommandRequestMessageJsonEncoder" /> class.
+        /// </summary>
+        /// <param name="wrappedEncoder">The wrapped encoder.</param>
+        public CommandRequestMessageJsonEncoder(CommandMessageJsonEncoder wrappedEncoder)
+        {
+            _wrappedEncoder = Ensure.IsNotNull(wrappedEncoder, nameof(wrappedEncoder));
+        }
+
+        // public methods
+        /// <summary>
+        /// Reads the message.
+        /// </summary>
+        /// <returns>A message.</returns>
+        public CommandRequestMessage ReadMessage()
+        {
+            var wrappedMessage = (CommandMessage)_wrappedEncoder.ReadMessage();
+            return new CommandRequestMessage(wrappedMessage, null);
+        }
+
+        /// <summary>
+        /// Writes the message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void WriteMessage(CommandRequestMessage message)
+        {
+            var wrappedMessage = message.WrappedMessage;
+            _wrappedEncoder.WriteMessage(wrappedMessage);
+        }
+
+        // explicit interface implementations
+        MongoDBMessage IMessageEncoder.ReadMessage()
+        {
+            return ReadMessage();
+        }
+
+        void IMessageEncoder.WriteMessage(MongoDBMessage message)
+        {
+            WriteMessage((CommandRequestMessage)message);
+        }
+    }
+}

+ 71 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandResponseMessageJsonEncoder.cs

@@ -0,0 +1,71 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.JsonEncoders
+{
+    /// <summary>
+    /// Represents a Json encoder for a CommandResponseMessage.
+    /// </summary>
+    /// <seealso cref="MongoDB.Driver.Core.WireProtocol.Messages.Encoders.IMessageEncoder" />
+    public class CommandResponseMessageJsonEncoder : IMessageEncoder
+    {
+        // private fields
+        private readonly CommandMessageJsonEncoder _wrappedEncoder;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CommandResponseMessageJsonEncoder" /> class.
+        /// </summary>
+        /// <param name="wrappedEncoder">The wrapped encoder.</param>
+        public CommandResponseMessageJsonEncoder(CommandMessageJsonEncoder wrappedEncoder)
+        {
+            _wrappedEncoder = Ensure.IsNotNull(wrappedEncoder, nameof(wrappedEncoder));
+        }
+
+        // public methods
+        /// <summary>
+        /// Reads the message.
+        /// </summary>
+        /// <returns>A message.</returns>
+        public CommandResponseMessage ReadMessage()
+        {
+            var wrappedMessage = (CommandMessage)_wrappedEncoder.ReadMessage();
+            return new CommandResponseMessage(wrappedMessage);
+        }
+
+        /// <summary>
+        /// Writes the message.
+        /// </summary>
+        /// <param name="message">The message.</param>
+        public void WriteMessage(CommandResponseMessage message)
+        {
+            var wrappedMessage = message.WrappedMessage;
+            _wrappedEncoder.WriteMessage(wrappedMessage);
+        }
+
+        // explicit interface implementations
+        MongoDBMessage IMessageEncoder.ReadMessage()
+        {
+            return ReadMessage();
+        }
+
+        void IMessageEncoder.WriteMessage(MongoDBMessage message)
+        {
+            WriteMessage((CommandResponseMessage)message);
+        }
+    }
+}

+ 43 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/ServerErrorCode.cs

@@ -0,0 +1,43 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver
+{
+    internal enum ServerErrorCode
+    {
+        // this is not a complete list, more will be added as needed
+        // see: https://github.com/mongodb/mongo/blob/master/src/mongo/base/error_codes.err
+        CappedPositionLost = 136,
+        CursorKilled = 237,
+        ElectionInProgress = 216,
+        ExceededTimeLimit = 50,
+        HostNotFound = 7,
+        HostUnreachable = 6,
+        Interrupted = 11601,
+        InterruptedAtShutdown = 11600,
+        InterruptedDueToReplStateChange = 11602,
+        NetworkTimeout = 89,
+        NotMaster = 10107,
+        NotMasterNoSlaveOk = 13435,
+        NotMasterOrSecondary = 13436,
+        PrimarySteppedDown = 189,
+        RetryChangeStream = 234,
+        ShutdownInProgress = 91,
+        SocketException = 9001,
+        UnknownReplWriteConcern = 79,
+        UnsatisfiableWriteConcern = 100,
+        WriteConcernFailed = 64
+    }
+}

+ 98 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.Core/TransactionOptions.cs

@@ -0,0 +1,98 @@
+/* Copyright 2018-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+
+namespace MongoDB.Driver
+{
+    /// <summary>
+    /// Transaction options.
+    /// </summary>
+    public class TransactionOptions
+    {
+        // private fields
+        private readonly ReadConcern _readConcern;
+        private readonly ReadPreference _readPreference;
+        private readonly WriteConcern _writeConcern;
+
+        // public constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TransactionOptions" /> class.
+        /// </summary>
+        /// <param name="readConcern">The read concern.</param>
+        /// <param name="readPreference">The read preference.</param>
+        /// <param name="writeConcern">The write concern.</param>
+        public TransactionOptions(
+            Optional<ReadConcern> readConcern = default(Optional<ReadConcern>),
+            Optional<ReadPreference> readPreference = default(Optional<ReadPreference>),
+            Optional<WriteConcern> writeConcern = default(Optional<WriteConcern>))
+        {
+            _readConcern = readConcern.WithDefault(null);
+            _readPreference = readPreference.WithDefault(null);
+            _writeConcern = writeConcern.WithDefault(null);
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the read concern.
+        /// </summary>
+        /// <value>
+        /// The read concern.
+        /// </value>
+        public ReadConcern ReadConcern => _readConcern;
+
+        /// <summary>
+        /// Gets the read preference.
+        /// </summary>
+        /// <value>
+        /// The read preference.
+        /// </value>
+        public ReadPreference ReadPreference => _readPreference;
+
+        /// <summary>
+        /// Gets the write concern.
+        /// </summary>
+        /// <value>
+        /// The write concern.
+        /// </value>
+        public WriteConcern WriteConcern => _writeConcern;
+
+        // public methods
+        /// <summary>
+        /// Returns a new TransactionOptions with some values changed.
+        /// </summary>
+        /// <param name="readConcern">The new read concern.</param>
+        /// <param name="readPreference">The read preference.</param>
+        /// <param name="writeConcern">The new write concern.</param>
+        /// <returns>
+        /// The new TransactionOptions.
+        /// </returns>
+        public TransactionOptions With(
+            Optional<ReadConcern> readConcern = default(Optional<ReadConcern>),
+            Optional<ReadPreference> readPreference = default(Optional<ReadPreference>),
+            Optional<WriteConcern> writeConcern = default(Optional<WriteConcern>))
+        {
+            return new TransactionOptions(
+                readConcern: readConcern.WithDefault(_readConcern),
+                readPreference: readPreference.WithDefault(_readPreference),
+                writeConcern: writeConcern.WithDefault(_writeConcern));
+        }
+    }
+}

+ 266 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/DelegatingStream.cs

@@ -0,0 +1,266 @@
+/* Copyright 2016-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.IO;
+#if NET452
+using System.Runtime.Remoting;
+#endif
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents a Stream that delegates all of its operations to a wrapped Stream.
+    /// </summary>
+    /// <seealso cref="System.IO.Stream" />
+    public class DelegatingStream : Stream
+    {
+        // private fields
+        private readonly Stream _wrappedStream;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DelegatingStream"/> class.
+        /// </summary>
+        /// <param name="wrappedStream">The wrapped stream.</param>
+        internal DelegatingStream(Stream wrappedStream)
+        {
+            _wrappedStream = wrappedStream;
+        }
+
+        // properties        
+        /// <inheritdoc/>
+        public override bool CanRead
+        {
+            get { return _wrappedStream.CanRead; }
+        }
+
+        /// <inheritdoc/>
+        public override bool CanSeek
+        {
+            get { return _wrappedStream.CanSeek; }
+        }
+
+        /// <inheritdoc/>
+        public override bool CanTimeout
+        {
+            get { return _wrappedStream.CanTimeout; }
+        }
+
+        /// <inheritdoc/>
+        public override bool CanWrite
+        {
+            get { return _wrappedStream.CanWrite; }
+        }
+
+        /// <inheritdoc/>
+        public override long Length
+        {
+            get { return _wrappedStream.Length; }
+        }
+
+        /// <inheritdoc/>
+        public override long Position
+        {
+            get { return _wrappedStream.Position; }
+            set { _wrappedStream.Position = value; }
+        }
+
+        /// <inheritdoc/>
+        public override int ReadTimeout
+        {
+            get { return _wrappedStream.ReadTimeout; }
+            set { _wrappedStream.ReadTimeout = value; }
+        }
+
+        /// <inheritdoc/>
+        public override int WriteTimeout
+        {
+            get { return _wrappedStream.WriteTimeout; }
+            set { _wrappedStream.WriteTimeout = value; }
+        }
+
+        // methods
+#if NET452
+        /// <inheritdoc/>
+        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        {
+            return _wrappedStream.BeginRead(buffer, offset, count, callback, state);
+        }
+#endif
+
+#if NET452
+        /// <inheritdoc/>
+        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        {
+            return _wrappedStream.BeginWrite(buffer, offset, count, callback, state);
+        }
+#endif
+
+#if NET452
+        /// <inheritdoc/>
+        public override void Close()
+        {
+            _wrappedStream.Close();
+        }
+#endif
+
+        /// <inheritdoc/>
+        public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
+        {
+            return _wrappedStream.CopyToAsync(destination, bufferSize, cancellationToken);
+        }
+
+ #if NET452
+       /// <inheritdoc/>
+        public override ObjRef CreateObjRef(Type requestedType)
+        {
+            return _wrappedStream.CreateObjRef(requestedType);
+        }
+#endif
+
+#if NET452
+        /// <inheritdoc/>
+        [Obsolete("Not supported by DelegatingStream.")]
+        protected override WaitHandle CreateWaitHandle()
+        {
+            throw new NotSupportedException();
+        }
+#endif
+
+        /// <inheritdoc/>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                _wrappedStream.Dispose();
+            }
+        }
+
+#if NET452
+        /// <inheritdoc/>
+        public override int EndRead(IAsyncResult asyncResult)
+        {
+            return _wrappedStream.EndRead(asyncResult);
+        }
+#endif
+
+#if NET452
+        /// <inheritdoc/>
+        public override void EndWrite(IAsyncResult asyncResult)
+        {
+            _wrappedStream.EndWrite(asyncResult);
+        }
+#endif
+
+        /// <inheritdoc/>
+        public override bool Equals(object obj)
+        {
+            return _wrappedStream.Equals(obj);
+        }
+
+        /// <inheritdoc/>
+        public override void Flush()
+        {
+            _wrappedStream.Flush();
+        }
+
+        /// <inheritdoc/>
+        public override Task FlushAsync(CancellationToken cancellationToken)
+        {
+            return _wrappedStream.FlushAsync(cancellationToken);
+        }
+
+        /// <inheritdoc/>
+        public override int GetHashCode()
+        {
+            return _wrappedStream.GetHashCode();
+        }
+
+ #if NET452
+       /// <inheritdoc/>
+        public override object InitializeLifetimeService()
+        {
+            return _wrappedStream.InitializeLifetimeService();
+        }
+#endif
+
+#if NET452
+        /// <inheritdoc/>
+        [Obsolete("Not supported by DelegatingStream.")]
+        protected override void ObjectInvariant()
+        {
+            throw new NotSupportedException();
+        }
+#endif
+
+        /// <inheritdoc/>
+        public override int Read(byte[] buffer, int offset, int count)
+
+        {
+            return _wrappedStream.Read(buffer, offset, count);
+        }
+
+        /// <inheritdoc/>
+        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            return _wrappedStream.ReadAsync(buffer, offset, count, cancellationToken);
+        }
+
+        /// <inheritdoc/>
+        public override int ReadByte()
+        {
+            return _wrappedStream.ReadByte();
+        }
+
+        /// <inheritdoc/>
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            return _wrappedStream.Seek(offset, origin);
+        }
+
+        /// <inheritdoc/>
+        public override void SetLength(long value)
+        {
+            _wrappedStream.SetLength(value);
+        }
+
+        /// <inheritdoc/>
+        public override string ToString()
+        {
+            return _wrappedStream.ToString();
+        }
+
+        /// <inheritdoc/>
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            _wrappedStream.Write(buffer, offset, count);
+        }
+
+        /// <inheritdoc/>
+        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            return _wrappedStream.WriteAsync(buffer, offset, count, cancellationToken);
+        }
+
+        /// <inheritdoc/>
+        public override void WriteByte(byte value)
+        {
+            _wrappedStream.WriteByte(value);
+        }
+    }
+}

+ 1027 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSBucket.cs

@@ -0,0 +1,1027 @@
+/* Copyright 2016-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Bindings;
+using MongoDB.Driver.Core.Clusters;
+using MongoDB.Driver.Core.Clusters.ServerSelectors;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.Operations;
+using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents a GridFS bucket.
+    /// </summary>
+    /// <typeparam name="TFileId">The type of the file identifier.</typeparam>
+    [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")] // we can get away with not calling Dispose on our SemaphoreSlim
+    public class GridFSBucket<TFileId> : IGridFSBucket<TFileId>
+    {
+        // fields
+        private readonly ICluster _cluster;
+        private readonly IMongoDatabase _database;
+        private bool _ensureIndexesDone;
+        private SemaphoreSlim _ensureIndexesSemaphore = new SemaphoreSlim(1);
+        private readonly IBsonSerializer<GridFSFileInfo<TFileId>> _fileInfoSerializer;
+        private readonly BsonSerializationInfo _idSerializationInfo;
+        private readonly ImmutableGridFSBucketOptions _options;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSBucket" /> class.
+        /// </summary>
+        /// <param name="database">The database.</param>
+        /// <param name="options">The options.</param>
+        public GridFSBucket(IMongoDatabase database, GridFSBucketOptions options = null)
+        {
+            _database = Ensure.IsNotNull(database, nameof(database));
+            _options = options == null ? ImmutableGridFSBucketOptions.Defaults : new ImmutableGridFSBucketOptions(options);
+
+            _cluster = database.Client.Cluster;
+
+            var idSerializer = _options.SerializerRegistry.GetSerializer<TFileId>();
+            _idSerializationInfo = new BsonSerializationInfo("_id", idSerializer, typeof(TFileId));
+            _fileInfoSerializer = new GridFSFileInfoSerializer<TFileId>(idSerializer);
+        }
+
+        // properties
+        /// <inheritdoc />
+        public IMongoDatabase Database
+        {
+            get { return _database; }
+        }
+
+        /// <inheritdoc />
+        public ImmutableGridFSBucketOptions Options
+        {
+            get { return _options; }
+        }
+
+        // methods
+        /// <inheritdoc />
+        public void Delete(TFileId id, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            using (var binding = GetSingleServerReadWriteBinding(cancellationToken))
+            {
+                var filesCollectionDeleteOperation = CreateDeleteFileOperation(id);
+                var filesCollectionDeleteResult = filesCollectionDeleteOperation.Execute(binding, cancellationToken);
+
+                var chunksDeleteOperation = CreateDeleteChunksOperation(id);
+                chunksDeleteOperation.Execute(binding, cancellationToken);
+
+                if (filesCollectionDeleteResult.DeletedCount == 0)
+                {
+                    throw new GridFSFileNotFoundException(_idSerializationInfo.SerializeValue(id));
+                }
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task DeleteAsync(TFileId id, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            using (var binding = await GetSingleServerReadWriteBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                var filesCollectionDeleteOperation = CreateDeleteFileOperation(id);
+                var filesCollectionDeleteResult = await filesCollectionDeleteOperation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+
+                var chunksDeleteOperation = CreateDeleteChunksOperation(id);
+                await chunksDeleteOperation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+
+                if (filesCollectionDeleteResult.DeletedCount == 0)
+                {
+                    throw new GridFSFileNotFoundException(_idSerializationInfo.SerializeValue(id));
+                }
+            }
+        }
+
+        /// <inheritdoc />
+        public byte[] DownloadAsBytes(TFileId id, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            options = options ?? new GridFSDownloadOptions();
+            using (var binding = GetSingleServerReadBinding(cancellationToken))
+            {
+                var fileInfo = GetFileInfo(binding, id, cancellationToken);
+                return DownloadAsBytesHelper(binding, fileInfo, options, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task<byte[]> DownloadAsBytesAsync(TFileId id, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            options = options ?? new GridFSDownloadOptions();
+            using (var binding = await GetSingleServerReadBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                var fileInfo = await GetFileInfoAsync(binding, id, cancellationToken).ConfigureAwait(false);
+                return await DownloadAsBytesHelperAsync(binding, fileInfo, options, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        public byte[] DownloadAsBytesByName(string filename, GridFSDownloadByNameOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull(filename, nameof(filename));
+            options = options ?? new GridFSDownloadByNameOptions();
+
+            using (var binding = GetSingleServerReadBinding(cancellationToken))
+            {
+                var fileInfo = GetFileInfoByName(binding, filename, options.Revision, cancellationToken);
+                return DownloadAsBytesHelper(binding, fileInfo, options, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task<byte[]> DownloadAsBytesByNameAsync(string filename, GridFSDownloadByNameOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull(filename, nameof(filename));
+            options = options ?? new GridFSDownloadByNameOptions();
+
+            using (var binding = await GetSingleServerReadBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                var fileInfo = await GetFileInfoByNameAsync(binding, filename, options.Revision, cancellationToken).ConfigureAwait(false);
+                return await DownloadAsBytesHelperAsync(binding, fileInfo, options, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        public void DownloadToStream(TFileId id, Stream destination, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            Ensure.IsNotNull(destination, nameof(destination));
+            options = options ?? new GridFSDownloadOptions();
+            using (var binding = GetSingleServerReadBinding(cancellationToken))
+            {
+                var fileInfo = GetFileInfo(binding, id, cancellationToken);
+                DownloadToStreamHelper(binding, fileInfo, destination, options, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task DownloadToStreamAsync(TFileId id, Stream destination, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            Ensure.IsNotNull(destination, nameof(destination));
+            options = options ?? new GridFSDownloadOptions();
+            using (var binding = await GetSingleServerReadBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                var fileInfo = await GetFileInfoAsync(binding, id, cancellationToken).ConfigureAwait(false);
+                await DownloadToStreamHelperAsync(binding, fileInfo, destination, options, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        public void DownloadToStreamByName(string filename, Stream destination, GridFSDownloadByNameOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull(filename, nameof(filename));
+            Ensure.IsNotNull(destination, nameof(destination));
+            options = options ?? new GridFSDownloadByNameOptions();
+
+            using (var binding = GetSingleServerReadBinding(cancellationToken))
+            {
+                var fileInfo = GetFileInfoByName(binding, filename, options.Revision, cancellationToken);
+                DownloadToStreamHelper(binding, fileInfo, destination, options, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task DownloadToStreamByNameAsync(string filename, Stream destination, GridFSDownloadByNameOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull(filename, nameof(filename));
+            Ensure.IsNotNull(destination, nameof(destination));
+            options = options ?? new GridFSDownloadByNameOptions();
+
+            using (var binding = await GetSingleServerReadBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                var fileInfo = await GetFileInfoByNameAsync(binding, filename, options.Revision, cancellationToken).ConfigureAwait(false);
+                await DownloadToStreamHelperAsync(binding, fileInfo, destination, options, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        public void Drop(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var filesCollectionNamespace = this.GetFilesCollectionNamespace();
+            var chunksCollectionNamespace = this.GetChunksCollectionNamespace();
+            var messageEncoderSettings = this.GetMessageEncoderSettings();
+
+            using (var binding = GetSingleServerReadWriteBinding(cancellationToken))
+            {
+                var filesCollectionDropOperation = CreateDropCollectionOperation(filesCollectionNamespace, messageEncoderSettings);
+                filesCollectionDropOperation.Execute(binding, cancellationToken);
+
+                var chunksCollectionDropOperation = CreateDropCollectionOperation(chunksCollectionNamespace, messageEncoderSettings);
+                chunksCollectionDropOperation.Execute(binding, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task DropAsync(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var filesCollectionNamespace = this.GetFilesCollectionNamespace();
+            var chunksCollectionNamespace = this.GetChunksCollectionNamespace();
+            var messageEncoderSettings = this.GetMessageEncoderSettings();
+
+            using (var binding = await GetSingleServerReadWriteBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                var filesCollectionDropOperation = CreateDropCollectionOperation(filesCollectionNamespace, messageEncoderSettings);
+                await filesCollectionDropOperation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+
+                var chunksCollectionDropOperation = CreateDropCollectionOperation(chunksCollectionNamespace, messageEncoderSettings);
+                await chunksCollectionDropOperation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        public IAsyncCursor<GridFSFileInfo<TFileId>> Find(FilterDefinition<GridFSFileInfo<TFileId>> filter, GridFSFindOptions<TFileId> options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull(filter, nameof(filter));
+            options = options ?? new GridFSFindOptions<TFileId>();
+
+            var operation = CreateFindOperation(filter, options);
+            using (var binding = GetSingleServerReadBinding(cancellationToken))
+            {
+                return operation.Execute(binding, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task<IAsyncCursor<GridFSFileInfo<TFileId>>> FindAsync(FilterDefinition<GridFSFileInfo<TFileId>> filter, GridFSFindOptions<TFileId> options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull(filter, nameof(filter));
+            options = options ?? new GridFSFindOptions<TFileId>();
+
+            var operation = CreateFindOperation(filter, options);
+            using (var binding = await GetSingleServerReadBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                return await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        public GridFSDownloadStream<TFileId> OpenDownloadStream(TFileId id, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            options = options ?? new GridFSDownloadOptions();
+            using (var binding = GetSingleServerReadBinding(cancellationToken))
+            {
+                var fileInfo = GetFileInfo(binding, id, cancellationToken);
+                return CreateDownloadStream(binding.Fork(), fileInfo, options, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task<GridFSDownloadStream<TFileId>> OpenDownloadStreamAsync(TFileId id, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            options = options ?? new GridFSDownloadOptions();
+            using (var binding = await GetSingleServerReadBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                var fileInfo = await GetFileInfoAsync(binding, id, cancellationToken).ConfigureAwait(false);
+                return CreateDownloadStream(binding.Fork(), fileInfo, options, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public GridFSDownloadStream<TFileId> OpenDownloadStreamByName(string filename, GridFSDownloadByNameOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull(filename, nameof(filename));
+            options = options ?? new GridFSDownloadByNameOptions();
+
+            using (var binding = GetSingleServerReadBinding(cancellationToken))
+            {
+                var fileInfo = GetFileInfoByName(binding, filename, options.Revision, cancellationToken);
+                return CreateDownloadStream(binding.Fork(), fileInfo, options);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task<GridFSDownloadStream<TFileId>> OpenDownloadStreamByNameAsync(string filename, GridFSDownloadByNameOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull(filename, nameof(filename));
+            options = options ?? new GridFSDownloadByNameOptions();
+
+            using (var binding = await GetSingleServerReadBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                var fileInfo = await GetFileInfoByNameAsync(binding, filename, options.Revision, cancellationToken).ConfigureAwait(false);
+                return CreateDownloadStream(binding.Fork(), fileInfo, options);
+            }
+        }
+
+        /// <inheritdoc />
+        public GridFSUploadStream<TFileId> OpenUploadStream(TFileId id, string filename, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            Ensure.IsNotNull(filename, nameof(filename));
+            options = options ?? new GridFSUploadOptions();
+
+            using (var binding = GetSingleServerReadWriteBinding(cancellationToken))
+            {
+                EnsureIndexes(binding, cancellationToken);
+                return CreateUploadStream(binding, id, filename, options);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task<GridFSUploadStream<TFileId>> OpenUploadStreamAsync(TFileId id, string filename, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            Ensure.IsNotNull(filename, nameof(filename));
+            options = options ?? new GridFSUploadOptions();
+
+            using (var binding = await GetSingleServerReadWriteBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                await EnsureIndexesAsync(binding, cancellationToken).ConfigureAwait(false);
+                return CreateUploadStream(binding, id, filename, options);
+            }
+        }
+
+        /// <inheritdoc />
+        public void Rename(TFileId id, string newFilename, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            Ensure.IsNotNull(newFilename, nameof(newFilename));
+            var renameOperation = CreateRenameOperation(id, newFilename);
+            using (var binding = GetSingleServerReadWriteBinding(cancellationToken))
+            {
+                var result = renameOperation.Execute(binding, cancellationToken);
+
+                if (result.IsModifiedCountAvailable && result.ModifiedCount == 0)
+                {
+                    throw new GridFSFileNotFoundException(_idSerializationInfo.SerializeValue(id));
+                }
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task RenameAsync(TFileId id, string newFilename, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            Ensure.IsNotNull(newFilename, nameof(newFilename));
+            var renameOperation = CreateRenameOperation(id, newFilename);
+            using (var binding = await GetSingleServerReadWriteBindingAsync(cancellationToken).ConfigureAwait(false))
+            {
+                var result = await renameOperation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+
+                if (result.IsModifiedCountAvailable && result.ModifiedCount == 0)
+                {
+                    throw new GridFSFileNotFoundException(_idSerializationInfo.SerializeValue(id));
+                }
+            }
+        }
+
+        /// <inheritdoc />
+        public void UploadFromBytes(TFileId id, string filename, byte[] source, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            Ensure.IsNotNull(filename, nameof(filename));
+            Ensure.IsNotNull(source, nameof(source));
+            options = options ?? new GridFSUploadOptions();
+
+            using (var sourceStream = new MemoryStream(source))
+            {
+                UploadFromStream(id, filename, sourceStream, options, cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task UploadFromBytesAsync(TFileId id, string filename, byte[] source, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            Ensure.IsNotNull(filename, nameof(filename));
+            Ensure.IsNotNull(source, nameof(source));
+            options = options ?? new GridFSUploadOptions();
+
+            using (var sourceStream = new MemoryStream(source))
+            {
+                await UploadFromStreamAsync(id, filename, sourceStream, options, cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        /// <inheritdoc />
+        public void UploadFromStream(TFileId id, string filename, Stream source, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            Ensure.IsNotNull(filename, nameof(filename));
+            Ensure.IsNotNull(source, nameof(source));
+            options = options ?? new GridFSUploadOptions();
+
+            using (var destination = OpenUploadStream(id, filename, options, cancellationToken))
+            {
+                var chunkSizeBytes = options.ChunkSizeBytes ?? _options.ChunkSizeBytes;
+                var buffer = new byte[chunkSizeBytes];
+
+                while (true)
+                {
+                    int bytesRead = 0;
+                    try
+                    {
+                        bytesRead = source.Read(buffer, 0, buffer.Length);
+                    }
+                    catch
+                    {
+                        try
+                        {
+                            destination.Abort();
+                        }
+                        catch
+                        {
+                            // ignore any exceptions because we're going to rethrow the original exception
+                        }
+                        throw;
+                    }
+                    if (bytesRead == 0)
+                    {
+                        break;
+                    }
+                    destination.Write(buffer, 0, bytesRead);
+                }
+
+                destination.Close(cancellationToken);
+            }
+        }
+
+        /// <inheritdoc />
+        public async Task UploadFromStreamAsync(TFileId id, string filename, Stream source, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull((object)id, nameof(id));
+            Ensure.IsNotNull(filename, nameof(filename));
+            Ensure.IsNotNull(source, nameof(source));
+            options = options ?? new GridFSUploadOptions();
+
+            using (var destination = await OpenUploadStreamAsync(id, filename, options, cancellationToken).ConfigureAwait(false))
+            {
+                var chunkSizeBytes = options.ChunkSizeBytes ?? _options.ChunkSizeBytes;
+                var buffer = new byte[chunkSizeBytes];
+
+                while (true)
+                {
+                    int bytesRead = 0;
+                    Exception sourceException = null;
+                    try
+                    {
+                        bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
+                    }
+                    catch (Exception ex)
+                    {
+                        // cannot await in the body of a catch clause
+                        sourceException = ex;
+                    }
+                    if (sourceException != null)
+                    {
+                        try
+                        {
+                            await destination.AbortAsync().ConfigureAwait(false);
+                        }
+                        catch
+                        {
+                            // ignore any exceptions because we're going to rethrow the original exception
+                        }
+                        throw sourceException;
+                    }
+                    if (bytesRead == 0)
+                    {
+                        break;
+                    }
+                    await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
+                }
+
+                await destination.CloseAsync(cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        // private methods
+        private bool ChunksCollectionIndexesExist(List<BsonDocument> indexes)
+        {
+            var key = new BsonDocument { { "files_id", 1 }, { "n", 1 } };
+            return IndexExists(indexes, key);
+        }
+
+        private bool ChunksCollectionIndexesExist(IReadBindingHandle binding, CancellationToken cancellationToken)
+        {
+            var indexes = ListIndexes(binding, this.GetChunksCollectionNamespace(), cancellationToken);
+            return ChunksCollectionIndexesExist(indexes);
+        }
+
+        private async Task<bool> ChunksCollectionIndexesExistAsync(IReadBindingHandle binding, CancellationToken cancellationToken)
+        {
+            var indexes = await ListIndexesAsync(binding, this.GetChunksCollectionNamespace(), cancellationToken).ConfigureAwait(false);
+            return ChunksCollectionIndexesExist(indexes);
+        }
+
+        private void CreateChunksCollectionIndexes(IReadWriteBindingHandle binding, CancellationToken cancellationToken)
+        {
+            var operation = CreateCreateChunksCollectionIndexesOperation();
+            operation.Execute(binding, cancellationToken);
+        }
+
+        private async Task CreateChunksCollectionIndexesAsync(IReadWriteBindingHandle binding, CancellationToken cancellationToken)
+        {
+            var operation = CreateCreateChunksCollectionIndexesOperation();
+            await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+        }
+
+        internal CreateIndexesOperation CreateCreateChunksCollectionIndexesOperation()
+        {
+            var collectionNamespace = this.GetChunksCollectionNamespace();
+            var requests = new[] { new CreateIndexRequest(new BsonDocument { { "files_id", 1 }, { "n", 1 } }) { Unique = true } };
+            var messageEncoderSettings = this.GetMessageEncoderSettings();
+            return new CreateIndexesOperation(collectionNamespace, requests, messageEncoderSettings)
+            {
+                WriteConcern = _options.WriteConcern ?? _database.Settings.WriteConcern
+            };
+        }
+
+        internal CreateIndexesOperation CreateCreateFilesCollectionIndexesOperation()
+        {
+            var collectionNamespace = this.GetFilesCollectionNamespace();
+            var requests = new[] { new CreateIndexRequest(new BsonDocument { { "filename", 1 }, { "uploadDate", 1 } }) };
+            var messageEncoderSettings = this.GetMessageEncoderSettings();
+            return new CreateIndexesOperation(collectionNamespace, requests, messageEncoderSettings)
+            {
+                WriteConcern = _options.WriteConcern ?? _database.Settings.WriteConcern
+            };
+        }
+
+        private BulkMixedWriteOperation CreateDeleteChunksOperation(TFileId id)
+        {
+            var filter = new BsonDocument("files_id", _idSerializationInfo.SerializeValue(id));
+            return new BulkMixedWriteOperation(
+                this.GetChunksCollectionNamespace(),
+                new[] { new DeleteRequest(filter) { Limit = 0 } },
+                this.GetMessageEncoderSettings());
+        }
+
+        private GridFSDownloadStream<TFileId> CreateDownloadStream(IReadBindingHandle binding, GridFSFileInfo<TFileId> fileInfo, GridFSDownloadOptions options, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var checkMD5 = options.CheckMD5 ?? false;
+            var seekable = options.Seekable ?? false;
+            if (checkMD5 && seekable)
+            {
+                throw new ArgumentException("CheckMD5 can only be used when Seekable is false.");
+            }
+
+            if (seekable)
+            {
+                return new GridFSSeekableDownloadStream<TFileId>(this, binding, fileInfo);
+            }
+            else
+            {
+                return new GridFSForwardOnlyDownloadStream<TFileId>(this, binding, fileInfo, checkMD5);
+            }
+        }
+
+        internal DropCollectionOperation CreateDropCollectionOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings)
+        {
+            return new DropCollectionOperation(collectionNamespace, messageEncoderSettings)
+            {
+                WriteConcern = _options.WriteConcern ?? _database.Settings.WriteConcern
+            };
+        }
+
+        private BulkMixedWriteOperation CreateDeleteFileOperation(TFileId id)
+        {
+            var filter = new BsonDocument("_id", _idSerializationInfo.SerializeValue(id));
+            return new BulkMixedWriteOperation(
+                this.GetFilesCollectionNamespace(),
+                new[] { new DeleteRequest(filter) },
+                this.GetMessageEncoderSettings());
+        }
+
+        private void CreateFilesCollectionIndexes(IReadWriteBindingHandle binding, CancellationToken cancellationToken)
+        {
+            var operation = CreateCreateFilesCollectionIndexesOperation();
+            operation.Execute(binding, cancellationToken);
+        }
+
+        private async Task CreateFilesCollectionIndexesAsync(IReadWriteBindingHandle binding, CancellationToken cancellationToken)
+        {
+            var operation = CreateCreateFilesCollectionIndexesOperation();
+            await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+        }
+
+        private FindOperation<GridFSFileInfo<TFileId>> CreateFindOperation(FilterDefinition<GridFSFileInfo<TFileId>> filter, GridFSFindOptions<TFileId> options)
+        {
+            var filesCollectionNamespace = this.GetFilesCollectionNamespace();
+            var messageEncoderSettings = this.GetMessageEncoderSettings();
+            var renderedFilter = filter.Render(_fileInfoSerializer, _options.SerializerRegistry);
+            var renderedSort = options.Sort == null ? null : options.Sort.Render(_fileInfoSerializer, _options.SerializerRegistry);
+
+            return new FindOperation<GridFSFileInfo<TFileId>>(
+                filesCollectionNamespace,
+                _fileInfoSerializer,
+                messageEncoderSettings)
+            {
+                BatchSize = options.BatchSize,
+                Filter = renderedFilter,
+                Limit = options.Limit,
+                MaxTime = options.MaxTime,
+                NoCursorTimeout = options.NoCursorTimeout ?? false,
+                ReadConcern = GetReadConcern(),
+                Skip = options.Skip,
+                Sort = renderedSort
+            };
+        }
+
+        private FindOperation<GridFSFileInfo<TFileId>> CreateGetFileInfoByNameOperation(string filename, int revision)
+        {
+            var collectionNamespace = this.GetFilesCollectionNamespace();
+            var messageEncoderSettings = this.GetMessageEncoderSettings();
+            var filter = new BsonDocument("filename", filename);
+            var skip = revision >= 0 ? revision : -revision - 1;
+            var limit = 1;
+            var sort = new BsonDocument("uploadDate", revision >= 0 ? 1 : -1);
+
+            return new FindOperation<GridFSFileInfo<TFileId>>(
+                collectionNamespace,
+                _fileInfoSerializer,
+                messageEncoderSettings)
+            {
+                Filter = filter,
+                Limit = limit,
+                ReadConcern = GetReadConcern(),
+                Skip = skip,
+                Sort = sort
+            };
+        }
+
+        private FindOperation<GridFSFileInfo<TFileId>> CreateGetFileInfoOperation(TFileId id)
+        {
+            var filesCollectionNamespace = this.GetFilesCollectionNamespace();
+            var messageEncoderSettings = this.GetMessageEncoderSettings();
+            var filter = new BsonDocument("_id", _idSerializationInfo.SerializeValue(id));
+
+            return new FindOperation<GridFSFileInfo<TFileId>>(
+                filesCollectionNamespace,
+                _fileInfoSerializer,
+                messageEncoderSettings)
+            {
+                Filter = filter,
+                Limit = 1,
+                ReadConcern = GetReadConcern(),
+                SingleBatch = true
+            };
+        }
+
+        private FindOperation<BsonDocument> CreateIsFilesCollectionEmptyOperation()
+        {
+            var filesCollectionNamespace = this.GetFilesCollectionNamespace();
+            var messageEncoderSettings = this.GetMessageEncoderSettings();
+            return new FindOperation<BsonDocument>(filesCollectionNamespace, BsonDocumentSerializer.Instance, messageEncoderSettings)
+            {
+                Limit = 1,
+                ReadConcern = GetReadConcern(),
+                SingleBatch = true,
+                Projection = new BsonDocument("_id", 1)
+            };
+        }
+
+        private ListIndexesOperation CreateListIndexesOperation(CollectionNamespace collectionNamespace)
+        {
+            var messageEncoderSettings = this.GetMessageEncoderSettings();
+            return new ListIndexesOperation(collectionNamespace, messageEncoderSettings);
+        }
+
+        private BulkMixedWriteOperation CreateRenameOperation(TFileId id, string newFilename)
+        {
+            var filesCollectionNamespace = this.GetFilesCollectionNamespace();
+            var filter = new BsonDocument("_id", _idSerializationInfo.SerializeValue(id));
+            var update = new BsonDocument("$set", new BsonDocument("filename", newFilename));
+            var requests = new[] { new UpdateRequest(UpdateType.Update, filter, update) };
+            var messageEncoderSettings = this.GetMessageEncoderSettings();
+            return new BulkMixedWriteOperation(filesCollectionNamespace, requests, messageEncoderSettings);
+        }
+
+        private GridFSUploadStream<TFileId> CreateUploadStream(IReadWriteBindingHandle binding, TFileId id, string filename, GridFSUploadOptions options)
+        {
+#pragma warning disable 618
+            var chunkSizeBytes = options.ChunkSizeBytes ?? _options.ChunkSizeBytes;
+            var batchSize = options.BatchSize ?? (16 * 1024 * 1024 / chunkSizeBytes);
+
+            return new GridFSForwardOnlyUploadStream<TFileId>(
+                this,
+                binding.Fork(),
+                id,
+                filename,
+                options.Metadata,
+                options.Aliases,
+                options.ContentType,
+                chunkSizeBytes,
+                batchSize,
+                options.DisableMD5);
+#pragma warning restore
+        }
+
+        private byte[] DownloadAsBytesHelper(IReadBindingHandle binding, GridFSFileInfo<TFileId> fileInfo, GridFSDownloadOptions options, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            if (fileInfo.Length > int.MaxValue)
+            {
+                throw new NotSupportedException("GridFS stored file is too large to be returned as a byte array.");
+            }
+
+            var bytes = new byte[(int)fileInfo.Length];
+            using (var destination = new MemoryStream(bytes))
+            {
+                DownloadToStreamHelper(binding, fileInfo, destination, options, cancellationToken);
+                return bytes;
+            }
+        }
+
+        private async Task<byte[]> DownloadAsBytesHelperAsync(IReadBindingHandle binding, GridFSFileInfo<TFileId> fileInfo, GridFSDownloadOptions options, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            if (fileInfo.Length > int.MaxValue)
+            {
+                throw new NotSupportedException("GridFS stored file is too large to be returned as a byte array.");
+            }
+
+            var bytes = new byte[(int)fileInfo.Length];
+            using (var destination = new MemoryStream(bytes))
+            {
+                await DownloadToStreamHelperAsync(binding, fileInfo, destination, options, cancellationToken).ConfigureAwait(false);
+                return bytes;
+            }
+        }
+
+        private void DownloadToStreamHelper(IReadBindingHandle binding, GridFSFileInfo<TFileId> fileInfo, Stream destination, GridFSDownloadOptions options, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var checkMD5 = options.CheckMD5 ?? false;
+
+            using (var source = new GridFSForwardOnlyDownloadStream<TFileId>(this, binding.Fork(), fileInfo, checkMD5))
+            {
+                var count = source.Length;
+                var buffer = new byte[fileInfo.ChunkSizeBytes];
+
+                while (count > 0)
+                {
+                    var partialCount = (int)Math.Min(buffer.Length, count);
+                    source.ReadBytes(buffer, 0, partialCount, cancellationToken);
+                    //((Stream)source).ReadBytes(buffer, 0, partialCount, cancellationToken);
+                    destination.Write(buffer, 0, partialCount);
+                    count -= partialCount;
+                }
+            }
+        }
+
+        private async Task DownloadToStreamHelperAsync(IReadBindingHandle binding, GridFSFileInfo<TFileId> fileInfo, Stream destination, GridFSDownloadOptions options, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var checkMD5 = options.CheckMD5 ?? false;
+
+            using (var source = new GridFSForwardOnlyDownloadStream<TFileId>(this, binding.Fork(), fileInfo, checkMD5))
+            {
+                var count = source.Length;
+                var buffer = new byte[fileInfo.ChunkSizeBytes];
+
+                while (count > 0)
+                {
+                    var partialCount = (int)Math.Min(buffer.Length, count);
+                    await source.ReadBytesAsync(buffer, 0, partialCount, cancellationToken).ConfigureAwait(false);
+                    await destination.WriteAsync(buffer, 0, partialCount, cancellationToken).ConfigureAwait(false);
+                    count -= partialCount;
+                }
+
+                await source.CloseAsync(cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        private void EnsureIndexes(IReadWriteBindingHandle binding, CancellationToken cancellationToken)
+        {
+            _ensureIndexesSemaphore.Wait(cancellationToken);
+            try
+            {
+                if (!_ensureIndexesDone)
+                {
+                    var isFilesCollectionEmpty = IsFilesCollectionEmpty(binding, cancellationToken);
+                    if (isFilesCollectionEmpty)
+                    {
+                        if (!FilesCollectionIndexesExist(binding, cancellationToken))
+                        {
+                            CreateFilesCollectionIndexes(binding, cancellationToken);
+                        }
+                        if (!ChunksCollectionIndexesExist(binding, cancellationToken))
+                        {
+                            CreateChunksCollectionIndexes(binding, cancellationToken);
+                        }
+                    }
+
+                    _ensureIndexesDone = true;
+                }
+            }
+            finally
+            {
+                _ensureIndexesSemaphore.Release();
+            }
+        }
+
+        private async Task EnsureIndexesAsync(IReadWriteBindingHandle binding, CancellationToken cancellationToken)
+        {
+            await _ensureIndexesSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+            try
+            {
+                if (!_ensureIndexesDone)
+                {
+                    var isFilesCollectionEmpty = await IsFilesCollectionEmptyAsync(binding, cancellationToken).ConfigureAwait(false);
+                    if (isFilesCollectionEmpty)
+                    {
+                        if (!(await FilesCollectionIndexesExistAsync(binding, cancellationToken).ConfigureAwait(false)))
+                        {
+                            await CreateFilesCollectionIndexesAsync(binding, cancellationToken).ConfigureAwait(false);
+                        }
+                        if (!(await ChunksCollectionIndexesExistAsync(binding, cancellationToken).ConfigureAwait(false)))
+                        {
+                            await CreateChunksCollectionIndexesAsync(binding, cancellationToken).ConfigureAwait(false);
+                        }
+                    }
+
+                    _ensureIndexesDone = true;
+                }
+            }
+            finally
+            {
+                _ensureIndexesSemaphore.Release();
+            }
+        }
+
+        private bool FilesCollectionIndexesExist(List<BsonDocument> indexes)
+        {
+            var key = new BsonDocument { { "filename", 1 }, { "uploadDate", 1 } };
+            return IndexExists(indexes, key);
+        }
+
+        private bool FilesCollectionIndexesExist(IReadBindingHandle binding, CancellationToken cancellationToken)
+        {
+            var indexes = ListIndexes(binding, this.GetFilesCollectionNamespace(), cancellationToken);
+            return FilesCollectionIndexesExist(indexes);
+        }
+
+        private async Task<bool> FilesCollectionIndexesExistAsync(IReadBindingHandle binding, CancellationToken cancellationToken)
+        {
+            var indexes = await ListIndexesAsync(binding, this.GetFilesCollectionNamespace(), cancellationToken).ConfigureAwait(false);
+            return FilesCollectionIndexesExist(indexes);
+        }
+
+        private GridFSFileInfo<TFileId> GetFileInfo(IReadBindingHandle binding, TFileId id, CancellationToken cancellationToken)
+        {
+            var operation = CreateGetFileInfoOperation(id);
+            using (var cursor = operation.Execute(binding, cancellationToken))
+            {
+                var fileInfo = cursor.FirstOrDefault(cancellationToken);
+                if (fileInfo == null)
+                {
+                    throw new GridFSFileNotFoundException(_idSerializationInfo.SerializeValue(id));
+                }
+                return fileInfo;
+            }
+        }
+
+        private async Task<GridFSFileInfo<TFileId>> GetFileInfoAsync(IReadBindingHandle binding, TFileId id, CancellationToken cancellationToken)
+        {
+            var operation = CreateGetFileInfoOperation(id);
+            using (var cursor = await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false))
+            {
+                var fileInfo = await cursor.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
+                if (fileInfo == null)
+                {
+                    throw new GridFSFileNotFoundException(_idSerializationInfo.SerializeValue(id));
+                }
+                return fileInfo;
+            }
+        }
+
+        private GridFSFileInfo<TFileId> GetFileInfoByName(IReadBindingHandle binding, string filename, int revision, CancellationToken cancellationToken)
+        {
+            var operation = CreateGetFileInfoByNameOperation(filename, revision);
+            using (var cursor = operation.Execute(binding, cancellationToken))
+            {
+                var fileInfo = cursor.FirstOrDefault(cancellationToken);
+                if (fileInfo == null)
+                {
+                    throw new GridFSFileNotFoundException(filename, revision);
+                }
+                return fileInfo;
+            }
+        }
+
+        private async Task<GridFSFileInfo<TFileId>> GetFileInfoByNameAsync(IReadBindingHandle binding, string filename, int revision, CancellationToken cancellationToken)
+        {
+            var operation = CreateGetFileInfoByNameOperation(filename, revision);
+            using (var cursor = await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false))
+            {
+                var fileInfo = await cursor.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
+                if (fileInfo == null)
+                {
+                    throw new GridFSFileNotFoundException(filename, revision);
+                }
+                return fileInfo;
+            }
+        }
+
+        private ReadConcern GetReadConcern()
+        {
+            return _options.ReadConcern ?? _database.Settings.ReadConcern;
+        }
+
+        private IReadBindingHandle GetSingleServerReadBinding(CancellationToken cancellationToken)
+        {
+            var readPreference = _options.ReadPreference ?? _database.Settings.ReadPreference;
+            var selector = new ReadPreferenceServerSelector(readPreference);
+            var server = _cluster.SelectServer(selector, cancellationToken);
+            var binding = new SingleServerReadBinding(server, readPreference, NoCoreSession.NewHandle());
+            return new ReadBindingHandle(binding);
+        }
+
+        private async Task<IReadBindingHandle> GetSingleServerReadBindingAsync(CancellationToken cancellationToken)
+        {
+            var readPreference = _options.ReadPreference ?? _database.Settings.ReadPreference;
+            var selector = new ReadPreferenceServerSelector(readPreference);
+            var server = await _cluster.SelectServerAsync(selector, cancellationToken).ConfigureAwait(false);
+            var binding = new SingleServerReadBinding(server, readPreference, NoCoreSession.NewHandle());
+            return new ReadBindingHandle(binding);
+        }
+
+        private IReadWriteBindingHandle GetSingleServerReadWriteBinding(CancellationToken cancellationToken)
+        {
+            var selector = WritableServerSelector.Instance;
+            var server = _cluster.SelectServer(selector, cancellationToken);
+            var binding = new SingleServerReadWriteBinding(server, NoCoreSession.NewHandle());
+            return new ReadWriteBindingHandle(binding);
+        }
+
+        private async Task<IReadWriteBindingHandle> GetSingleServerReadWriteBindingAsync(CancellationToken cancellationToken)
+        {
+            var selector = WritableServerSelector.Instance;
+            var server = await _cluster.SelectServerAsync(selector, cancellationToken).ConfigureAwait(false);
+            var binding = new SingleServerReadWriteBinding(server, NoCoreSession.NewHandle());
+            return new ReadWriteBindingHandle(binding);
+        }
+
+        private bool IndexExists(List<BsonDocument> indexes, BsonDocument key)
+        {
+            foreach (var index in indexes)
+            {
+                if (index["key"].Equals(key))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private bool IsFilesCollectionEmpty(IReadWriteBindingHandle binding, CancellationToken cancellationToken)
+        {
+            var operation = CreateIsFilesCollectionEmptyOperation();
+            using (var cursor = operation.Execute(binding, cancellationToken))
+            {
+                var firstOrDefault = cursor.FirstOrDefault(cancellationToken);
+                return firstOrDefault == null;
+            }
+        }
+
+        private async Task<bool> IsFilesCollectionEmptyAsync(IReadWriteBindingHandle binding, CancellationToken cancellationToken)
+        {
+            var operation = CreateIsFilesCollectionEmptyOperation();
+            using (var cursor = await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false))
+            {
+                var firstOrDefault = await cursor.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
+                return firstOrDefault == null;
+            }
+        }
+
+        private List<BsonDocument> ListIndexes(IReadBinding binding, CollectionNamespace collectionNamespace, CancellationToken cancellationToken)
+        {
+            var operation = CreateListIndexesOperation(collectionNamespace);
+            return operation.Execute(binding, cancellationToken).ToList();
+        }
+
+        private async Task<List<BsonDocument>> ListIndexesAsync(IReadBinding binding, CollectionNamespace collectionNamespace, CancellationToken cancellationToken)
+        {
+            var operation = CreateListIndexesOperation(collectionNamespace);
+            var cursor = await operation.ExecuteAsync(binding, cancellationToken).ConfigureAwait(false);
+            return await cursor.ToListAsync(cancellationToken).ConfigureAwait(false);
+        }
+    }
+}

+ 270 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSBucketCompat.cs

@@ -0,0 +1,270 @@
+/* Copyright 2016-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents a GridFS bucket.
+    /// </summary>
+    public class GridFSBucket : GridFSBucket<ObjectId>, IGridFSBucket
+    {
+        // private fields
+        private readonly GridFSBucket<BsonValue> _bsonValueBucket;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSBucket" /> class.
+        /// </summary>
+        /// <param name="database">The database.</param>
+        /// <param name="options">The options.</param>
+        public GridFSBucket(IMongoDatabase database, GridFSBucketOptions options = null)
+            : base(database, options)
+        {
+            _bsonValueBucket = new GridFSBucket<BsonValue>(database, options);
+        }
+
+        // methods
+        /// <summary>
+        /// Deletes a file from GridFS.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        public void Delete(BsonValue id, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            _bsonValueBucket.Delete(id, cancellationToken);
+        }
+
+        /// <summary>
+        /// Deletes a file from GridFS.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A Task.</returns>
+        public Task DeleteAsync(BsonValue id, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            return _bsonValueBucket.DeleteAsync(id, cancellationToken);
+        }
+
+        /// <summary>
+        /// Downloads a file stored in GridFS and returns it as a byte array.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="options">The options.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A byte array containing the contents of the file stored in GridFS.</returns>
+        public byte[] DownloadAsBytes(BsonValue id, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            return _bsonValueBucket.DownloadAsBytes(id, options, cancellationToken);
+        }
+
+        /// <summary>
+        /// Downloads a file stored in GridFS and returns it as a byte array.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="options">The options.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A Task whose result is a byte array containing the contents of the file stored in GridFS.</returns>
+        public Task<byte[]> DownloadAsBytesAsync(BsonValue id, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            return _bsonValueBucket.DownloadAsBytesAsync(id, options, cancellationToken);
+        }
+
+        /// <summary>
+        /// Downloads a file stored in GridFS and writes the contents to a stream.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="destination">The destination.</param>
+        /// <param name="options">The options.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        public void DownloadToStream(BsonValue id, Stream destination, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            _bsonValueBucket.DownloadToStream(id, destination, options, cancellationToken);
+        }
+
+        /// <summary>
+        /// Downloads a file stored in GridFS and writes the contents to a stream.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="destination">The destination.</param>
+        /// <param name="options">The options.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A Task.</returns>
+        public Task DownloadToStreamAsync(BsonValue id, Stream destination, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            return _bsonValueBucket.DownloadToStreamAsync(id, destination, options, cancellationToken);
+        }
+
+        /// <inheritdoc />
+        public IAsyncCursor<GridFSFileInfo> Find(FilterDefinition<GridFSFileInfo> filter, GridFSFindOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull(filter, nameof(filter));
+            var wrappedFilter = WrapFilter(filter);
+            var wrappedOptions = WrapFindOptions(options);
+            var cursor = base.Find(wrappedFilter, wrappedOptions, cancellationToken);
+            return new BatchTransformingAsyncCursor<GridFSFileInfo<ObjectId>, GridFSFileInfo>(cursor, TransformFileInfos);
+        }
+
+        /// <inheritdoc />
+        public async Task<IAsyncCursor<GridFSFileInfo>> FindAsync(FilterDefinition<GridFSFileInfo> filter, GridFSFindOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            Ensure.IsNotNull(filter, nameof(filter));
+            var wrappedFilter = WrapFilter(filter);
+            var wrappedOptions = WrapFindOptions(options);
+            var cursor = await base.FindAsync(wrappedFilter, wrappedOptions, cancellationToken).ConfigureAwait(false);
+            return new BatchTransformingAsyncCursor<GridFSFileInfo<ObjectId>, GridFSFileInfo>(cursor, TransformFileInfos);
+        }
+
+        /// <summary>
+        /// Opens a Stream that can be used by the application to read data from a GridFS file.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="options">The options.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A Stream.</returns>
+        public GridFSDownloadStream OpenDownloadStream(BsonValue id, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var wrappedStream = _bsonValueBucket.OpenDownloadStream(id, options, cancellationToken);
+            return new GridFSDownloadStream(wrappedStream);
+        }
+
+        /// <summary>
+        /// Opens a Stream that can be used by the application to read data from a GridFS file.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="options">The options.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A Task whose result is a Stream.</returns>
+        public async Task<GridFSDownloadStream> OpenDownloadStreamAsync(BsonValue id, GridFSDownloadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var wrappedStream = await _bsonValueBucket.OpenDownloadStreamAsync(id, options, cancellationToken).ConfigureAwait(false);
+            return new GridFSDownloadStream(wrappedStream);
+        }
+
+        /// <inheritdoc />
+        public GridFSUploadStream OpenUploadStream(string filename, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var id = ObjectId.GenerateNewId();
+            var wrappedStream = base.OpenUploadStream(id, filename, options, cancellationToken);
+            return new GridFSUploadStream(wrappedStream);
+        }
+
+        /// <inheritdoc />
+        public async Task<GridFSUploadStream> OpenUploadStreamAsync(string filename, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var id = ObjectId.GenerateNewId();
+            var wrappedStream = await base.OpenUploadStreamAsync(id, filename, options, cancellationToken).ConfigureAwait(false);
+            return new GridFSUploadStream(wrappedStream);
+        }
+
+        /// <summary>
+        /// Renames a GridFS file.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="newFilename">The new filename.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        public void Rename(BsonValue id, string newFilename, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            _bsonValueBucket.Rename(id, newFilename, cancellationToken);
+        }
+
+        /// <summary>
+        /// Renames a GridFS file.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="newFilename">The new filename.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A Task.</returns>
+        public Task RenameAsync(BsonValue id, string newFilename, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            return _bsonValueBucket.RenameAsync(id, newFilename, cancellationToken);
+        }
+
+        /// <inheritdoc />
+        public ObjectId UploadFromBytes(string filename, byte[] source, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var id = ObjectId.GenerateNewId();
+            UploadFromBytes(id, filename, source, options, cancellationToken);
+            return id;
+        }
+
+        /// <inheritdoc />
+        public async Task<ObjectId> UploadFromBytesAsync(string filename, byte[] source, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var id = ObjectId.GenerateNewId();
+            await UploadFromBytesAsync(id, filename, source, options, cancellationToken).ConfigureAwait(false);
+            return id;
+        }
+
+        /// <inheritdoc />
+        public ObjectId UploadFromStream(string filename, Stream source, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var id = ObjectId.GenerateNewId();
+            UploadFromStream(id, filename, source, options, cancellationToken);
+            return id;
+        }
+
+        /// <inheritdoc />
+        public async Task<ObjectId> UploadFromStreamAsync(string filename, Stream source, GridFSUploadOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            var id = ObjectId.GenerateNewId();
+            await UploadFromStreamAsync(id, filename, source, options, cancellationToken).ConfigureAwait(false);
+            return id;
+        }
+
+        // private methods
+        private IEnumerable<GridFSFileInfo> TransformFileInfos(IEnumerable<GridFSFileInfo<ObjectId>> fileInfos)
+        {
+            return fileInfos.Select(fi => new GridFSFileInfo(fi.BackingDocument));
+        }
+
+        private FilterDefinition<GridFSFileInfo<ObjectId>> WrapFilter(FilterDefinition<GridFSFileInfo> filter)
+        {
+            var renderedFilter = filter.Render(GridFSFileInfoSerializer.Instance, BsonSerializer.SerializerRegistry);
+            return new BsonDocumentFilterDefinition<GridFSFileInfo<ObjectId>>(renderedFilter);
+        }
+
+        private GridFSFindOptions<ObjectId> WrapFindOptions(GridFSFindOptions options)
+        {
+            if (options != null)
+            {
+                var renderedSort = options.Sort == null ? null : options.Sort.Render(GridFSFileInfoSerializer.Instance, BsonSerializer.SerializerRegistry);
+                var wrappedSort = renderedSort == null ? null : new BsonDocumentSortDefinition<GridFSFileInfo<ObjectId>>(renderedSort);
+                return new GridFSFindOptions<ObjectId>
+                {
+                    BatchSize = options.BatchSize,
+                    Limit = options.Limit,
+                    MaxTime = options.MaxTime,
+                    NoCursorTimeout = options.NoCursorTimeout,
+                    Skip = options.Skip,
+                    Sort = wrappedSort
+                };
+            }
+            else
+            {
+                return null;
+            }
+        }
+    }
+}

+ 289 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSBucketOptions.cs

@@ -0,0 +1,289 @@
+/* Copyright 2015-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using MongoDB.Bson.Serialization;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents mutable options for a GridFS instance.
+    /// </summary>
+    public class GridFSBucketOptions
+    {
+        // fields
+        private string _bucketName;
+        private int _chunkSizeBytes;
+        private bool _disableMD5 = false;
+        private ReadConcern _readConcern;
+        private ReadPreference _readPreference;
+        private WriteConcern _writeConcern;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSBucketOptions"/> class.
+        /// </summary>
+        public GridFSBucketOptions()
+            : this(ImmutableGridFSBucketOptions.Defaults)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSBucketOptions"/> class.
+        /// </summary>
+        /// <param name="other">The other <see cref="GridFSBucketOptions"/> from which to copy the values.</param>
+        public GridFSBucketOptions(GridFSBucketOptions other)
+        {
+            Ensure.IsNotNull(other, nameof(other));
+            _bucketName = other.BucketName;
+            _chunkSizeBytes = other.ChunkSizeBytes;
+            _disableMD5 = other.DisableMD5;
+            _readConcern = other.ReadConcern;
+            _readPreference = other.ReadPreference;
+            _writeConcern = other.WriteConcern;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSBucketOptions"/> class.
+        /// </summary>
+        /// <param name="other">The other <see cref="ImmutableGridFSBucketOptions"/> from which to copy the values.</param>
+        public GridFSBucketOptions(ImmutableGridFSBucketOptions other)
+        {
+            Ensure.IsNotNull(other, nameof(other));
+            _bucketName = other.BucketName;
+            _chunkSizeBytes = other.ChunkSizeBytes;
+            _disableMD5 = other.DisableMD5;
+            _readConcern = other.ReadConcern;
+            _readPreference = other.ReadPreference;
+            _writeConcern = other.WriteConcern;
+        }
+
+        // properties
+        /// <summary>
+        /// Gets or sets the bucket name.
+        /// </summary>
+        /// <value>
+        /// The bucket name.
+        /// </value>
+        public string BucketName
+        {
+            get { return _bucketName; }
+            set
+            {
+                Ensure.IsNotNullOrEmpty(value, nameof(value));
+                _bucketName = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the chunk size in bytes.
+        /// </summary>
+        /// <value>
+        /// The chunk size in bytes.
+        /// </value>
+        public int ChunkSizeBytes
+        {
+            get { return _chunkSizeBytes; }
+            set
+            {
+                Ensure.IsGreaterThanZero(value, nameof(value));
+                _chunkSizeBytes = value;
+            }
+        }
+        
+        /// <summary>
+        /// Gets or sets whether to disable MD5 checksum computation when uploading a GridFS file.
+        /// </summary>
+        /// <value>
+        /// Whether MD5 checksum computation is disabled when uploading a GridFS file.
+        /// </value>
+        public bool DisableMD5
+        {
+            get { return _disableMD5; }
+            set { _disableMD5 = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the read concern.
+        /// </summary>
+        /// <value>
+        /// The read concern.
+        /// </value>
+        public ReadConcern ReadConcern
+        {
+            get { return _readConcern; }
+            set { _readConcern = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the read preference.
+        /// </summary>
+        /// <value>
+        /// The read preference.
+        /// </value>
+        public ReadPreference ReadPreference
+        {
+            get { return _readPreference; }
+            set { _readPreference = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets the write concern.
+        /// </summary>
+        /// <value>
+        /// The write concern.
+        /// </value>
+        public WriteConcern WriteConcern
+        {
+            get { return _writeConcern; }
+            set { _writeConcern = value; }
+        }
+    }
+
+    /// <summary>
+    /// Represents immutable options for a GridFS instance.
+    /// </summary>
+    public class ImmutableGridFSBucketOptions
+    {
+        #region static
+        // static fields
+        private static readonly ImmutableGridFSBucketOptions __defaults = new ImmutableGridFSBucketOptions();
+
+        // static properties
+        /// <summary>
+        /// Gets the default GridFSBucketOptions.
+        /// </summary>
+        /// <value>
+        /// The default GridFSBucketOptions.
+        /// </value>
+        public static ImmutableGridFSBucketOptions Defaults
+        {
+            get { return __defaults; }
+        }
+        #endregion
+
+        // fields
+        private readonly string _bucketName;
+        private readonly int _chunkSizeBytes;
+        private readonly bool _disableMD5 = false;
+        private readonly ReadConcern _readConcern;
+        private readonly ReadPreference _readPreference;
+        private readonly WriteConcern _writeConcern;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ImmutableGridFSBucketOptions"/> class.
+        /// </summary>
+        public ImmutableGridFSBucketOptions()
+        {
+            _bucketName = "fs";
+            _chunkSizeBytes = 255 * 1024;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ImmutableGridFSBucketOptions" /> class.
+        /// </summary>
+        /// <param name="other">The other <see cref="GridFSBucketOptions"/> from which to copy the values.</param>
+        public ImmutableGridFSBucketOptions(GridFSBucketOptions other)
+        {
+            Ensure.IsNotNull(other, nameof(other));
+            _bucketName = other.BucketName;
+            _chunkSizeBytes = other.ChunkSizeBytes;
+            _disableMD5 = other.DisableMD5;
+            _readConcern = other.ReadConcern;
+            _readPreference = other.ReadPreference;
+            _writeConcern = other.WriteConcern;
+        }
+
+        // properties
+        /// <summary>
+        /// Gets the bucket name.
+        /// </summary>
+        /// <value>
+        /// The bucket name.
+        /// </value>
+        public string BucketName
+        {
+            get { return _bucketName; }
+        }
+
+        /// <summary>
+        /// Gets the chunk size in bytes.
+        /// </summary>
+        /// <value>
+        /// The chunk size in bytes.
+        /// </value>
+        public int ChunkSizeBytes
+        {
+            get { return _chunkSizeBytes; }
+        }
+        
+        /// <summary>
+        /// Gets or sets whether to disable MD5 checksum computation when uploading a GridFS file.
+        /// </summary>
+        /// <value>
+        /// Whether MD5 checksum computation is disabled when uploading a GridFS file.
+        /// </value>
+        public bool DisableMD5
+        {
+            get { return _disableMD5; }
+        }
+
+
+        /// <summary>
+        /// Gets the read concern.
+        /// </summary>
+        /// <value>
+        /// The read concern.
+        /// </value>
+        public ReadConcern ReadConcern
+        {
+            get { return _readConcern; }
+        }
+
+        /// <summary>
+        /// Gets the read preference.
+        /// </summary>
+        /// <value>
+        /// The read preference.
+        /// </value>
+        public ReadPreference ReadPreference
+        {
+            get { return _readPreference; }
+        }
+
+        /// <summary>
+        /// Gets the serializer registry.
+        /// </summary>
+        /// <value>
+        /// The serializer registry.
+        /// </value>
+        public IBsonSerializerRegistry SerializerRegistry
+        {
+            get { return BsonSerializer.SerializerRegistry; }
+        }
+
+        /// <summary>
+        /// Gets the write concern.
+        /// </summary>
+        /// <value>
+        /// The write concern.
+        /// </value>
+        public WriteConcern WriteConcern
+        {
+            get { return _writeConcern; }
+        }
+    }
+}

+ 67 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSChunkException.cs

@@ -0,0 +1,67 @@
+/* Copyright 2015-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+#if NET452
+using System.Runtime.Serialization;
+#endif
+using MongoDB.Bson;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents a GridFSChunk exception.
+    /// </summary>
+#if NET452
+    [Serializable]
+#endif
+    public class GridFSChunkException : GridFSException
+    {
+#region static
+        private static string FormatMessage(BsonValue id, long n, string reason)
+        {
+            Ensure.IsNotNull(id, nameof(id));
+            Ensure.IsGreaterThanOrEqualToZero(n, nameof(n));
+            Ensure.IsNotNull(reason, nameof(reason));
+            return string.Format("GridFS chunk {0} of file id {1} is {2}.", n, id, reason);
+        }
+#endregion
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSChunkException" /> class.
+        /// </summary>
+        /// <param name="id">The file id.</param>
+        /// <param name="n">The chunk number.</param>
+        /// <param name="reason">The reason.</param>
+        public GridFSChunkException(BsonValue id, long n, string reason)
+            : base(FormatMessage(id, n, reason))
+        {
+        }
+
+#if NET452
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSChunkException"/> class.
+        /// </summary>
+        /// <param name="info">The SerializationInfo.</param>
+        /// <param name="context">The StreamingContext.</param>
+        public GridFSChunkException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+        {
+        }
+#endif
+    }
+}

+ 39 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSDownloadByNameOptions.cs

@@ -0,0 +1,39 @@
+/* Copyright 2015-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents options to a GridFS download by name operation.
+    /// </summary>
+    public class GridFSDownloadByNameOptions : GridFSDownloadOptions
+    {
+        // fields
+        private int _revision = -1;
+
+        // properties
+        /// <summary>
+        /// Gets or sets which revision of the file to download.
+        /// </summary>
+        /// <value>
+        /// Which revision of the file to download.
+        /// </value>
+        public int Revision
+        {
+            get { return _revision; }
+            set { _revision = value; }
+        }
+    }
+}

+ 52 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSDownloadOptions.cs

@@ -0,0 +1,52 @@
+/* Copyright 2015-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents options for a GridFS download operation.
+    /// </summary>
+    public class GridFSDownloadOptions
+    {
+        // fields
+        private bool? _checkMD5;
+        private bool? _seekable;
+
+        // properties
+        /// <summary>
+        /// Gets or sets a value indicating whether to check the MD5 value.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if the MD5 value should be checked; otherwise, <c>false</c>.
+        /// </value>
+        public bool? CheckMD5
+        {
+            get { return _checkMD5; }
+            set { _checkMD5 = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the returned Stream supports seeking.
+        /// </summary>
+        /// <value>
+        ///   <c>true</c> if the returned Stream supports seeking; otherwise, <c>false</c>.
+        /// </value>
+        public bool? Seekable
+        {
+            get { return _seekable; }
+            set { _seekable = value; }
+        }
+    }
+}

+ 68 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSDownloadStream.cs

@@ -0,0 +1,68 @@
+/* Copyright 2016-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents a Stream used by the application to read data from a GridFS file.
+    /// </summary>
+    /// <typeparam name="TFileId">The type of the file identifier.</typeparam>
+    public abstract class GridFSDownloadStream<TFileId> : Stream
+    {
+        // constructors
+        internal GridFSDownloadStream()
+        {
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the files collection document.
+        /// </summary>
+        /// <value>
+        /// The files collection document.
+        /// </value>
+        public abstract GridFSFileInfo<TFileId> FileInfo { get; }
+
+        // public methods
+#if NETSTANDARD1_5 || NETSTANDARD1_6
+        /// <summary>
+        /// Closes the GridFS stream.
+        /// </summary>
+        public virtual void Close()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+#endif
+
+        /// <summary>
+        /// Closes the GridFS stream.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        public abstract void Close(CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Closes the GridFS stream.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>A Task.</returns>
+        public abstract Task CloseAsync(CancellationToken cancellationToken = default(CancellationToken));
+    }
+}

+ 210 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSDownloadStreamBase.cs

@@ -0,0 +1,210 @@
+/* Copyright 2015-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Driver.Core.Bindings;
+
+namespace MongoDB.Driver.GridFS
+{
+    internal abstract class GridFSDownloadStreamBase<TFileId> : GridFSDownloadStream<TFileId>
+    {
+        // private fields
+        private readonly IReadBinding _binding;
+        private readonly IGridFSBucket<TFileId> _bucket;
+        private bool _closed;
+        private bool _disposed;
+        private readonly GridFSFileInfo<TFileId> _fileInfo;
+
+        // constructors
+        protected GridFSDownloadStreamBase(
+            IGridFSBucket<TFileId> bucket,
+            IReadBinding binding,
+            GridFSFileInfo<TFileId> fileInfo)
+        {
+            _bucket = bucket;
+            _binding = binding;
+            _fileInfo = fileInfo;
+        }
+
+        // public properties
+        public override bool CanRead
+        {
+            get { return true; }
+        }
+
+        public override bool CanWrite
+        {
+            get { return false; }
+        }
+
+        public override GridFSFileInfo<TFileId> FileInfo
+        {
+            get { return _fileInfo; }
+        }
+
+        public override long Length
+        {
+            get { return _fileInfo.Length; }
+        }
+
+        // protected properties
+        protected IReadBinding Binding
+        {
+            get { return _binding; }
+        }
+
+        protected IGridFSBucket<TFileId> Bucket
+        {
+            get { return _bucket; }
+        }
+
+        // public methods
+        public override void Close(CancellationToken cancellationToken)
+        {
+            try
+            {
+                CloseIfNotAlreadyClosed(cancellationToken);
+            }
+            finally
+            {
+                Dispose();
+            }
+        }
+
+        public override async Task CloseAsync(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            try
+            {
+                await CloseIfNotAlreadyClosedAsync(cancellationToken).ConfigureAwait(false);
+            }
+            finally
+            {
+                Dispose();
+            }
+        }
+
+        public override void Flush()
+        {
+            throw new NotSupportedException();
+        }
+
+        public override Task FlushAsync(CancellationToken cancellationToken)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            throw new NotSupportedException();
+        }
+
+        // protected methods
+        protected void CloseIfNotAlreadyClosedFromDispose(bool disposing)
+        {
+            if (disposing)
+            {
+                try
+                {
+                    CloseIfNotAlreadyClosed(CancellationToken.None);
+                }
+                catch
+                {
+                    // ignore exceptions when calling CloseIfNotAlreadyClosed from Dispose
+                }
+            }
+        }
+
+        protected virtual void CloseImplementation(CancellationToken cancellationToken)
+        {
+            // override in subclass if there is anything to do
+        }
+
+        protected virtual Task CloseImplementationAsync(CancellationToken cancellationToken)
+        {
+            // override in subclass if there is anything to do
+            CloseImplementation(cancellationToken);
+            return Task.FromResult(true);
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            CloseIfNotAlreadyClosedFromDispose(disposing);
+
+            if (!_disposed)
+            {
+                if (disposing)
+                {
+                    _binding.Dispose();
+                }
+
+                _disposed = true;
+            }
+
+            base.Dispose(disposing);
+        }
+
+        protected virtual void ThrowIfDisposed()
+        {
+            if (_disposed)
+            {
+                throw new ObjectDisposedException(GetType().Name);
+            }
+        }
+
+        // private methods
+        private void CloseIfNotAlreadyClosed(CancellationToken cancellationToken)
+        {
+            if (!_closed)
+            {
+                try
+                {
+                    CloseImplementation(cancellationToken);
+                }
+                finally
+                {
+                    _closed = true;
+                }
+            }
+        }
+
+        private async Task CloseIfNotAlreadyClosedAsync(CancellationToken cancellationToken)
+        {
+            if (!_closed)
+            {
+                try
+                {
+                    await CloseImplementationAsync(cancellationToken).ConfigureAwait(false);
+                }
+                finally
+                {
+                    _closed = true;
+                }
+            }
+        }
+    }
+}

+ 58 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSDownloadStreamCompat.cs

@@ -0,0 +1,58 @@
+/* Copyright 2016-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Bson;
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents a Stream used by the application to read data from a GridFS file.
+    /// </summary>
+    public class GridFSDownloadStream : DelegatingStream
+    {
+        // fields
+        private readonly GridFSDownloadStream<BsonValue> _wrappedStream;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSDownloadStream"/> class.
+        /// </summary>
+        /// <param name="wrappedStream">The wrapped stream.</param>
+        public GridFSDownloadStream(GridFSDownloadStream<BsonValue> wrappedStream)
+            : base(wrappedStream)
+        {
+            _wrappedStream = wrappedStream;
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the files collection document.
+        /// </summary>
+        /// <value>
+        /// The files collection document.
+        /// </value>
+        public GridFSFileInfo FileInfo
+        {
+            get
+            {
+                var wrappedFileInfo = _wrappedStream.FileInfo;
+                return new GridFSFileInfo(wrappedFileInfo.BackingDocument);
+            }
+        }
+    }
+}

+ 63 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSException.cs

@@ -0,0 +1,63 @@
+/* Copyright 2015-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+#if NET452
+using System.Runtime.Serialization;
+#endif
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents a GridFS exception.
+    /// </summary>
+#if NET452
+    [Serializable]
+#endif
+    public class GridFSException : MongoException
+    {
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSException"/> class.
+        /// </summary>
+        /// <param name="message">The error message.</param>
+        public GridFSException(string message)
+            : base(message)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSException"/> class.
+        /// </summary>
+        /// <param name="message">The error message.</param>
+        /// <param name="innerException">The inner exception.</param>
+        public GridFSException(string message, Exception innerException)
+            : base(message, innerException)
+        {
+        }
+
+#if NET452
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSException"/> class.
+        /// </summary>
+        /// <param name="info">The SerializationInfo.</param>
+        /// <param name="context">The StreamingContext.</param>
+        public GridFSException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+        {
+        }
+#endif
+    }
+}

+ 159 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSFileInfo.cs

@@ -0,0 +1,159 @@
+/* Copyright 2015-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents information about a stored GridFS file (backed by a files collection document).
+    /// </summary>
+    /// <typeparam name="TFileId">The type of the file identifier.</typeparam>
+    [BsonSerializer(typeof(GridFSFileInfoSerializer<>))]
+    public sealed class GridFSFileInfo<TFileId> : BsonDocumentBackedClass
+    {
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSFileInfo" /> class.
+        /// </summary>
+        /// <param name="backingDocument">The backing document.</param>
+        /// <param name="fileInfoSerializer">The fileInfo serializer.</param>
+        public GridFSFileInfo(BsonDocument backingDocument, IGridFSFileInfoSerializer<TFileId> fileInfoSerializer)
+            : base(backingDocument, fileInfoSerializer)
+        {
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the aliases.
+        /// </summary>
+        /// <value>
+        /// The aliases.
+        /// </value>
+        [Obsolete("Place aliases inside metadata instead.")]
+        public IEnumerable<string> Aliases
+        {
+            get { return GetValue<string[]>("Aliases", null); }
+        }
+
+        /// <summary>
+        /// Gets the backing document.
+        /// </summary>
+        /// <value>
+        /// The backing document.
+        /// </value>
+        new public BsonDocument BackingDocument
+        {
+            get { return base.BackingDocument; }
+        }
+
+        /// <summary>
+        /// Gets the size of a chunk.
+        /// </summary>
+        /// <value>
+        /// The size of a chunk.
+        /// </value>
+        public int ChunkSizeBytes
+        {
+            get { return GetValue<int>("ChunkSizeBytes"); }
+        }
+
+        /// <summary>
+        /// Gets the type of the content.
+        /// </summary>
+        /// <value>
+        /// The type of the content.
+        /// </value>
+        [Obsolete("Place contentType inside metadata instead.")]
+        public string ContentType
+        {
+            get { return GetValue<string>("ContentType", null); }
+        }
+
+        /// <summary>
+        /// Gets the filename.
+        /// </summary>
+        /// <value>
+        /// The filename.
+        /// </value>
+        public string Filename
+        {
+            get { return GetValue<string>("Filename"); }
+        }
+
+        /// <summary>
+        /// Gets the identifier.
+        /// </summary>
+        /// <value>
+        /// The identifier.
+        /// </value>
+        public TFileId Id
+        {
+            get { return GetValue<TFileId>("Id"); }
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the length.
+        /// </summary>
+        /// <value>
+        /// The length.
+        /// </value>
+        public long Length
+        {
+            get { return GetValue<long>("Length"); }
+        }
+
+        /// <summary>
+        /// Gets the MD5 checksum.
+        /// </summary>
+        /// <value>
+        /// The MD5 checksum.
+        /// </value>
+        public string MD5
+        {
+            get { return GetValue<string>("MD5", null); }
+        }
+
+        /// <summary>
+        /// Gets the metadata.
+        /// </summary>
+        /// <value>
+        /// The metadata.
+        /// </value>
+        public BsonDocument Metadata
+        {
+            get { return GetValue<BsonDocument>("Metadata", null); }
+        }
+
+        /// <summary>
+        /// Gets the upload date time.
+        /// </summary>
+        /// <value>
+        /// The upload date time.
+        /// </value>
+        public DateTime UploadDateTime
+        {
+            get { return GetValue<DateTime>("UploadDateTime"); }
+        }
+    }
+}

+ 169 - 0
Server/ThirdParty/MongoDBDriver/MongoDB.Driver.GridFS/GridFSFileInfoCompat.cs

@@ -0,0 +1,169 @@
+/* Copyright 2015-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.Misc;
+
+namespace MongoDB.Driver.GridFS
+{
+    /// <summary>
+    /// Represents information about a stored GridFS file (backed by a files collection document).
+    /// </summary>
+    [BsonSerializer(typeof(GridFSFileInfoSerializer))]
+    public sealed class GridFSFileInfo : BsonDocumentBackedClass
+    {
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GridFSFileInfo"/> class.
+        /// </summary>
+        /// <param name="backingDocument">The backing document.</param>
+        public GridFSFileInfo(BsonDocument backingDocument)
+            : base(backingDocument, GridFSFileInfoSerializer.Instance)
+        {
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the aliases.
+        /// </summary>
+        /// <value>
+        /// The aliases.
+        /// </value>
+        [Obsolete("Place aliases inside metadata instead.")]
+        public IEnumerable<string> Aliases
+        {
+            get { return GetValue<string[]>("Aliases", null); }
+        }
+
+        /// <summary>
+        /// Gets the backing document.
+        /// </summary>
+        /// <value>
+        /// The backing document.
+        /// </value>
+        new public BsonDocument BackingDocument
+        {
+            get { return base.BackingDocument; }
+        }
+
+        /// <summary>
+        /// Gets the size of a chunk.
+        /// </summary>
+        /// <value>
+        /// The size of a chunk.
+        /// </value>
+        public int ChunkSizeBytes
+        {
+            get { return GetValue<int>("ChunkSizeBytes"); }
+        }
+
+        /// <summary>
+        /// Gets the type of the content.
+        /// </summary>
+        /// <value>
+        /// The type of the content.
+        /// </value>
+        [Obsolete("Place contentType inside metadata instead.")]
+        public string ContentType
+        {
+            get { return GetValue<string>("ContentType", null); }
+        }
+
+        /// <summary>
+        /// Gets the filename.
+        /// </summary>
+        /// <value>
+        /// The filename.
+        /// </value>
+        public string Filename
+        {
+            get { return GetValue<string>("Filename"); }
+        }
+
+        /// <summary>
+        /// Gets the identifier.
+        /// </summary>
+        /// <value>
+        /// The identifier.
+        /// </value>
+        public ObjectId Id
+        {
+            get { return GetValue<BsonValue>("IdAsBsonValue").AsObjectId; }
+        }
+
+        /// <summary>
+        /// Gets the identifier as a BsonValue.
+        /// </summary>
+        /// <value>
+        /// The identifier as a BsonValue.
+        /// </value>
+        [Obsolete("All new GridFS files should use an ObjectId as the Id.")]
+        public BsonValue IdAsBsonValue
+        {
+            get { return GetValue<BsonValue>("IdAsBsonValue"); }
+        }
+
+        /// <summary>
+        /// Gets the length.
+        /// </summary>
+        /// <value>
+        /// The length.
+        /// </value>
+        public long Length
+        {
+            get { return GetValue<long>("Length"); }
+        }
+
+        /// <summary>
+        /// Gets the MD5 checksum.
+        /// </summary>
+        /// <value>
+        /// The MD5 checksum.
+        /// </value>
+        [Obsolete("MD5 support will be removed soon.")]
+        public string MD5
+        {
+            get { return GetValue<string>("MD5", null); }
+        }
+
+        /// <summary>
+        /// Gets the metadata.
+        /// </summary>
+        /// <value>
+        /// The metadata.
+        /// </value>
+        public BsonDocument Metadata
+        {
+            get { return GetValue<BsonDocument>("Metadata", null); }
+        }
+
+        /// <summary>
+        /// Gets the upload date time.
+        /// </summary>
+        /// <value>
+        /// The upload date time.
+        /// </value>
+        public DateTime UploadDateTime
+        {
+            get { return GetValue<DateTime>("UploadDateTime"); }
+        }
+    }
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов