I am connecting to an IBM Websphere MQ server in my .Net code and I wanted to make sure that I am following best practice when using "finally".
I currently have the below code block which I believe can be modified to just have the close portion in the finally clause. Is that correct? (I am catching errors in the calling portion of the application).
Hashtable properties = new Hashtable();
properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_CLIENT);
properties.Add(MQC.CHANNEL_PROPERTY, channel);
properties.Add(MQC.HOST_NAME_PROPERTY, host);
properties.Add(MQC.PORT_PROPERTY, port);
MQQueueManager qmgr = new MQQueueManager(queueManager, properties);
try
{
var queueDepth = qmgr.AccessQueue(userQueue,
MQC.MQOO_INPUT_AS_Q_DEF +
MQC.MQOO_FAIL_IF_QUIESCING +
MQC.MQOO_INQUIRE).CurrentDepth;
if (qmgr.IsOpen)
qmgr.Close();
return queueDepth;
}
finally
{
if (qmgr.IsOpen)
qmgr.Close();
}
Is now this
Hashtable properties = new Hashtable();
properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_CLIENT);
properties.Add(MQC.CHANNEL_PROPERTY, channel);
properties.Add(MQC.HOST_NAME_PROPERTY, host);
properties.Add(MQC.PORT_PROPERTY, port);
MQQueueManager qmgr = new MQQueueManager(queueManager, properties);
try
{
var queueDepth = qmgr.AccessQueue(userQueue,
MQC.MQOO_INPUT_AS_Q_DEF +
MQC.MQOO_FAIL_IF_QUIESCING +
MQC.MQOO_INQUIRE).CurrentDepth;
return queueDepth;
}
finally
{
if (qmgr.IsOpen)
qmgr.Close();
}
EDIT: Renan made a good suggestion. I didn't think the MQQueueManger was disposable. Sounds like I could potentially do this:
using(MQQueueManager qmgr = new MQQueueManager(queueManager, properties))
{
var queueDepth = qmgr.AccessQueue(userQueue,
MQC.MQOO_INPUT_AS_Q_DEF +
MQC.MQOO_FAIL_IF_QUIESCING +
MQC.MQOO_INQUIRE).CurrentDepth;
return queueDepth;
}
Edit: I did some research after reading Renan's suggestion and found the below. Sounds like they did in fact make it disposable.
MQ.Net
You are right. The finally clause will execute even if the code in the try block returns an exception.
You could also use the "using" construct for the connection (if it implements IDisposable, which it should).
using(qmgr){
//do stuff
}
That is fine.
A finally block is guaranteed by the CLR to be called (except in some very very rare edge cases, which IIRC are internal CLR errors, such as a call to FailFast or an ExecutingEngineException). By removing it from the try, you are removing redundant code.
First of all, there is no valid reason that an application needs to know the depth of a queue. Applications should process ALL messages in the queue until it is empty.
Secondly, do NOT use IsOpen methods as they do not work as you might expect. The IsOpen method does not actually check if the queue handle is open - it only checks an internal flag. Hence, do not use it.
Third, you do NOT close a queue manager object but rather you disconnect from a queue manager.
Fourth, when connecting to a queue manager, that statement needs to be in a try/catch because it will throw an MQException if the connection fails.
Here is a better layout of the code which will catch and handle errors:
MQQueueManager qMgr = null;
MQQueue queue = null;
int openOptions = MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING + MQC.MQOO_INQUIRE;
try
{
qMgr = new MQQueueManager(qMgrName);
System.Console.Out.WriteLine("Successfully connected to " + qMgrName);
queue = qMgr.AccessQueue(qName, openOptions, null, null, null);
System.Console.Out.WriteLine("Successfully opened " + qName);
System.Console.Out.WriteLine("Current queue depth is " + queue.CurrentDepth);
}
catch (MQException mqex)
{
System.Console.Out.WriteLine("Exception CC=" + mqex.CompletionCode + " : RC=" + mqex.ReasonCode);
}
catch (System.IO.IOException ioex)
{
System.Console.Out.WriteLine("Exception ioex=" + ioex);
}
finally
{
try
{
if (queue !=null)
{
queue.Close();
System.Console.Out.WriteLine("Successfully closed " + qName);
}
}
catch (MQException mqex)
{
System.Console.Out.WriteLine("Exception on close CC=" + mqex.CompletionCode + " : RC=" + mqex.ReasonCode);
}
try
{
if (qMgr !=null)
{
qMgr.Disconnect();
System.Console.Out.WriteLine("Disconnected from " + qMgrName);
}
}
catch (MQException mqex)
{
System.Console.Out.WriteLine("Exception on disconnect CC=" + mqex.CompletionCode + " : RC=" + mqex.ReasonCode);
}
}
Related
I have a problem in activemq. I want to receive a special message from my activemq queue. I have there over 300 Messages, and I want one of the message. I solved this with a multiselectcombobox. In this box I have all messages with all properties I need.
When I click on the 247 item, I want do select the item to receive the message, after them I want to send the message but first I have a problem with the receive.
I don't know why it doesn't work. Maybe someone has an idea?
ErrorMessageProperty prop = new ErrorMessageProperty();
IMessage message = null;
try
{
string MsgID = MSGID;
string desinationque = sourceQueue;
string selector = "ProducerId = '" + MsgID + "'";
IDestination dest = MQSession.GetDestination(desinationque);
Uri _activeMQURI = new Uri(conf.ActiveMqURL);
MQConnectionFactory = new NMSConnectionFactory(_activeMQURI);
using (MQConnection = MQConnectionFactory.CreateConnection(conf.ActiveMqUser, conf.ActiveMqPWD))
using (MQSession = MQConnection.CreateSession(AcknowledgementMode.AutoAcknowledge))
{
try
{
MQConnection.Start();
}
catch (Exception ex)
{
myLogger.NLogger.Info("MQReceiveTextMessage Connection fehlgeschlagen: " + ex.Message);
}
using (IMessageConsumer consumer = this.MQSession.CreateConsumer(dest, selector,false))
{
if (shallwait)
{
try
{
message = consumer.Receive();
}
catch (Exception ex)
{
myLogger.NLogger.Error("Error in consumer Receive (MQReceiveTextMessage): Message" + message + " Fehler-Exception: " + ex.Message);
}
}
else
{
message = consumer.Receive(TimeSpan.FromSeconds(1));
}
}
}
}
catch (Exception ex)
{
myLogger.NLogger.Error("Error in MQReceiveTextMessage: Parameter: sourceQueue: " + sourceQueue + " MSGID: " + MSGID + " Message: " + message + " Fehler-Exception: " + ex.Message);
}
return message;
}
My ProducerID is correct. But why doesn't this work? It stops at the line
message = consumer.receive();
I don't know anymore
With the selector ProducerId = 'MsgIDValue', the operation consumer.receive() is searching a Message in the queue with a custom property "ProducerId" with the value of the variable MsgID. If the message is not found the consumer waits new messages.
If you want to search for a default message field, message header field references are restricted to JMSDeliveryMode, JMSPriority, JMSMessageID, JMSTimestamp, JMSCorrelationID, and JMSType. JMSMessageID, JMSCorrelationID, and JMSType values may be null and if so are treated as a NULL value.
Source Message Selectors
I used Apache.NMS and Apache.NMS.ActiveMQ (1.7.1.3924)
is it possible to u se this api than the jms?
I try this since 1 Week and the selector does'nt work....
Maybe someone othe
this is my first question in here.
So I have this app that connects to a remote database using Npgsql library.
I have a method that connects to the db, execute a query, and finally it closes the connection.
It work fine, but the problem is that if, while the program is running but not calling the method, I disconnect the WiFi to simulate the inability to connect to the server, and then run the method, the connection method still is able to open the connection. This causes the query to get stuck.
I can't seem to find a way to check if I can connect to server because, even if I disconnect the internet, the NpgsqlConnection.Open() method still opens it.
Sorry about my english
public static NpgsqlConnection ConnectRemote()
{
try
{
remoteConnection = new NpgsqlConnection("Server = " + remoteData.server + "; " +
"Port = " + remoteData.port + "; " +
"User Id = " + remoteData.user + "; " +
"Password = " + remoteData.password + "; " +
"Database = " + remoteData.dataBase + "; ");
remoteConnection.Open();
}
catch (NpgsqlException ex)
{
throw;
}
catch (Exception ex)
{
remoteConnection.Close();
remoteConnection = null;
}
return remoteConnection;
}
public static bool CheckRemote()
{
if (remoteConnection != null)
{
if (remoteConnection.FullState.Equals(ConnectionState.Open))
return true;
return false;
}
return false;
}
public bool AddNewProduct(Product product)
{
try
{
DBManager.ConnectLocal();
DBManager.ConnectRemote();
object[] parameters;
if (DBManager.CheckRemote())
{
if (!DBManager.isSyncronized)
{
DBManager.Syncronize();
}
parameters = new object[8];
parameters[0] = 1;
parameters[1] = product.id;
parameters[2] = product.description;
parameters[3] = (decimal)product.salePrice;
parameters[4] = (decimal)product.cost;
parameters[5] = product.minStock;
parameters[6] = product.providerName;
parameters[7] = product.category;
DBManager.RunFunction(DBManager.remoteConnection, DBProcedures.createProduct, parameters);
}
else
{
string sql = "select * from createproduct(1, " + product.id + ", '" + product.description + "', " + (decimal)product.salePrice + ", "
+ (decimal)product.cost + ", " + product.minStock + ", '" + product.providerName + "', '" + product.category + "'); ";
parameters = new object[1];
parameters[0] = sql;
DBManager.RunFunction(DBManager.localConnection, "addsync", parameters);
DBManager.isSyncronized = false;
}
parameters = new object[6];
parameters[0] = product.description;
parameters[1] = (decimal)product.salePrice;
parameters[2] = (decimal)product.cost;
parameters[3] = product.minStock;
parameters[4] = product.providerName;
parameters[5] = product.category;
DataTable result = DBManager.RunFunction(DBManager.localConnection, DBProcedures.createProduct, parameters);
DBManager.DisconnectLocal();
DBManager.DisconnectRemote();
return true;
}
catch (Npgsql.NpgsqlException ex)
{
return false;
}
}
A few things -- one unrelated, and two related. I am hopeful that some combination of these will help.
First, the unrelated comment. The NpgSqlStringBuilder class is a nice tool to help demystify the connection strings. I realize yours works, but as you have to make edits (as I will suggest in a minute), I find it much easier to use than navigating String.Format, just as Query Parameters are easier (on top of being more secure) than trying to string.Format your way through passing arguments to a query. Also, declare the ApplicationName in your connection string to help diagnose what exactly is happening on the server, like you will read in the next comment.
If you are using connection pooling, When a connection is closed, I don't think it's really closed -- not even on the database. If you open server admin, you will see what I mean -- it kind of dangles out there, waiting to be reused. Try setting pooled=false in your connection string to ensure that when you close a connection you really close it.
If this doesn't work, try a trivial query. The cost will be minimal in cases where you don't need it and will undoubtedly fix your use case when you do need it.
All three suggestions are reflected here:
public static NpgsqlConnection ConnectRemote()
{
NpgsqlConnectionStringBuilder sb = new NpgsqlConnectionStringBuilder();
sb.ApplicationName = "Connection Tester";
sb.Host = remoteData.server;
sb.Port = remoteData.port;
sb.Username = remoteData.user;
sb.Password = remoteData.password;
sb.Database = remoteData.database;
sb.Pooling = false;
remoteConnection = new NpgsqlConnection(sb.ToString());
try
{
remoteConnection.Open();
NpgSqlCommand test = new NpgSqlCommand("select 1", remoteConnection);
test.ExecuteScalar();
}
catch (NpgsqlException ex)
{
throw;
}
catch (Exception ex)
{
remoteConnection.Close();
remoteConnection = null;
}
return remoteConnection;
}
I'm writing a part of a program that shall copy a batch of files from the current computer to a defined list of computers.
If these computers are not available, the code will hang for a long time trying to access them. Is there any functionallity in C# to check if the machine is available and then skip if it's not?
MFWs = File.ReadAllLines(GuiManager.MyConfigManagerConfig.MachinesList);
foreach (string MFW in MFWs)
{
if (MFW != System.Environment.MachineName)
{
String target = #"\\" + MFW + #"\D\IbSi\config\" + Path.GetFileName(ConfigFile);
String backup = #"\\" + MFW + #"\D\IbSi\userdata\" + Path.GetFileName(ConfigFile);
try
{
File.Copy(source, target, true);
File.Copy(source, backup, true);
}
catch (Exception ex)
{
Manager.SendMessage("Failed to copy " + Path.GetFileName(ConfigFile) + " to " + MFW + "\n" + ex.Message);
}
}
}
You could ping the computer before starting the copy (taken from this answer):
using System.Net.NetworkInformation;
public static bool IsHostAvailable(string nameOrAddress)
{
bool pingable = false;
Ping pinger = new Ping();
try
{
PingReply reply = pinger.Send(nameOrAddress);
pingable = reply.Status == IPStatus.Success;
}
catch (PingException)
{
// Discard PingExceptions and return false;
}
return pingable;
}
As noted in the comments you need to make sure the firewall on the servers is open for pings (ICMP echo requests)
I have code below in global asax now, I want to store exception log in database, is this good practice? because if sql error happens there, I want to log it too. So I am thinking changing the code below to write text log instead email, then on sql error, write text log.
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
string testEnvironment = ConfigurationSettings.AppSettings["isTestEnvironment"];
if (testEnvironment == "0")
{
Exception ex = Server.GetLastError();
if (ex is HttpException && ex.InnerException is ViewStateException)
{
Response.Redirect(Request.Url.AbsoluteUri)
return
}
StringBuilder theBody = new StringBuilder();
theBody.Append("URL: " + Request.Url + "\n");
theBody.Append("Referer: " + Request.ServerVariables["HTTP_REFERER"] + "\n");
theBody.Append("IP: " + Request.ServerVariables["REMOTE_HOST"] + "\n");
theBody.Append("Error Message: " + ex.ToString() + "\n");
if (User.Identity.IsAuthenticated)
theBody.Append("User: " + User.Identity.Name + "\n");
else
theBody.Append("User is not logged in." + "\n");
theBody.Append("Form Values: " + "\n");
foreach (string s in Request.Form.AllKeys)
{
if (s != "__VIEWSTATE")
theBody.Append(s + ":" + Request.Form[s] + "\n");
}
theBody.Append("Session Values: " + "\n");
foreach (string s in Session.Keys)
theBody.Append(s + ":" + Session[s] + "\n");
System.Net.Mail.MailMessage email = new System.Net.Mail.MailMessage();
email.IsBodyHtml = false;
email.From = new System.Net.Mail.MailAddress("errors#karpach.com", "ErrorManager");
email.To.Add(new System.Net.Mail.MailAddress("errornotification#karpach.com", "Developer"));
email.Subject = Request.Url.ToString().Split('/')[2] + " has ASP.NET error";
email.Body = theBody.ToString();
try
{
System.Net.Mail.SmtpClient emailProvider = new System.Net.Mail.SmtpClient();
emailProvider.Send(email);
}
catch (Exception anException)
{
}
finally
{
if (Request.Url.Segments[Request.Url.Segments.Length - 1].ToLower() != "error.aspx")
Response.Redirect("~/error.aspx?msg=4");
else
{
Response.Write(#"We encountered an internal error. We apologize for any inconvenience
but know that our staff gets emailed EVERY error that occurs so that we can solve it promptly.");
Response.End();
}
}
}
}
You could log it to the EventLog. System admins can setup monitoring to see when new events are added and be alerted to potential problems.
Here's an example from MSDN for the EventLog class:
if(!EventLog.SourceExists("MySource"))
{
//An event log source should not be created and immediately used.
//There is a latency time to enable the source, it should be created
//prior to executing the application that uses the source.
//Execute this sample a second time to use the new source.
EventLog.CreateEventSource("MySource", "MyNewLog");
Console.WriteLine("CreatedEventSource");
Console.WriteLine("Exiting, execute the application a second time to use the source.");
// The source is created. Exit the application to allow it to be registered.
return;
}
// Create an EventLog instance and assign its source.
EventLog myLog = new EventLog();
myLog.Source = "MySource";
// Write an informational entry to the event log.
myLog.WriteEntry("Writing to event log.");
I am scraping the content of web pages heavily in a multi-thread environment. I need a reliable downloader component that is tolerable to temporary server failures, connection drops, etc. Below is what my code looks like.
Now, I am having a weird situation over and over: It all starts perfectly. 10 threads pull data concurrently for about 10 minutes. After that time I start getting WebException with timeouts right after I call the GetResponse method of my request object. Taking a break (getting a thread to sleep) doesn't help. It only helps when I stop the application and start it over until the next 10 minutes pass and the problem comes back again.
What I tried already and nothing has helped:
to close/dispose the response object explicitly and via the "using" statement
to call request.Abort everywhere it could have helped
to manipulate timeouts at ServicePointManager/ServicePoint and WebRequest level (extend / shorten the timeout interval)
to manipulate the KeepAlive property
to call to CloseConnectionGroup
to manipulate the number the threads that run simultaneously
Nothing helps! So it seems like it's a bug or at least very poorly documented behavior. I've seen a lot of question regarding this in Google and on Stackoverflow, but non of them is fully answered. Basically people suggest one of the things from the list above. I tried all of them.
public TResource DownloadResource(Uri uri)
{
for (var resourceReadingAttempt = 0; resourceReadingAttempt <= MaxTries; resourceReadingAttempt++)
{
var request = (HttpWebRequest)WebRequest.Create(uri);
HttpWebResponse response = null;
for (var downloadAttempt = 0; downloadAttempt <= MaxTries; downloadAttempt++)
{
if (downloadAttempt > 0)
{
var sleepFor = TimeSpan.FromSeconds(4 << downloadAttempt) + TimeSpan.FromMilliseconds(new Random(DateTime.Now.Millisecond).Next(1000));
Trace.WriteLine("Retry #" + downloadAttempt + " in " + sleepFor + ".");
Thread.Sleep(sleepFor);
}
Trace.WriteLine("Trying to get a resource by URL: " + uri);
var watch = Stopwatch.StartNew();
try
{
response = (HttpWebResponse)request.GetResponse();
break;
}
catch (WebException exception)
{
request.Abort();
Trace.WriteLine("Failed to get a resource by the URL: " + uri + " after " + watch.Elapsed + ". " + exception.Message);
if (exception.Status == WebExceptionStatus.Timeout)
{
//Trace.WriteLine("Closing " + request.ServicePoint.CurrentConnections + " current connections.");
//request.ServicePoint.CloseConnectionGroup(request.ConnectionGroupName);
//request.Abort();
continue;
}
else
{
using (var failure = exception.Response as HttpWebResponse)
{
Int32 code;
try { code = failure != null ? (Int32)failure.StatusCode : 500; }
catch { code = 500; }
if (code >= 500 && code < 600)
{
if (failure != null) failure.Close();
continue;
}
else
{
Trace.TraceError(exception.ToString());
throw;
}
}
}
}
}
if (response == null) throw new ApplicationException("Unable to get a resource from URL \"" + uri + "\".");
try
{
// response disposal is required to eliminate problems with timeouts
// more about the problem: http://stackoverflow.com/questions/5827030/httpwebrequest-times-out-on-second-call
// http://social.msdn.microsoft.com/Forums/en/netfxnetcom/thread/a2014f3d-122b-4cd6-a886-d619d7e3140e
TResource resource;
using (var stream = response.GetResponseStream())
{
try
{
resource = this.reader.ReadFromStream(stream);
}
catch (IOException exception)
{
Trace.TraceError("Unable to read the resource stream: " + exception.ToString());
continue;
}
}
return resource;
}
finally
{
// recycle as much as you can
if (response != null)
{
response.Close();
(response as IDisposable).Dispose();
response = null;
}
if (request != null)
{
//Trace.WriteLine("closing connection group: " + request.ConnectionGroupName);
//request.ServicePoint.CloseConnectionGroup(request.ConnectionGroupName);
request.Abort();
request = null;
}
}
}
throw new ApplicationException("Resource was not able to be acquired after several attempts.");
}
i have same problem i have search a lot on internet , i got 1 solution, fix the number of thread at a time .you have to control the number of thread at a time, i have started to use 2-3 thread at a time.
also use this ServicePointManager.DefaultConnectionLimit = 200;
this will really help you.