Currently I'm working on widows service which is receiving messages from local private MSMQ. Queue is transactional.
Receiving is done like that:
public void ReceiveAndSaveData(MessageQueue queue, MsmqDbContext context)
{
var message = new Message();
try
{
using (var tx = new MessageQueueTransaction())
{
tx.Begin();
message = queue.Receive(tx);
var bodyReader = new StreamReader(message.BodyStream);
var jsonBody = bodyReader.ReadToEnd();
var messageData = JsonConvert.DeserializeObject<QueueMessage>(jsonBody);
/*THERE IS SOME DATA PROCESSING*/
tx.Commit();
}
}
catch (JsonSerializationException e)
{
Logger.WriteError(new LogDetail("Error occured during deserializing incoming data.", e, message.Id));
}
catch (Exception e)
{
Logger.WriteError(new LogDetail("Error occured during saving data to database", e, message.Id));
}
}
In case of JsonSerializationException, I want to delete this message from current queue. Does anybody know how to solve this problem?
Use the Abort() method and also move the tx-object creation outside the try-catch block.
public void ReceiveAndSaveData(MessageQueue queue, MsmqDbContext context)
{
bool exceptionOccurred = false;
var message = new Message();
MessageQueueTransaction tx;
try
{
exceptionOccurred = false;
using (tx = new MessageQueueTransaction())
{
tx.Begin();
message = queue.Receive(tx);
var bodyReader = new StreamReader(message.BodyStream);
var jsonBody = bodyReader.ReadToEnd();
var messageData = JsonConvert.DeserializeObject<QueueMessage>(jsonBody);
/*THERE IS SOME DATA PROCESSING*/
}
}
catch (JsonSerializationException e)
{
Logger.WriteError(new LogDetail("Error occured during deserializing incoming data.", e, message.Id));
tx.Abort(); //Rolls back the pending internal transaction
exceptionOccurred = true;
}
catch (Exception e)
{
Logger.WriteError(new LogDetail("Error occured during saving data to database", e, message.Id));
exceptionOccurred = true;
}
finally
{
if(!exceptionOccurred)
tx.Commit();
}
}
Abort() MSDN
Put tx.Commit() also inside the catch block of the JsonSerializationException
Related
I have simple Windows service which sends HTTP requests on few timer's. I installed Release version of this service and after few days running of it I noticed memory usage increase from ~5MB to ~32MB. This made me worried, I rarely do anything for desktop so I really lack knowledge to figure out where leak is happening...
Maybe log4net object is growing?
Here I initialize my service and it's configuration:
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private Historian historian;
private EndpointsConfiguration endpointsConfiguration;
private readonly string endpointsJson;
public Service()
{
InitializeComponent();
historian = new Historian(ConfigurationManager.ConnectionStrings["Historian"].ConnectionString);
try
{
string path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6);
endpointsJson = File.ReadAllText($#"{path}\EndpointsConfiguration.json");
var jsonOptions = new JsonSerializerOptions
{
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
}
};
endpointsConfiguration = JsonSerializer.Deserialize<EndpointsConfiguration>(endpointsJson, jsonOptions);
}
catch (Exception ex)
{
logger.Fatal("Nepavyko nuskaityti konfigūracijos", ex);
return;
}
}
OnStart method:
protected override void OnStart(string[] args)
{
logger.Info("Servisas startavo");
try
{
historian.Ping();
logger.Info("Pavyko prisijungti prie Historian duomenų bazės");
foreach (var endpoint in endpointsConfiguration.Endpoints)
{
var timer = new TimerWithContext(endpoint, endpoint.Interval)
{
Enabled = true
};
timer.Elapsed += async (sender, e) => await Timer_Elapsed(sender, e);
}
logger.Info("Suformuotos užduočių gijos");
}
catch (Exception ex)
{
logger.Fatal("Nepavyko prisijungti prie Historian duomenų bazės", ex);
OnStop();
}
}
Timer Elapsed (primary work of this service):
private async Task Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Endpoint endpoint = ((TimerWithContext)sender).Endpoint;
var endpointTags = endpoint.Tags;
try
{
historian.RetrieveLiveValues(ref endpointTags);
}
catch (Exception ex)
{
logger.Fatal($"Nepavyko nuskaityti naujausių tag'o reikšmių, Gavėjas:${endpoint.UrlAddress}", ex);
}
finally
{
using (HttpClient httpClient = new HttpClient())
{
if (endpoint.AuthScheme != null && endpoint.AuthKey != null)
{
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(endpoint.AuthScheme, endpoint.AuthKey);
}
object data = new { };
switch (endpoint.SerializationOption)
{
case SerializationOption.PECustom:
data = new DeviceComponents
{
SerialNr = endpoint.SerialNr,
MeterCode = endpoint.MeterCode,
ReadDate = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss}",
DevCompValues = endpointTags.ToDictionary(tag => tag.DestinationName, tag => tag.Value.ToString())
};
break;
default:
data = endpointTags.ToDictionary(tag => tag.DestinationName, tag => tag.Value.ToString());
break;
}
var content = new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json");
try
{
var response = await httpClient.PostAsync(endpoint.UrlAddress, content);
response.EnsureSuccessStatusCode();
logger.Info($"Duomenys perduoti gavėjui:{endpoint.Name}");
}
catch (Exception ex)
{
logger.Warn($"Nepavyko perduoti duomenų šaltiniui: {endpoint.Name}; Adresas{endpoint.UrlAddress}; Duomenų kiekis:{endpoint.Tags.Count}", ex);
}
}
}
}
We have a siglnalR hub hosted in IIS, and a WPF .net core application that connects. Everything is working perfectly on first run. However, when IIS recycles the application pool, the WPF client re-reconnects successfully, but, (so it seems) on another thread, as when the user attempts to perform an action (open a new WPF window) - the following error is thrown when creating a new instance of the window to open :-
"The calling thread must be STA, because many UI components require this"
This is how we connect to the hub :-
private async void Connect()
{
try
{
_signalRConnection.On<Notification>(NotificationMessageStr, (message) =>
{
if (message != null && _signalRConnection != null)
{
OnProcessMessage(message);
}
}
);
_signalRConnection.Reconnecting += error =>
{
OnReconnecting("Connection lost - Attempting to reconnect.");
return Task.CompletedTask;
};
_signalRConnection.Reconnected += connectionId =>
{
OnReconnected("Reconnected");
return Task.CompletedTask;
};
_signalRConnection.Closed += error =>
{
OnLostConnection("Failed to connect");
// Notify users the connection has been closed or manually try to restart the connection.
return Task.CompletedTask;
};
try
{
//Connect to the server
await _signalRConnection.StartAsync();
}
catch (Exception ex)
{
}
}
catch (Exception ex)
{
}
}
When a message is received from the hub, we call :-
private void SubscriveToNewNotification()
{
vm.NewNotification += (sender, e) => {
ShowNotificationAlert(e.NotificationMessage); };
}
private void ShowNotificationAlert(Notification notification) {
NotificationAlert notificationAlert = new NotificationAlert();
notificationAlert.notification = notification;
notificationAlert.Show();
}
And it is this:-
NotificationAlert notificationAlert = new NotificationAlert();
That is failing.
This is how the connection is built up :-
private void InitializeViewModel()
{
try
{
string serviceAddress = "xxxx/notificationHub";
connectHub = NotificationHubManager.CreateNotificationHub(serviceAddress, userInfo);
}
catch (System.Exception ex)
{
System.Windows.MessageBox.Show(ex.Message + "--");
}
connectHub.ProcessMessage += (sender, e) =>
{
// THIS IS WHERE IT FALLS OVER
NotificationAlert n = new NotificationAlert();
OnNotificationReceived(e.NotificationMessage);
};
-- This is the notification hub
public static NotificationHubConnect CreateNotificationHub(string address, ISwiftUser userInfo = null)
{
HubConnection hubConnection = new HubConnectionBuilder()
.WithUrl(address)
.WithAutomaticReconnect()
.Build();
try
{
var result = new NotificationHubConnect(hubConnection, userInfo);
return result;
}
catch (Exception ex)
{
throw ex;
}
}
Is there a way to have the reconnect run on the same thread?
A developer has written the following code below and I am trying to find a better way to refactor it:
try
{
using (var client = new WebClient())
{
var proxy = new WebProxy(address, portNo);
proxy.BypassProxyOnLocal = false;
proxy.UseDefaultCredentials = true;
client.UseDefaultCredentials = true;
result = client.DownloadString(httpURL);
}
}
catch (Exception ex)
{
log.Error("blah blah", ex);
try
{
SendNotification
}
catch (Exception emailEx)
{
log.Error("blahblah " + emailEx);
}
}
Is the using clause required to be inside a try/catch block, considering it itself is using try/finally? And then if an exception is thrown inside the using, how do I handle it?
Is there a better way to avoid the nested try/catch when sending a notification?
Try to call SendNotification when exception is thrown and handle exceptions in SendNotification():
try
{
using(var client = new WebClient())
{
var proxy = new WebProxy(address, portNo);
proxy.BypassProxyOnLocal = false;
proxy.UseDefaultCredentials = true;
client.UseDefaultCredentials = true;
result = client.DownloadString(httpURL);
}
}
catch (Exception ex)
{
log.Error("blah blah", ex);
SendNotification();
}
And SendNotification():
private void SendNotification()
{
try
{
// Here you are sending notifications
}
catch (Exception emailEx)
{
log.Error("blahblah " + emailEx);
}
}
The best way to avoid nesting is to make it in another function
catch (Exception ex)
{
log.Error("blah blah", ex);
FUNCTION_NAME()
}
private RETURN_TYPE FUNCTION_NAME()
{
try
{
SendNotification
}
catch (Exception emailEx)
{
log.Error("blahblah " + emailEx);
}
}
Many C# native libraries use the Try pattern to specify they will not throw:
For example:
bool Dictionary.TryAdd(element)
public DoEverything()
{
if(!TryDownload(..))
{
TrySendNotification();
}
}
public bool TryDownload(out result)
{
try {
using(var client = new WebClient())
{
var proxy = new WebProxy(address, portNo);
proxy.BypassProxyOnLocal = false;
proxy.UseDefaultCredentials = true;
client.UseDefaultCredentials = true;
result = client.DownloadString(httpURL);
return true;
}
}
catch (Exception ex)
{
log.Error("blah blah", ex);
return false;
}
}
public bool TrySendNotification()
{
try
{
// Here you are sending notifications
return true;
}
catch (Exception emailEx)
{
log.Error("blahblah " + emailEx);
return false;
}
}
I'm trying to port my code from an obsolete library called CastleMQ to NetMQ but I'm running into some problems.
I prefer to using polling with a timeout, for reliability - I just found that it worked best for me from trial and error compared to just sitting blocking the port indefinitely.
here is my CastleMQ code
public int ZeroPort;
private void ThreadProc()
{
var ctx = new Context();
try {
using (var repSocket = ctx.CreateSocket(SocketType.Rep))
{
string bindAddress = "tcp://*:"+ZeroPort;
repSocket.Bind(bindAddress);
print2("*** BINDING on {0} ***", bindAddress);
bool quit = false;
while (!quit) {
try {
var polling = new Polling(PollingEvents.RecvReady, repSocket);
polling.RecvReady += (socket) =>
{ // using socket.Recv() here is guaranted to return stuff
var msg = socket.Recv();
var msgStr = Encoding.UTF8.GetString(msg);
print2("[REP:{0}] {1}", bindAddress, msgStr);
switch (msgStr) {
case "positions": {
StringBuilder csv = new StringBuilder();
print2("csv: {0}", csv.ToString());
socket.Send(csv.ToString());
break;
}
default: {
socket.Send("Unrecognized Command: " + msgStr);
break;
}
}
};
polling.Poll(POLL_TIMEOUT_MS); // this returns once some socket event happens
} catch (Exception e) {
if (e is ThreadAbortException) {
quit = true;
print2("\n*** EXITED ***");
} else print2(e.ToString());
}
}
}
} catch (Exception e) {
print2(e.ToString());
} finally {
ctx.Dispose();
}
}
here is what I tried to do and then got lost with NetMQ
private void ThreadProc()
{
try {
string bindAddress = "#tcp://*:" + ZeroPort;
print2("*** BINDING on {0} ***", bindAddress);
using (var repSocket = new ResponseSocket(bindAddress))
using (var poller = new NetMQPoller { repSocket })
{
// bool quit = false;
// while (!quit)
// these event will be raised by the Poller
repSocket.ReceiveReady += (s, a) =>
{
// receive won't block as a message is ready
string msg = a.Socket.ReceiveString(); // defeinition for ReceiveString() can't be found
// send a response
a.Socket.Send("Response"); // it doesn't like "Response", do I need to wrap it in some object?
I'm especially confused as how to add a timeout so I can poll with a timeout in a loop the way my CastleMQ code does.
Any pointers would be much appreciated, thanks
I'm creating a UI that uses rabbitmq to receive multiple lists of type 'StorageMessage'. I'm using a background worker to merge all the data from the lists into a datatable and I bind to the gridview in the UI. I have put the method that receives the messages below, my problem is that the UI doesn't display all the data I expect it to. I'm guessing its because the background work is busy when the message comes in. Whats the correct approach to deal with these types of situations?
public void OnMessageArrived(MessageArrivedEventArgs<object> args)
{
var topicName = args.MessagingParticipant.TopicName;
if (_logger.IsInfoEnabled)
_logger.InfoFormat("Message Received from {0}", topicName);
try
{
if (args.To == _uniqueId.ToString() || args.To.EqualsOrdinalIgnoreCase("all"))
{
lock (_lock)
{
var receivedMessage = Serialization.FromJsonString<StorageMessage>(args.MessageBody);
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync(receivedMessage);
}
}
}
}
catch (Exception exception)
{
_logger.Error("An error occurred whilst processing the received message.", exception);
}
}
The RunWorkComplete Code looks lie
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
try
{
var res = e.Result as DataTable;
_storageDataTable = ReorderTable(res, "Date", "Factor", "Aldbrough", "Holford", "Humbly Grove", "Stublach", "Holehouse Farm", "Hatfield Moor", "Hornsea", "Hill Top", "Rough", "South Hook", "Isle Of Grain", "Dragon");
UpdateDataTable();
}
catch (Exception ex)
{
}
}
And the updateDataTable code is:
private void UpdateDataTable()
{
try
{
if (InvokeRequired)
{
BeginInvoke(new MethodInvoker(() => UpdateDataTable()));
}
else
{
radGridView1.SuspendLayout();
radGridView1.GroupDescriptors.Clear();
radGridView1.DataSource = null;
radGridView1.DataSource = _storageDataTable;
radGridView1.GroupDescriptors.Add("Factor", ListSortDirection.Ascending);
// radGridView1.MasterTemplate.AutoExpandGroups = true;
radGridView1.Refresh();
radGridView1.ResumeLayout(true);
}
}
catch (Exception exception)
{
_logger.Error("Encountered an error while updating the data table.", exception);
}
}
Thanks
Elias