Can't de-serialize Message.Body when reading from MSMQ - c#

I've seen several other posts here with the same problem, but none offer a solution. And what's really odd is that this works in dev, but not in prod.
I am submitting a message to a queue as follows:
public void QueueMessage(LeadSubmissionMessage message)
{
using (var queue = new MessageQueue(MessageQueuePath))
{
queue.DefaultPropertiesToSend.Recoverable = true; // always send as recoverable
queue.Send(message);
}
}
This is the LeadSubmissionMessage class:
[Serializable]
public class LeadSubmissionMessage
{
public long LeadId { get; set; }
public long UserId { get; set; }
public DateTime DateTime { get; set; }
}
This is the message, in raw text:
<?xml version="1.0"?>
<LeadSubmissionMessage xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<LeadId>194018</LeadId>
<UserId>300</UserId>
<DateTime>2016-05-17T14:52:30.1484784Z</DateTime>
</LeadSubmissionMessage>
That all works fine. But on the receiving end, and only in production, when we do this:
body = message.Body;
It throws this error:
System.InvalidOperationException: Cannot deserialize the message passed as an argument. Cannot recognize the serialization format.
at System.Messaging.XmlMessageFormatter.Read(Message message)
at System.Messaging.Message.get_Body()
It works find in Dev and Staging. I'm trying to minimize and eliminate the points where things could be different, but I've run out of things to check. They are all running the same build version (release). Any MSMQ related config keys match (except for the obvious queue names and locations). One possible variation is the version of MSMQ installed on the machine? But I'm not sure how to check that. Would the OS make a difference? Can't imagine it would.

I'm using it in the following way:
private static MyMessage RecieveMessage()
{
if (!MessageQueue.Exists(QueueName))
{
return null;
}
using (var msmq = new MessageQueue(QueueName))
{
msmq.Formatter = new XmlMessageFormatter(new Type[] { typeof(MyMessage) });
var message = msmq.Receive();
return message != null && message.Body is MyMessage ? (MyMessage)message.Body : null;
}
}
Not sure what's the problem in your case, but you could try to make it similar to my approach and see if it's working for you.

Related

C# Winforms Crashing from external function without exception, with exit code 40445582 (0x269268e)

As the title suggests, I have a Winform written in C# .Net Framework 4.8; it calls the MAPISendMail external function from the mapi32.dll to open up a new message window in Outlook for the user, initially populated with a to address and message (and sometimes an attachment):
[DllImport("MAPI32.DLL")]
public static extern int MAPISendMail(IntPtr session, IntPtr hwnd, MapiMessage message, int flg, int rsv);
NOTE: If there is anything that you know that could replace MAPI for the usage described, that would be phenomenal.
For whatever reason, every now and again this will end up causing the whole winform to hang for a bit, then close. There is no indication that this is going to happen aside from the aforementioned hanging, and no pattern as far as I can tell; I can go hours without ever encountering it.
Additionally, NO try/catch blocks will be caught when this happens. I have tried catching the standard Exception of course, but also RuntimeWrappedException and that doesn't get triggered either:
try
{
error = MAPIHelperInterop.MAPISendMail(IntPtr.Zero, IntPtr.Zero, message, MAPI_DIALOG, 0);
}
catch (RuntimeWrappedException rwe)
{
throw rwe.InnerException;
}
catch (Exception e)
{
throw e;
}
The only indication that something is wrong is the final line in the Debug output, stating "The program 'PROGRAMNAME' has exited with code 40445582 (0x269268e)". I have googled my hands off trying to find a meaning to this code and have found nothing. Does anyone have any insight on what could be going on here, maybe even a way I can catch this error to prevent the form from closing?
I was essentially asking the wrong question. Thanks to Hans Passant and Ian Kemp for pointing out MAPI is long deprecated and should be avoided.
In its place, I used Microsoft.Office.Interop.Outlook thanks to this SO question and made a very simple wrapper class:
public class OutlookEmail
{
public OutlookEmail() { }
public OutlookEmail(params string[] toAddrs)
{
To.AddRange(toAddrs);
}
private Application OApp = new Application();
public List<string> To { get; set; } = new List<string>();
public string Subject { get; set; }
public string Body { get; set; }
public List<string> Attachments { get; set; } = new List<string>();
public void ShowDialog()
{
_MailItem oMailItem = (_MailItem)OApp.CreateItem(OlItemType.olMailItem);
oMailItem.To = string.Join("; ", To);
// body, bcc etc...
oMailItem.Subject = Subject;
oMailItem.Body = Body;
if(Attachments != null)
{
foreach (string path in Attachments)
{
oMailItem.Attachments.Add(path);
}
}
oMailItem.Display(true);
}
}
NOTE: this will ONLY work for Outlook; luckily for me, ALL of my users definitely use Outlook.

