I am using the C# driver to work with MongoDB. I need to use my program to update the set config during execution, and then allow other parts of the program to continue using the driver.
My current issue is reconfiguring the driver to use the new set.
try
{
var res = Database.Admin.RunCommand(new CommandDocument("replSetReconfig", replicaSetConfig));
}
catch (EndOfStreamException){}
catch (Exception e)
{
Log.Exc("Problem updating replica set", e);
ranCommand = false;
}
if (ranCommand)
{
HERE - I need to update the MongoClient or MongoServer to have the new servers
return;
}
I assume when an EndOfStreamException occurs, that the command has been successful, as the server has shutdown/started a reconfig.
I'd like to update the driver to have the new config to ensure that it will definitely reconnect to at least one of the servers, in any edge cases where changing the config will prevent it connecting back with its original connection string.
Is there any way to achieve this?
As an extra question, is there any way from C# to determine the current replica set config version?
Thanks
I can answer part 2 of your question - you can query the local database to get the current replica set configuration:
MongoServer server = client.GetServer();
var local = server.GetDatabase("local");
var collection = local.GetCollection("system.replset");
var cfg = collection.FindOne();
Console.WriteLine(cfg["version"]);
I would imagine that if the original connection string is no longer valid, you need to create a new MongoClient object with a new connection string.
[Later]
You can also get everything else about the replica set, including its status, by running the replSetGetStatus command on the admin database.
Related
We have a number of SSRS sites serving reports to various locations. Each of these servers all have custom connections in each and every report (don't ask why, that's a tale too torrid to tell). Our goal is to replace all of these custom data sources with a single shared data source for all reports on each server.
To that end, I have created a C# program that will find each report on each server and point the current custom data sources to a currently existing shared data source. This executes and seems to work fine.
My next goal is to use C# to create the shared data source on each server where none currently exists.
My current dilemma arises here:
private static void CreateSharedDataSource(string user, string password, string connection)
{
DataSourceDefinition source = new DataSourceDefinition();
source.CredentialRetrieval = CredentialRetrievalEnum.Store;
source.ConnectString = connection;
source.Enabled = true;
source.EnabledSpecified = true;
source.Extension = "SQL";
source.ImpersonateUser = false;
source.ImpersonateUserSpecified = false;
source.Prompt = "Enter a user name and password to access the data source:";
source.UserName = user;
source.Password = password;
source.WindowsCredentials = true;
source.OriginalConnectStringExpressionBased = true;
source.UseOriginalConnectString = true;
try
{
service.CreateDataSource("DbDataSource", "/DsFolder", false, source, null);
Console.WriteLine("Data source created successfully");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
The data source is created correctly and the user name and password are updated correctly. The problem is that, when I look at the newly created data source on the server, the Connect string property is empty and, yes, the correct value is being passed to it in the method above. If I plug that value into the shared source on the server and test the connection, it works fine, but I cannot get the C# program to update that value itself.
So, is there something subtle I'm missing? Am I misinterpreting a setting up there? Did I set a value wrong?
Clues appreciated.
I've never tried anything like this but a quick bit of research uncovered this which may be helpful.
https://learn.microsoft.com/en-us/dotnet/api/reportservice2010.datasourcedefinition.originalconnectstringexpressionbased?view=sqlserver-2016
It states
"Expression-based connection strings are not supported in shared data
sources."
Assuming the conneciton string is just a plain text string then I would guess that you could set this to false. This may help preserve the string you pass in.
Alright, found my answer. I had a pre-existing data source that was working so, instead of creating it from scratch, I copied that and only changed the name. That created a data source where the Connect string did persist. Comparing the settings in that with what I was setting revealed:
source.UseOriginalConnectString = false;
whereas, my code was:
source.UseOriginalConnectString = true;
Looking that up in docs and it tells me "If true, the value of the ConnectString property is ignored."
Hmmm... that's intuitive. That's not what that sounds like at all. :)
I'm working on an app that has a live network database and a contingency local database, and it detects whether the live network db is accessible, and, if not, it times out after three seconds, changing the connectionstring to the local contingency database.
Following tips here on SO, I managed to alter the connectionstring on app.config during run time and reload the settings.
This is the method the app calls when a change on the connection string is needed:
public static void ChangeConnectionString(string connectionstring)
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings");
connectionStringsSection.ConnectionStrings[0].ConnectionString = connectionstring;
var connectionStrings = config.ConnectionStrings;
foreach (ConnectionStringSettings connectionString in connectionStrings.ConnectionStrings)
{
connectionString.ConnectionString = connectionstring;
}
config.Save();
ConfigurationManager.RefreshSection("connectionStrings");
PDV_WPF.Properties.Settings.Default.Save();
PDV_WPF.Properties.Settings.Default.Reload();
//Ensures the configuration is saved and reloaded.
FbConnection.ClearAllPools();
//Closes all currently open connections which might be using the old connection string.
Debug.WriteLine("==========Ran ChangeConnectionString");
Debug.WriteLine("==========FDBConnString is:");
Debug.WriteLine("==========" + PDV_WPF.Properties.Settings.Default.FDBConnString);
After I disconnect my computer form the network, whenever I check the current FDBConnString, it correctly points to the local contingency database. However, on the very next line, when it tries to run a query, I get the following exception:
Inner Exception 1:
IscException: Unable to complete network request to host "dbserver".
Inner Exception 2:
SocketException: Este host não é conhecido //(This host is unknown)
Full exception details: https://pastebin.com/3syLvsQf
It seems that, even after I successfully change the connection string, and successfully reload the application config file, it still tries to open a connection using the old connection string. Even if I call Debug to print the current Properties.Settings.Default.FDBConnString right on the line above the call for FbConnection.Open(), it shows the new string rather than the incorrect, old one.
Any insights on what might be going on?
I found what was the issue.
I am instancing a inherited table adapter from the generated xsd file. When I declare a table adapter on my class it also inherits the connection string stored on app.config at the time of declaration. So it doesn't matter if I change app.config, as the declared table adapter is already stuck with the previous connection string.
So, the solution was, rather than changing the connection string stored on app.config, I just had to change the connection string on the declared table adapter:
tB_STOCKTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.ContingencyDB;
tB_STK_PRODUCTTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.ContingencyDB;
or
tB_STOCKTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.NetworkDB;
tB_STK_PRODUCTTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.NetworkDB;
Both ContingencyDB and NetworkDB are strings stored on app.config as a user-scoped string, which can be changed via a given "Settings" window presented to the user.
I'm going through the mongoDB Driver Documentation Quick Tour for the first time. Specifically the 2.4 version.
I've created a fresh mongodb instance at the 192.168.1.50 address, and it appears to be running correctly.
The MongoDB documentation gives the following example:
var client = new MongoClient("mongodb://192.168.1.50:27017");
#It's ok if the database doesn't yet exist. It will be created upon first use
var database = client.GetDatabase("testDB");
#It’s ok if the collection doesn’t yet exist. It will be created upon first use.
var collection = database.GetCollection<BsonDocument>("testCollection");
However, when I go on my server, and I enter the mongo console
mongo
And I list the databases using
show dbs
The output is only
admin 0.000GB
local 0.000GB
Is there anything else I should have done to make this work? I'm getting no errors on try/catch, and it appears to be running fine.
Troubleshooting
So far I've confirmed that mongodb is running by using the following:
netstat -plntu
Shows mongod running on 27017 in the LISTEN state.
I'd also be interested in knowing if there's a way on the mongodb server to view live connections, so I could see if it were actually successfully connecting.
Well the problem is that you need to create almost one collection in order to persist the created database (weird right?) i tested it with robomongo and works in that way.
The problem is that GetCollection method is not creating the target collection, you can try with this code:
static void Main(string[] args)
{
var client = new MongoClient("mongodb://192.168.1.50:27017");
//# It's ok if the database doesn't yet exist. It will be created upon first use
var database = client.GetDatabase("test");
//# It’s ok if the collection doesn’t yet exist. It will be created upon first use.
string targetCollection = "testCollection";
bool alreadyExists = database.ListCollections().ToList().Any(x => x.GetElement("name").Value.ToString() == targetCollection);
if (!alreadyExists)
{
database.CreateCollection(targetCollection);
}
var collection = database.GetCollection<BsonDocument>(targetCollection);
}
It turns out that a method I had found on how to set multiple bindIp's was incorrect. The problem wasn't with the C# at all. I found the solution here
In case that ever goes away, here's the current settings I had to follow for multiple ip's
edit file /etc/mongod.conf
Wrap the comma-separated-Ips with brackets
bindIp = [127.0.0.1, 192.168.184.155, 96.88.169.145]
My original code worked fine, I just didn't have the brackets on the bindIp.
I have a WorkAboutPro 4 and on this i run an application.
This application uses an SQLlite database.
Now i also run a computer program along side it, in here i use RAPI2 to work with my handheld device.
As soon i connect my device a function triggers and it first pulls my database from my handheld to my computer.
I then do some stuff with it and go on to push it back. problem is that the database that returns is always 0kb and has no data, not even tables.
//Create my Paths
string myDevice = device.GetFolderPath(SpecialFolder.ProgramFiles);
string deviceFile = myDevice + #"\PPPM\SQL_PPPM.s3db";
string myComputer = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6);
string localFile = myComputer + #"\SQL_PPPM.s3db";
//Get the Database
RemoteFile.CopyFileFromDevice(device, deviceFile, localFile, true);
//Do Stuff
try
....
catch(Exception ex)
....
//Push The Database back
RemoteFile.CopyFileToDevice(device, localFile, deviceFile, true);
Now first i thought it was beccause i am not able to push a database over the connection. So i tried to pull a full database to my computer. but this works just fine.
Then i went on and placed an empty Txt file on my hadn held. pulled it, added text and pushed it and also this works fine.
So the only thing that goes wrong is when i try i push a full database back to my HandHeld resulting in an 0kb empty database.
Anyone an idea why this is?
Lotus~
Edit: if you know a beter way to detect if a device is connected and push/pull files from a PDA please let me know.
So i faced the same problem as well.
It most likely has to do with your Sqlite connections still being open.
The thing that worked out best for me was to modify my SqlDataAccess class and start using the 'using'.
Example:
using(var connection = new SQLiteConnection(ConnectionString))
{
try
{
connection.Open();
}
catch (Exception e)
{
throw new Exception(e.Message);
}
finally
{
connection.Close();
}
}
For me the same worked with DataAdapters.
Good luck in the future, and remember never throw yourself in a case of Denvercoder9. You should have answered this a long time ago.
I need to setup sharding over replica set as recommended in MongoDB reference for high availability & scalability. I have few questions about connection string and its behavior for C# driver in that scenario (code snippet below):
Is the connection string below looks right for connecting to mongos instances: mongos1, mongos2 & mongos3?
What happens to client if one of the mongos instance crashes? Will the failed call handled gracefully by retrying to second mongos instance? Does the client blacklist the failed mongos instance and try after sometime?
If I want to set readpreference, will the driver be aware of replica set existence and honor setting ReadPreference?
Code snippet:
MongoUrlBuilder bldr = new MongoUrlBuilder();
List<MongoServerAddress> servers = new List<MongoServerAddress>();
servers.Add(new MongoServerAddress("mongos1:27016"));
servers.Add(new MongoServerAddress("mongos2:27016"));
servers.Add(new MongoServerAddress("mongos3:27016"));
bldr.Username = "myuser";
bldr.Password = "mypwd";
bldr.Servers = servers;
bldr.DatabaseName = "mydb";
bldr.ReadPreference = ReadPreference.Primary;
var server = MongoServer.Create(bldr.ToMongoUrl());
1) Yes, this is just fine. Note that all of this could be put in an actual connection string as well. mongodb://myuser:mypwd#mongos1:27016,mongos2:27016,mongos3:27016/mydb/?readPreference=primary
2) The way your connection string is built, you'll be load balancing across the 3 mongos. If one goes down, then the other two will simply begin to receive more traffic. Errors, however, will happen and nothing gets retried automatically. You'll need to handle the errors and make decisions based on each query/write whether it is safe to retry.
3) The driver, when talking to a sharded system, will simply forward the read preference to mongos. Note that mongos version 2.2 had some difficulty with read preferences. I'd advise you to be on the 2.4 line.