{"record":{"id":"f822d5da509b4047","repo":"dotnet/orleans","slug":"configure-exactly-one-of-nameof-connectionstring","errorCode":null,"errorMessage":"Configure exactly one of {nameof(connectionString)} or {nameof(dataSource)}.","messagePattern":"Configure exactly one of (.+?) or (.+?)\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/AdoNet/Shared/Storage/RelationalStorage.cs","lineNumber":134,"sourceCode":"        {\n            if (string.IsNullOrWhiteSpace(invariantName))\n            {\n                throw new ArgumentException(\"The name of invariant must contain characters\", nameof(invariantName));\n            }\n\n            ArgumentNullException.ThrowIfNull(dataSource);\n            DbConnectionFactory.ValidateDataSource(invariantName, dataSource);\n            return new RelationalStorage(invariantName, dataSource);\n        }\n\n        /// <summary>\n        /// Creates an instance using exactly one configured connection source.\n        /// </summary>\n        public static IRelationalStorage CreateInstance(string invariantName, string? connectionString, DbDataSource? dataSource)\n        {\n            if (string.IsNullOrWhiteSpace(connectionString) == (dataSource is null))\n            {\n                throw new ArgumentException($\"Configure exactly one of {nameof(connectionString)} or {nameof(dataSource)}.\");\n            }\n\n            return dataSource is null\n                ? CreateInstance(invariantName, connectionString!)\n                : CreateInstance(invariantName, dataSource);\n        }\n\n\n        /// <summary>\n        /// Executes a given statement. Especially intended to use with <em>SELECT</em> statement.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The result type.</typeparam>\n        /// <param name=\"query\">Executes a given statement. Especially intended to use with <em>SELECT</em> statement.</param>\n        /// <param name=\"parameterProvider\">Adds parameters to the query. Parameter names must match those defined in the query.</param>\n        /// <param name=\"selector\">This function transforms the raw <see cref=\"IDataRecord\"/> results to type <see paramref=\"TResult\"/> the <see cref=\"int\"/> parameter being the resultset number.</param>\n        /// <param name=\"commandBehavior\">The command behavior that should be used. Defaults to <see cref=\"CommandBehavior.Default\"/>.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>A list of objects as a result of the <see paramref=\"query\"/>.</returns>","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/AdoNet/Shared/Storage/RelationalStorage.cs#L116-L152","documentation":"Thrown by the 3-argument RelationalStorage.CreateInstance(string invariantName, string? connectionString, DbDataSource? dataSource) when the (connectionString, dataSource) pair is ambiguous: both null/whitespace or both set. The contract is 'exactly one' connection source so storage does not silently pick a winner. Note the message uses nameof tokens literally inside an interpolated string, so it reads with the literal C# syntax unless rewritten.","triggerScenarios":"Calling the overload with both connectionString and dataSource null, or both non-null. The check is `string.IsNullOrWhiteSpace(connectionString) == (dataSource is null)` which is true when both are missing or both are present.","commonSituations":"Configuring both a connection string and a data source in options (ambiguous intent); neither configured (defaults to null/null); refactor that left both fields populated; conditional config that sometimes sets both.","solutions":["Set exactly one of connectionString or dataSource; leave the other null.","Decide your connection strategy upfront: connection-string-based OR DbDataSource-based, and clear the unused option.","Add a configuration validator that rejects options where both are populated or both are empty.","If you only ever use a connection string, call the 2-argument CreateInstance(invariantName, connectionString) overload instead."],"exampleFix":"// before - both set or both null\nvar storage = RelationalStorage.CreateInstance(invariant, connStr, dataSource); // throws if both/null\n\n// after - exactly one\nvar storage = RelationalStorage.CreateInstance(invariant, connStr, dataSource: null);","handlingStrategy":"validation","validationCode":"bool hasCs = !string.IsNullOrWhiteSpace(connectionString);\nbool hasDs = dataSource is not null;\nif (hasCs == hasDs)\n    throw new InvalidOperationException(\"Configure exactly one of connectionString or dataSource.\");","typeGuard":"static bool ExactlyOneSource(string? cs, DbDataSource? ds)\n    => !string.IsNullOrWhiteSpace(cs) ^ (ds is not null);","tryCatchPattern":"try { storage = RelationalStorage.CreateInstance(inv, cs, ds); }\ncatch (ArgumentException) { /* clear one of the two */ }","preventionTips":["Decide on one connection strategy and clear the other option.","Add an options validator enforcing exactly-one-source.","Use the 2-arg overload when the source is fixed."],"tags":["csharp","dotnet","orleans","adonet","configuration","argument-validation"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}