Use Try and Catch in a method to verify HttpWebRequest

I am learning C #, with this class I get information in JSON from an API, then from the form I call my class "MyClass" to put the values in the corresponding fields, but I do not know how to detect if the connection with the API was unsuccessful, I know that try and catch must be used and that's why I put it in my "MyClass" class but I do not know how to do the verification correctly:
I have these defined classes:
public class Lawyer
{
public string type { get; set; }
public string numdoc { get; set; }
public string name { get; set; }
public string date { get; set; }
}
public class Worker
{
public string time { get; set; }
public string service { get; set; }
}
public class Result
{
public string id { get; set; }
public string name { get; set; }
public string Condition { get; set; }
public string PLE { get; set; }
public List<Lawyer> lawyers { get; set; }
public List<Worker> workers { get; set; }
}
public class RootObject
{
public bool success { get; set; }
public Result result { get; set; }
}
And it is my "MyClass" (I tried using the "try" and the "catch" but I do not know if it is the correct way to do it...):
class MyClass
{
public RootObject MyMethod(int inRUC){
try {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(#"https://www.example.com/api/?get=" + inRUC);
HttpWebResponse response;
response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
{
var json = reader.ReadToEnd();
return JsonConvert.DeserializeObject<RootObject>(json);
}
}
catch (Exception)
{
return null;
}
}
}
This is the section of my form that calls the class, it works fine but I do not know how to verify from here that the connection with the API was successful:
private void Button1_ClickBefore(object sboObject, SAPbouiCOM.SBOItemEventArg pVal, out bool BubbleEvent)
{
if (string.IsNullOrEmpty(txtRuc1.Value.ToString()))
{
BubbleEvent = false;
}
else
{
BubbleEvent = true;
int para = 0;
int.TryParse(txtRuc1.Value, out para);
MyClass obj = new MyClass();
EditText1.Value = obj.MyMethod(para).result.name;
}
}
Do not do this:
catch (Exception)
{
return null;
}
This will simply "swallow" any runtime errors. If the connection fails, obj.MyMethod(para).result.name; will give you a NullpointerException that doesn't tell you what exactly went wrong. Instead take a look at what could possibly go wrong within "MyMethod" and which specific exceptions that would cause. Catch only exceptions that you know how to handle. If you don't (yet) know how to handle a specific exception, don't catch it. This will cause your program to crash with a somewhat meaningful error message. Work your your way from there. Try everything you can come up with to make the connection fail and observe which exceptions are thrown, so you might come up with a way to prevent those situations or recover from them.
Your doubt is right. This is not correct way to handle exception in your case.
You should use WebException which will give you an opportunity to read the response sent by server. Here, you can check details of the errorsome response received from the API and take appropriate action. Below is sample code for your reference. You can tweak it to your need.
catch (WebException e)
        {
            using (WebResponse response = e.Response)
            {
                HttpWebResponse httpResponse = (HttpWebResponse)response;
                Console.WriteLine("Error code: {0}", httpResponse.StatusCode);
                using (Stream data = response.GetResponseStream())
                {
                    string text = new StreamReader(data).ReadToEnd();
                    Console.WriteLine(text);
                }
            }
        }
You can get more details about WbeException from here: https://learn.microsoft.com/en-us/dotnet/api/system.net.webexception?view=netframework-4.7.2
And some more details with code sample here: https://learn.microsoft.com/en-us/dotnet/framework/network-programming/handling-errors
You should not create a class just for a method. You can put this method aside your UI event handler - if it is used only there. Or create a static helper class for all your API calls - or not static if you are reusing something between calls, like cookies. But then create an instance for the whole UI or at most for the form.
Please note, that API call might succeed technically and you still get an error message back. Check StatusCode property before trying to deserialize. You will most likely get IOException or WebException if there is a network or http level problem. If the server code is faulting or you passed invalid parameters, you will get a status code different than 200 (OK) - there are other success status codes trough. But you can get also content parsing exceptions. Always log such exceptions, even temporarily, but never handle with just noticing it!
But I suggest you using HttpClient class instead with HttpContentExtensions methods. There are many advantages, as this is optimized for API calls and it supports async for all operations. And the later package makes it easy to handle custom objects when reading or sending with any method. Beware, HttpClient instances are optimized for reusability even across threads - thus you can have only one or few in your application. Unfortunately, I haven't found any complete tutorial in this topic to link to.

NetworkComms custom object error - "objectToSerialize must implement IExplicitlySerialize"

I get this error from the SendObject method when I try to serialize an object just as the NetworkComms example says to do it. This seems like something silly, but I can't figure out what I need to do, and I don't think implementing the IExplicitlySerialize interface is the answer. Here is my calling method and the serialized class:
public static void SendTestPacket()
{
var message = "This is a test packet";
NetworkComms.SendObject("PacketPrintToConsole", "192.168.1.105", 5614, new PacketPrintToConsole(message));
}
[ProtoContract]
public class PacketPrintToConsole
{
[ProtoMember(1)]
public string Message { get; set; }
public PacketPrintToConsole() { }
public PacketPrintToConsole(string message)
{
this.Message = message;
}
}
Maybe you already figured it out, but for everyone else finding this here (like me). Here´s the answer.
That error message tells you, that you have to define a serializer.
You have an object you want to send, but you didn´t tell NetworkComms what serializer to use.
So you can either implement IExplicitlySerialize in your object or use a serializer that has already been created for protobuf-net.
You need to use the NetworkCommsDotNet.DPSBase.ProtobufSerializer.
You have to reference the ProtobufSerializer.dll compiled from the NetworkComms source you can get on github and then define the SendReceiveOptions.
Example:
SendReceiveOptions customSendReceiveOptions = new SendReceiveOptions<ProtobufSerializer>();
ConnectionInfo connectionInfo = new ConnectionInfo("192.168.1.105", 5614);
TCPConnection serverConnection = TCPConnection.GetConnection(connectionInfo, customSendReceiveOptions);
var message = "This is a test packet";
serverConnection.SendObject("PacketPrintToConsole", new PacketPrintToConsole(message));
This has only to be done where the object will be serialized to be sent.
A receiving client just need´s to have protobuf-net with the same object class to deserialize into.
Example with SendReceiveObject to request a message.
SendReceiveOptions customSendReceiveOptions = new SendReceiveOptions<ProtobufSerializer>();
NetworkComms.AppendGlobalIncomingPacketHandler<int>("GetMessage", GetMessageRequest, customSendReceiveOptions);
The method to send the result:
private static void GetMessageRequest(PacketHeader packetheader, Connection connection, int incomingobject)
{
connection.SendObject("MessageReply", new MessageObject(message));
}
And on the client side then:
ConnectionInfo connectionInfo = new ConnectionInfo("192.168.2.105", 5614);
TCPConnection serverConnection = TCPConnection.GetConnection(connectionInfo);
MessageObject myMessageObject = serverConnection.SendReceiveObject<ImageWrap>("GetMessage", "MessageReply", 1000);
if (myMessageObject != null)
{
Console.WriteLine(myMessageObject.Message);
}

Rebus: advice for adding a usercontext to each message

First let's define 'UserContext' as being a number of properties required to execute the receiving message in the correct context of the user, so it is a bit more than just a string. In my case this also includes data on which application 'instance' the user was working.
As I see it there are 2 main options to provide a 'UserContext' for a message:
As a Header
As a base class for the message
When using a Header, I need to provide my own serialization, when using a base class, Rebus will solve the serialization for me.
So I spiked using a base class using a little sample program:
public class UserContext
{
public string Name { get; set; }
public int UserId { get; set; }
public Guid AppId { get; set; }
}
public class UserContextMessageBase
{
public UserContext UserContext { get; set; }
}
public class SimpleMessage : UserContextMessageBase
{
public string Data { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
using (var adapter = new BuiltinContainerAdapter())
using (var timer = new Timer())
{
//adapter.Register(typeof(UserContextHandler));
adapter.Register(typeof(SimpleMessageHandler));
var bus = Configure.With(adapter)
.Transport(t => t.UseMsmqAndGetInputQueueNameFromAppConfig())
.MessageOwnership(d => d.FromRebusConfigurationSection())
//.SpecifyOrderOfHandlers(o => o.First<UserContextHandler>())
.CreateBus()
.Start();
timer.Elapsed += delegate
{
bus.Send(new Messages.SimpleMessage { Data = Guid.NewGuid().ToString() });
};
timer.Interval = 10000;
timer.Start();
Console.WriteLine("Press enter to quit");
Console.ReadLine();
}
}
}
internal class UserContextHandler : IHandleMessages<UserContextMessageBase>
{
protected UserContext _context;
public void Handle(UserContextMessageBase message)
{
var old = Console.ForegroundColor;
if (_context != null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Context is already populated");
}
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine("Processing UserContextMessageBase");
// create the correct Context to process the message
_context = message.UserContext;
Console.ForegroundColor = old;
}
}
internal class SimpleMessageHandler : **UserContextHandler**, IHandleMessages<SimpleMessage>
{
public void Handle(SimpleMessage message)
{
// allow to use the _context to process this message
Console.WriteLine("Received SimpleMessage {0}", message.Data);
}
}
But when I run the program, I see that the SimpleMessage is getting processed twice. Is this 'by design' or perhaps a bug?
On the other hand, I can uncomment the registration for the UserContextHandler, and not inherit the SimpleMessageHandler from the UserContextHandler, but then I would have to stuff the UserContext into the MessageContext, and use it as such from the SimpleMessageHandler.
In my opinion, both approaches are valid - personally, I'd lean towards using headers because they're less noisy, and because that's really what they're there for :) but, as you correctly state, that requires that you somehow take care of "serializing" the user context into one or more headers, deserializing it again upon receiving each message.
The header approach could be done pretty elegantly, though, in the MessageSent and MessageContextEstablished events for sending and receiving respectively, staying out of your message handlers, and then the user context could be made available in the message context.
The other approach with using a message base class is definitely valid too, and I can see that you're hit by the fact that the lookup for the incoming message will get a new handler instance for each lookup - therefore, the pipeline will contain two handler instances, and the message will then be dispatched "as much as possible" (i.e. once for each compatible type/supertype) to each handler instance, thus resulting in effectively handling the message twice.
In your case, I suggest you do as you hint at towards the end: Make the UserContextHandler a separate handler that you ensure gets to be first in the pipeline, thus allowing it to stash the user context in MessageContext.GetCurrent().Items for all subsequent handlers to extract.
I'd love to cook an example, though, showing a way to do exactly what you need, but by using headers (possibly in the form of simply a ;-separated list of key-value pairs, or something similar), but I'm afraid I cannot promise that such an example would be available within the next few days.
Let me know if it works out for you :)
Update: I've added a sample to Rebus' sample repo that demonstrates how an ambient user context can be picked up and passed around in a message header, including a few nifties around configuration and DI - it's called UserContextHeaders - check it out :)

