【问题标题】:Connecting MongoDb.Driver (.Net) with SSL throws value cannot be null error使用 SSL 连接 MongoDb.Driver (.Net) 会引发 value cannot be null 错误
【发布时间】:2021-12-23 08:42:57
【问题描述】:

我正在尝试将 .Net Core API 连接到受 SSL 保护的 MongoDB。我可以使用 Mongo Compass 进行连接,因此我确信问题不在我的 MongoDB 配置中。

在将证书添加到 MongoDB 之前一切正常,您会看到堆栈指向证书。就是不知道怎么改。

我找不到很多关于如何在 MongoDB 驱动程序中实现 SslSettings 的文档,所以我从不同的来源和 SO 问题拼凑起来。

当我的 API 连接到 Mongo 时,问题似乎出现了。我得到以下异常。

值不能为空。 (参数'来源')

堆栈转储指向 X509 证书作为缺失/空值。

at System.Linq.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument)
at System.Linq.Enumerable.Cast[TResult](IEnumerable source)
at MongoDB.Driver.SslSettings.X509CertificateCollectionEqualityComparer.Equals(X509CertificateCollection lhs, X509CertificateCollection rhs)
at MongoDB.Driver.SslSettings.Equals(Object obj)
at System.Object.Equals(Object objA, Object objB)
at MongoDB.Driver.ClusterKey.Equals(Object obj)
at System.Collections.Generic.ObjectEqualityComparer`1.Equals(T x, T y)
at System.Collections.Generic.Dictionary`2.FindValue(TKey key)
at System.Collections.Generic.Dictionary`2.TryGetValue(TKey key, TValue& value)
at MongoDB.Driver.ClusterRegistry.GetOrCreateCluster(ClusterKey clusterKey)
at MongoDB.Driver.MongoClient..ctor(MongoClientSettings settings)
at MongoDB.Driver.MongoClient..ctor(String connectionString)
at Bullies.API.Endpoints.Users.UserService..ctor(IOptions`1 config, IMediator mediator) in C:\Users\...\Demo.API\Endpoints\Users\UserService.cs:line 38
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Demo.API.HostedServices.SubscriptionHostedService.<ExecuteAsync>d__2.MoveNext() in C:\Users\...\Demo.API\HostedServices\SubscriptionHostedService.cs:line 32
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>d__9.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.<RunAsync>d__4.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
at Demo.API.Program.Main(String[] args) in C:\...\Demo.API\Program.cs:line 22

appsettings.json 连接字符串

mongodb://user:pass@localmongo:12345/MyDb?authSource=admin&readPreference=primary&appname=demoapi&ssl=true

AccessMongoClass.cs

MongoCredential creds = MongoCredential.CreateMongoCRCredential("localmongo:12345", "user", "pass");
var clientCertificate = new List<X509Certificate>()
  { new X509Certificate("Path\\...\\mysite_com.pfx", "privateKeyPassword") };

MongoClientSettings settingz = new MongoClientSettings();
settingz.ApplicationName = "demo-api";
settingz.Credential = creds;
settingz.SslSettings = new SslSettings()
{
    CheckCertificateRevocation = false,
    //EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12,
    ClientCertificates = clientCertificate,
    ClientCertificateSelectionCallback =
      (sender, host, certificates, certificate, issuers) => clientCertificate.ToList()[0],
    ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true
 };

MongoClient client = new MongoClient(settingz);

在 mongodb 端我看到这个错误:

"ctx":"conn7","msg":"Interrupted operation as its client disconnected","attr":{"opId":1731}}

Mongo 日志很长,所以我只是挑选出我认为的关键行。如果您想看其他内容,我可以轻松添加。

我原以为我提供了 X509 证书,但显然我遗漏了一些东西。

【问题讨论】:

    标签: mongodb mongodb-.net-driver


    【解决方案1】:

    如果您只是创建一个新客户端并在完整的堆栈跟踪中看到ClusterRegistry.GetOrCreateCluster,我假设您不会看到此异常。当驱动程序试图重用存储在静态存储中的先前创建的集群时,将调用此逻辑 (ClusterRegistry)。在您的情况下,您似乎从这样的设置中创建了 2 个mongoClients:

            var clientSettings1 = new MongoClientSettings()
            {
                SslSettings = new SslSettings
                {
                    ClientCertificates = new X509Certificate2[] { new X509Certificate2(@"path", "pass") }
                }
            };
            // create client 1
            var clientSettings2 = new MongoClientSettings()
            {
                SslSettings = new SslSettings
                {
                    ClientCertificates = null
                }
            };
            // create client 2
    

    如果是这样,这是驱动程序中的一个错误,请尽量避免在 ClientCertificates 中设置 null 例如您可以分配一个空集合

    【讨论】:

    • 实际上我只使用连接字符串就得到了同样的错误。这就是导致我在 OP 中使用更详细的尝试来定义 x509 证书的原因。 //MongoClient client = new(_mongoSettings.ConnectionString);
    • 我不认为你可以通过connectionString来配置x509证书,但是关键点:1.当你创建new MongoClient时,驱动程序实际上试图找到之前创建的mongoClients,如果它是找到,然后它会尝试检查找到的客户端是否与您要创建的客户端具有相同的 MongoClientSettings。 2. 为此,它调用MongoClientSettings.Equals,然后调用SslSettings.Equals,后者又调用Equals for X509CertificateCollection。如果正确的 collection 为 null,则此方法存在错误,这会导致您看到的错误
    猜你喜欢
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    • 2012-06-28
    • 1970-01-01
    • 2016-07-26
    • 1970-01-01
    相关资源
    最近更新 更多