MongoDb Connect to Replica Set Primary Issue C# - c#

How do I get back the name of the primary database? Lets say database3 was primary
Thanks
var connString = "mongodb://database1,database2,database3/?replicaSet=repl";
var client = new MongoClient(connString);
var server = client.GetServer().Instances.FirstOrDefault(server => server.IsPrimary);
var address = server.Address;

Having looked at the source code of the MongoDB driver, there is no straightforward way to get the name of the primary server from the driver itself. However, you can query server name in MOngoDB by executing {isMaster:1} using RunCommand. You can then parse the primary server from the returned JSON document. This approach works regardless if you are connected to the primary or secondary server.
var mongoClient = new MongoClient(clientSettings);
var testDB = mongoClient.GetDatabase("test");
var cmd = new BsonDocument("isMaster", "1");
var result = testDB.RunCommand<BsonDocument>(cmd);
var primaryServer = result.Where(x => x.Name == "primary").FirstOrDefault().Value.ToString();

Thanks to Jaco for putting me on the right track I solved my problem by doing the following
public static string GetPrimaryDatabase()
{
var mongoClient = new MongoClient(clientSettings);
var server = mongoClient.GetServer();
var database = server.GetDatabase("test");
var cmd = new CommandDocument("isMaster", "1");
var result = database.RunCommand(cmd);
return result.Response.FirstOrDefault(
response => response.ToString().Contains("primary")).Value.ToString();
}

You really should not handle connecting to the right server yourself. The MongoDB driver handles that for you.
Just specify all of your servers in the connections string and the driver will connect to one of them and get replica set's current state on its own. The driver will then direct write operations to the current primary. Read operations may be directed to the primary, or any other server, depending on the read preference you specify.
You can read about forming replica set connection strings here: https://docs.mongodb.org/v3.0/reference/connection-string/

Related

How to see DynamoDB table name in C#?

I can't see the name of the tables already created. I'm working on a project in which I have access to the DynamoDB database through an IAM client, I create the AmazonClient using the credentials and configs that were made available to me, but I can't see the tables already created in the database.
I have already created the client and connected it to the database, I am trying to see the number of tables as follows, but the result is always 0
new code
List<string> currentTables = client.ListTablesAsync().Result.TableNames;
MessageBox.Show(currentTables.Count.ToString());
Try awaiting the API call:
List<string> currentTables = await client.ListTablesAsync().Result.TableNames;
MessageBox.Show(currentTables.Count.ToString());
Try this sync code instead:
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
// Initial value for the first page of table names.
string lastEvaluatedTableName = null;
do
{
// Create a request object to specify optional parameters.
var request = new ListTablesRequest
{
Limit = 10, // Page size.
ExclusiveStartTableName = lastEvaluatedTableName
};
var response = client.ListTables(request);
ListTablesResult result = response.ListTablesResult;
foreach (string name in result.TableNames)
Console.WriteLine(name);
lastEvaluatedTableName = result.LastEvaluatedTableName;
} while (lastEvaluatedTableName != null);

How can I get my collections (and data in general) from cloud.mongodb.com?

This is exactly my code. I've purposely let the Main method, so that you can see the whole thing.
static void Main(string[] args)
{
var client = new MongoClient("mongodb+srv:://MyDatabaseUser:MyDatabaseUserPassword#cluster0.re2kq.mongodb.net/LiviuTestDb?retryWrites=true&w=majority");
var database = client.GetDatabase("LiviuTestDb");
var myCollections = database.ListCollections();
}
I am getting a ConnectionTimeOutException. The credentials are correct - the user has read write to any database.
This is how my (only) cluster looks like (as simplistic as possible):
What can I try next?
What happens if you drop the db name from the connection string?
var client = new MongoClient("mongodb://MyDatabaseUser:MyDatabaseUserPassword#cluster0.re2kq.mongodb.net");

How to get all installations when using Azure Notification Hubs installation model?

Using NotificationHubClient I can get all registered devices using GetAllRegistrationsAsync(). But if I do not use the registration model but the installation model instead, how can I get all installations? There are methods to retrieve a specific installation but none to get everything.
You're correct, as of July 2016 there's no way to get all installations for a hub. In the future, the product team is planning to add this feature to the installations model, but it will work in a different way. Instead of making it a runtime operation, you'll provide your storage connection string and you'll get a blob with everything associated with the hub.
Sorry for visiting an old thread... but in theory you could use the GetAllRegistrationsAsyc to get all the installations. I guess this will return everything without an installation id as well, but you could just ignore those if you choose.
Could look something like this
var allRegistrations = await _hub.GetAllRegistrationsAsync(0);
var continuationToken = allRegistrations.ContinuationToken;
var registrationDescriptionsList = new List<RegistrationDescription>(allRegistrations);
while (!string.IsNullOrWhiteSpace(continuationToken))
{
var otherRegistrations = await _hub.GetAllRegistrationsAsync(continuationToken, 0);
registrationDescriptionsList.AddRange(otherRegistrations);
continuationToken = otherRegistrations.ContinuationToken;
}
// Put into DeviceInstallation object
var deviceInstallationList = new List<DeviceInstallation>();
foreach (var registration in registrationDescriptionsList)
{
var deviceInstallation = new DeviceInstallation();
var tags = registration.Tags;
foreach(var tag in tags)
{
if (tag.Contains("InstallationId:"))
{
deviceInstallation.InstallationId = new Guid(tag.Substring(tag.IndexOf(":")+1));
}
}
deviceInstallation.PushHandle = registration.PnsHandle;
deviceInstallation.Tags = new List<string>(registration.Tags);
deviceInstallationList.Add(deviceInstallation);
}
I am not suggesting this to be the cleanest chunk of code written, but it does the trick for us. We only use this for debugging type purposes anyways

