MySQL 6.9.8 - System.String.Substring exception when opening new connection - c#

Every now and then, when I'm making a database query I run into a problem with ExecuteNonQuery in the MySQL.Data library.
The exception which gets raised is this:
Exception thrown: 'System.ArgumentOutOfRangeException' in CommonLanguageRuntimeLibrary ("Length cannot be less than zero.")
There are my logs from IntelliTrace from an Azure Worker Role.
It works most of the time but when this happens it stops the normal processing of the worker.
I'm loading the connection string from app.config, this is what it looks like:
<add key="DatabaseConnectionString" value="Server=localhost; Port=3306; Uid=user; Pwd=mypassword; Pooling=false;" />
I select the database at runtime with every request because it keeps changing which database it's connecting to.
Is there anything I can do to stop this from occurring and allow the new connection to open correctly?
Edit
Upon further investigation and crawling through the MySQL.Data Source code I've drilled down into this getter.
[DisplayName("program_name")]
public string ProgramName
{
get
{
string name = Environment.CommandLine;
try
{
string path = Environment.CommandLine.Substring(0, Environment.CommandLine.IndexOf("\" ")).Trim('"');
name = System.IO.Path.GetFileName(path);
if (Assembly.GetEntryAssembly() != null)
name = Assembly.GetEntryAssembly().ManifestModule.Name;
}
catch (Exception ex)
{
name = string.Empty;
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
return name;
}
}
Now is it possible that the WorkerRole will start returning a different value for the Environment.CommandLine property sometime during the execution? That's what seems to be happening because it works at the beginning and then fails after a while (2-3 days.)

Related

EF EntityState.Modified Try Catch Issue

I have a code like this:
try
{
Member member = database.Members.Where(m=>m.ID=1).FirstOrDefault();
member.Name = "NewMemberName";
database.Entry(member).State = EntityState.Modified;
database.SaveChanges();
}
catch (Exception ex)
{
database.Logs.Add(new Log() { Value=ex.ToString() });
database.SaveChanges();
}
And Entity:
[StringLength(5)]
public string Name { get; set; }
If the Name String more than 5 it would be error and catch the exception ,but when I add a log then save ,the exception from SaveChange(); still remains,how should I do?(Can't change the schema)
the exception from SaveChange(); still remains
Well, if this throws an exception:
database.SaveChanges();
Then there's a pretty good chance that this will also throw an exception:
database.SaveChanges();
Basically, in your catch block you shouldn't be immediately re-trying the operation that just failed a millisecond ago. Instead, log the failure and handle the exception:
catch (Exception ex)
{
// DO NOT call SaveChanges() here.
}
Of course, if writing to the database is failing, then logging to the database is also likely to fail. Suppose for example that the connection string is wrong or the database is down or timing out. You can't log that.
I recommend using a logging framework (log4net, NLog, etc.) as a separate dependency from your Entity Framework data access layer. It's a small learning curve, but you end up with a pretty robust logging system that can much more effectively handle problems. And can be easily configured to log to multiple places, so if writing to one error log (the database) fails then you still have another one (a file, for example).
At the very least, if persisting your data context fails, you'll need to log to a new data context. Otherwise the part that failed is still there.
Something structurally more like this:
try
{
using (var database = new DbContext())
{
Member member = database.Members.Where(m=>m.ID=1).FirstOrDefault();
member.Name = "NewMemberName";
database.Entry(member).State = EntityState.Modified;
database.SaveChanges();
}
}
catch (Exception ex)
{
using (var database = new DbContext())
{
database.Logs.Add(new Log() { Value=ex.ToString() });
database.SaveChanges();
}
}

How to resolve a System.TimeoutException during MongoDB connection?

I've started using the MongoDB .Net driver to connect a WPF application to a MongoDB database hosted on MongoLabs.
But the following method I created to load the connection(called on the MainViewModel's constructor), threw a timeout exception on the line marked in the method below.
I tried to resolve the error further by adding an exception check of type MongoException to no avail. Also checked that the connection string is valid as per the docs and it seems so: (password starred out for security)
private const string connectionString = "mongodb://<brianVarley>:<********>#ds048878.mongolab.com:48878/orders";
The specific error thrown is as follows:
An exception of type 'System.TimeoutException' occurred in mscorlib.dll
Complete Error Link: http://hastebin.com/funanodufa.tex
Does anyone know the reason why I'm getting the timeout on my connection method?
public List<Customer> LoadCustomers()
{
var client = new MongoClient(connectionString);
var database = client.GetDatabase("orders");
//Get a handle on the customers collection:
var collection = database.GetCollection<Customer>("customers");
try
{
//Timeout error thrown at this line:
customers = collection.Find(new BsonDocument()).ToListAsync().GetAwaiter().GetResult();
}
catch(MongoException ex)
{
//Log exception here:
MessageBox.Show("A handled exception just occurred: " + ex.Message, "Connection Exception", MessageBoxButton.OK, MessageBoxImage.Warning);
}
return customers;
}
Solved this error by re-editing my connection string. I had left these two symbols in my connection string in error, '<' and '>' between the user name and password credentials.
Correct format:
"mongodb://brianVarley:password#ds054118.mongolab.com:54118/orders";
Incorrect format:
"mongodb://<brianVarley>:<password;>#ds054118.mongolab.com:54118/orders";

Catch MongoAuthenticationException in Mongo .NET 2.0 Driver

I'm doing MongoDB project based on .NET 2.0 driver which involves authentication to MongoDB. There is a example code for what i'm doing:
public static bool createConneciton(string login, SecureString pass, string authDB) {
var settings = new MongoClientSettings {
Credentials = new[] {
MongoCredential.CreateCredential(authDB, login, pass)
},
Server = new MongoServerAddress("my.mongodb.server", 27017)
};
mongoClient = new MongoClient(settings);
return true;
}
if (Mongo.createConneciton(textBoxUsername.Text, pass, textBoxAuthDatabase.Text))
Task<BsonDocument> results = Mongo.getNodeStats();
public static async Task<BsonDocument> getNodeStats() {
try {
var db = Mongo.mongoClient.GetDatabase("admin");
var command = new BsonDocument {
{"serverStatus",1}
};
BsonDocument result = await db.RunCommandAsync<BsonDocument>(command).ConfigureAwait(false);
return result;
}
catch (Exception ex)
{
Logging.Log(ex);
return null;
}
}
Main problem i encountered so far is processing user's credentials. Because all operations are lazy and connection opens only on execution in getNodeStats() method. So if user types wrong credentials, he is going to wait for 30 seconds because instead of MongoDB.AuthenticationException or even MongoDB.ConnectionException method going to though only System.Timeout exception. If you look though text of exception that is quite obvious that both are rised but not catched.
"MongoDB.Driver.MongoConnectionException: An exception occurred while opening a connection to the server. ---> MongoDB.Driver.MongoAuthenticationException: Unable to authenticate using sasl protocol mechanism SCRAM-SHA-1
My first thought was to force open connection to check for credentials as soon as user typed them and hit connect button rather then waiting for any command to be executed, but apparently MongoClient class does not have .Open() method anymore. So if it does not seem to be possible i at least would like to catch AuthenticationException without need to wait for timeout, but out of ideas where should i try and catch it.
You cannot connect mongodb using MongoCredential.CreateCredential.You have to use MongoCredential.CreateMongoCRCredential method to connect the db. Because the former credential use SCRAM-SHA-1 mechanism to connect db, in .NET which will fail. And the reason I have not make clear.
Using MongoCredential.CreateMongoCRCredential, you have change "authSchema" setting in mongodb. You can refer to MongoDB-CR Authentication failed

Test if MongoDB server is part of a replica set at run time

I have the same software deployed in multiple environments, some use a MongoDB replica set, and some use a single server. There are certain update operations where I use WriteConcern.WMajority, but this throws an exception if the server is not part of a replica set.
I'm looking for a way to ask the server if it is part of a replica set, so I will know if it is safe to use WriteConcern.WMajority. My attempt was this:
string connStr = System.Configuration.ConfigurationManager
.ConnectionStrings["connStrName"].ConnectionString;
var server = new MongoDB.Driver.MongoClient(connStr).GetServer();
bool isReplicaSet = server.GetDatabase("admin")
.RunCommand("replSetGetStatus").Ok;
But this throws MongoDB.Driver.MongoCommandException: Command 'replSetGetStatus' failed: not running with --replSet (response: { "ok" : 0.0, "errmsg" : "not running with --replSet" }). Is catching this exception my best option?
public bool IsPartOfReplicaSet(string connectionString)
{
var result = new MongoClient(connectionString)
.GetServer()
.GetDatabase("admin")
.RunCommand("getCmdLineOpts")
.Response["parsed"] as BsonDocument;
return result.Contains("replSet");
}

Annoying SQL exception, probably due to some code done wrong

I started working on this "already started" project, and I'm having a really annoying error when trying to execute some interactions with SQL Server 2008:
The server failed to resume the
transaction. Desc.:
One of these errors I get in this specific method call:
The aspx.cs Call:
busProcesso openProcess = new busProcesso(pProcessoId);
try
{
if (openProcess.GetDocument() == null)
{
//Irrelevant code.
}
}
catch{ //... }
The Business class (relevant part):
public class busProcesso : IbusProcesso
{
public Processo vProcesso { get; set; }
RENDBDataContext db;
public busProcesso()
{
vProcesso = new Processo();
}
public busProcesso(decimal pProcessoId)
{
db = new RENDBDataContext();
try
{
vProcesso = db.Processos.SingleOrDefault(x => x.Id == pProcessoId);
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
public string GetDocument()
{
try
{
string document = null;
foreach (Processo_has_Servico ps in ListaServicosProcesso())
{
if (ps.Servico.Document != null) //Get the error right at this line.
{
document = ps.Servico.Document;
}
}
return document ;
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
public IQueryable<Processo_has_Servico> ListaServicosProcesso()
{
db = new RENDBDataContext();
try
{
return from ps in db.Processo_has_Servicos
join s in db.Servicos on ps.Servico_Id equals s.Id
where ps.Processo_Id == vProcesso.Id
select ps;
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
}
As I said, the error occurs right at the line:
if (ps.Servico.Document != null) from the GetDocument() method.
Opening SQL Server Activity Monitor, I see there is a process for my database (.Net SqlClient Data Provider)
After some time/use (when I start to get the "server failed to resume the transaction" error), I go to the SQL Server Activity Monitor and there's around 5 or 6 more identical processes that weren't killed and (probably) should've been. When I manually kill them, the error stops for a while, until it starts again.
I'm not really good at working in OO and all, so I'm probably missing something, maybe some way to close one of these connections. Also, any help/tip about this structure will be welcome.
PS. The error doesn't happen everytime. Sometimes it runs just perfectly. Then it starts to give the error. Then it stops. Sometimes it happens just once.. pretty weird.
The code in ListaServicosProcesso is creating the context db. Then it is returning an IQueryable.
At this point no request has been sent to the database.
Then there is a for each in the code. At this point EF says "I need to get the data from the database". So it tries to get the data.
But the context db is now out of scope, so it crashes, on the first line that tries to use the data.
There are 2 ways to get around this:
return a list from ListaServicosProcesso, this will force the database call to execute
move the for each into ListaServicosProcesso
Edit
Pharabus is correct db is not out of scope. The problem is here:
db = new RENDBDataContext();
A new instance of the context is being created without the old one being disposed. Try Dispose of db at the end of ListaServicosProcesso. Even better place db in a using statement. But then the foreach must be moved inside the using statement.
Here's a couple of ideas to try.
1/ You can attach SQL server profiler to see the query that is being executed, which will allow you to copy and paste that query to see the data that is in the database. This might be help.
2/ You never check whether ps.Servico is null - you jump straight to ps.Servico.Document. If ps.Servico is null then you will get a null reference exception if you try to access any properties on that object.
I'm not sure of the exact cause of the error you're seeing (if you Google it, the references are all over the place...), but there are a few things you could improve in your code and I've found that just cleaning things up a bit often makes problems go away. Not always, but often.
I agree with the other answerers that it would help to keep better track of your DataContext(s). For example in you're creating it once in the constructor, then again in ListaServicosProcesso(). At that point vProcesso is on one DataContext and other entities will be on another, which gets messy.
I think you could simplify the whole thing a bit, for example you could combine GetDocument() and ListaServicosProcesso() like this:
public string GetDocument()
{
try
{
// Are you sure vProcesso is not null?
if (vProcesso == null)
return null;
// Only create the context if it wasn't already created,
if (db == null)
db = new RENDBDataContext();
return db.Processo_has_Servicos
.Where(ps => ps.Processo_Id == vProcesso.Id && ps.Servico.Document != null)
.Select(ps => ps.Servico.Document) // use an implicit join
.SingleOrDefault();
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}

Categories

Resources