How to properly convert returned JSON to C# class?

I am working with an API that returns data in JSON format (as far as I can tell, this is my first time working with a true API or JSON). I read a bunch about working with JSON in C#, and eventually got the Newtonsoft.Json library. Unfortunately, I am having a hard time converting the response I am receiving into a C# class following the examples that exist in the Newtonsoft documentation.
Here is an example of the data returned by this API:
{"name":{"id":1,"name":"name","pID":1,"revisionDate":1390580000000}}
And heres what I have so far:
public class apiDataObject
{
public long id {get; set;}
public string name { get; set; }
public int pID { get; set; }
public long revisionDate { get; set; }
}
public long getID()
{
try
{
data = WebRequest.Create(baseURL);
retData = data.GetResponse().GetResponseStream();
}
catch (Exception exception)
{
outputBox.AppendText(Environment.NewLine + exception.ToString());
}
retDataReader = new StreamReader(retData);
returnedData = retDataReader.ReadToEnd();
outputBox.AppendText(returnedData);
apiDataObject test = new apiDataObject();
JsonConvert.PopulateObject(returnedData, test);
return test.id;
}
I have also tried replacing the JsonConvert.PopulateObject(returnedData, test) with:
apiDataObject test = JsonConvert.DeserializeObject<apiDataObject>(returnedData)
The problem is that my "test" object is always empty after the code finishes. I have stepped through the code, and everything works great until I get to the lines where the test object is created, and supposedly populated. I also tried the inbuilt Microsoft libraries and had the exact same issue. I am honestly stumped, I have spent 2 or 3 hours looking at these few lines of code and tons of documentation and samples of the Newtonsoft.Json library, but simply cant figure out where I've gone wrong here. Any help would be greatly appreciated.
From the JSON you posted, its actually a dictionary type: I changed your method to show you, I tested it out and it works.
public long GetID()
{
var testDict = new Dictionary<string, apiDataObject>();
var returnedData = "{\"name\":{\"id\":1,\"name\":\"name\",\"pID\":1,\"revisionDate\":1390580000000}}";
JsonConvert.PopulateObject(returnedData, testDict);
return testDict["name"].id;
}
Running your original code throws an exception telling you that it doesn't know what to do with the first "name".
Just in case anyone ever comes across this in a search, I figured out an alternative solution to working with this type of data as well. The Newtonsoft.Json library contains a function called DeserializeObject. So for the sample data of:
{"name":{"id":1,"name":"name","pID":1,"revisionDate":1390580000000}}
You can create an object that looks like:
public class Name
{
public int id { get; set; }
public string name { get; set; }
public int pID { get; set; }
public long revisionDate { get; set; }
}
public class RootObject
{
public Name name { get; set; }
}
and then use:
JsonConvert.DeserializeObject<RootObject>(returnedData);
to convert the json into the object without having to use a dictionary.
This is probably "common knowledge", considering the object code can easily be created using the json2csharp converter someone linked earlier, but I was unable to find any direct explanation about when to use the DeserializeObject function or why it should be used versus PopulateObject.

Categories

Resources