Prepared statement caching issue in Cassandra Csharp driver

I believe I have found a bug with the logic of how a prepared statement is cached in the StatementFactory in the Cassandra csharp driver (version 2.7.3). Here is the use case.
Guid key = Guid.NewGuid(); // your key
ISession session_foo = new Session("foo"); //This is pseudo code
ISession session_bar = new Session("bar");
var foo_mapper = new Mapper(session_foo); //table foo_bar
var bar_mapper = new Mapper(session_bar); //table foo_bar
await Task.WhenAll(
foo_mapper.DeleteAsync<Foo>("WHERE id = ?", key),
bar_mapper.DeleteAsync<Bar>("WHERE id = ?", key));
We have found that after running this deletes, only the first request is succeeding. After diving in the the source code of StatementFactory
public Task<Statement> GetStatementAsync(ISession session, Cql cql)
{
if (cql.QueryOptions.NoPrepare)
{
// Use a SimpleStatement if we're not supposed to prepare
Statement statement = new SimpleStatement(cql.Statement, cql.Arguments);
SetStatementProperties(statement, cql);
return TaskHelper.ToTask(statement);
}
return _statementCache
.GetOrAdd(cql.Statement, session.PrepareAsync)
.Continue(t =>
{
if (_statementCache.Count > MaxPreparedStatementsThreshold)
{
Logger.Warning(String.Format("The prepared statement cache contains {0} queries. Use parameter markers for queries. You can configure this warning threshold using MappingConfiguration.SetMaxStatementPreparedThreshold() method.", _statementCache.Count));
}
Statement boundStatement = t.Result.Bind(cql.Arguments);
SetStatementProperties(boundStatement, cql);
return boundStatement;
});
}
You can see that the cache only uses the cql statement. In our case, we have the same table names in different keyspaces (aka sessions). Our cql statement in both queries look the same. ie DELETE FROM foo_bar WHERE id =?.
If I had to guess, I would say that a simple fix would be to combine the cql statement and keyspace together as the cache key.
Has anyone else run into this issue before?
As a simple workaround, I am skipping the cache by using the DoNotPrepare
await _mapper.DeleteAsync<Foo>(Cql.New("WHERE id = ?", key).WithOptions(opt => opt.DoNotPrepare()));
I also found an open issue with Datastax
There is an open ticket to fix this behaviour.
As a workaround, you can use a different MappingConfiguration instances when creating the Mapper:
ISession session1 = cluster.Connect("ks1");
ISession session2 = cluster.Connect("ks2");
IMapper mapper1 = new Mapper(session1, new MappingConfiguration());
IMapper mapper2 = new Mapper(session2, new MappingConfiguration());
Or, you can reuse a single ISession instance and fully-qualify your queries to include the keyspace.
MappingConfiguration.Global.Define(
new Map<Foo>()
.TableName("foo")
.KeyspaceName("ks1"),
new Map<Bar>()
.TableName("bar")
.KeyspaceName("ks2"));
ISession session = cluster.Connect();
IMapper mapper = new Mapper(session);

Opening a MongoDB GridFS by name with C# Driver

In pymongo, there is an option to open a GridFS with a specific collection name. E.g. mygridfs = gridfs.GridFS(db, collection = mycolc).
I cannot find a similar option in the MongoDB C# driver (official MongoDB latest driver version).
As a result if I want to share GridFS data between Python and C# modules, I can only use the default GridFS in the DB (named 'fs').
Any clues to whether I can somehow access a GridFS with a non-default name in the C# MongoDB driver ?
A sample using grid in c#:
var url = new MongoUrl("mongodb://localhost");
var Client = new MongoClient(url);
var Server = Client.GetServer();
var Database = Server.GetDatabase("test");
var collection = Database.GetCollection("test");
var set = new MongoGridFSSettings {UpdateMD5 = true, ChunkSize = 512*1024, VerifyMD5 = false};
// you can set the name here
set.Root = "mycol";
var grid = Database.GetGridFS(set);
// Upload
grid.Upload(#"C:\Users\Hamid\Desktop\sample.txt", "remote");
// Download
grid.Download(#"C:\Users\Hamid\Desktop\sample2.txt", "remote");

Categories

Resources