MSMQ custom message format - c#

I would like to make message in MSMQ which will have text for example
<order><data id="5" color="blue"/></order>
This is standard XML. So far I have made Serializable class
[Serializable]
public class order
string id
string color
I am using BinaryFormatter. When i check the message.BodyStream there are some chars which are not supposed to be there( 00,01,FF ), then I cannot receive this message without error.
This task seems to be simple, just put text
<order><data id="5" color="blue"/></order>
into msmq.
Mine whole important code:
public static void Send()
{
using (message = new Message())
{
request req = new request("1", "blue");
message.Recoverable = true;
message.Body = req.ToString();
message.Formatter = new BinaryMessageFormatter();
using (msmq = new MessageQueue(#".\Private$\testrfid"))
{
msmq.Formatter = new BinaryMessageFormatter();
msmq.Send(message, MessageQueueTransactionType.None);
}
}
}
[Serializable]
public class request
{
private readonly string _order;
private readonly string _color;
public request(string order, string color)
{
_order = order;
_color = color;
}
public request()
{ }
public string Order
{
get { return _order; }
}
public string Color
{
get { return _color; }
}
public override string ToString()
{
return string.Format(#"<request> <job order = ""{0}"" color = ""{1}"" /> </request>",_order,_color);
}
}

Your question isn't very clear at all; you can send any type of message you like to MSMQ, so long as you use the BinaryMessageFormatter. Here's an example:
string error = "Some error message I want to log";
using (MessageQueue MQ = new MessageQueue(#".\Private$\Your.Queue.Name"))
{
BinaryMessageFormatter formatter = new BinaryMessageFormatter();
System.Messaging.Message mqMessage = new System.Messaging.Message(error, formatter);
MQ.Send(mqMessage, MessageQueueTransactionType.Single);
MQ.Close();
}

I have not found reason why the Message.Body contains these ascii characters before the string I pass to Body. I just fill directly BodyStream instead of Body and let it convert itself:
Message.BodyStream = new MemoryStream(Encoding.ASCII.GetBytes(string i want to put as Body))
Then the message is simply only the string with nothing else.

You don't need the serializable class to send a string to a message queue.
Since you are using the BinaryMessageFormatter, you must first convert your string to a byte array using a text encoder e.g.
message.Body = new UTF8Encoding().GetBytes(req.ToString());
I'm just using UTF8 as an example, you can use whatever encoding you like.
Then when you read the message from the queue, remember to use the same encoding to get your string back e.g.
string myString = new UTF8Encoding().GetString(message.Body);
Hope this helps

Related

C# Azure: How to read body from Microsoft.Azure.ServiceBus.Message?

I have trouble with the Microsoft.Azure.ServiceBus.Message class. I want to create a Message object containing a payload object and then read this object back from it. In my current example I am not even sending the Message through a real Azure bus; I'm just creating it in memory and then trying to read it.
I cannot figure out what type I am supposed to read the message body as. I've tried byte[], string and the original object type. In all my cases I get an XmlException: "The input source is not correctly formatted".
Can someone please tell me what I am doing wrong, either when encoding or decoding the Message?
[DataContract]
public class Thingy
{
[DataMember]
public string Doodad { get; set; }
}
private static Message CreateMessage()
{
var entityMessage = new Thingy {Doodad = "foobar"};
var serializedMessageBody = JsonConvert.SerializeObject(entityMessage);
var contentType = typeof(Thingy).AssemblyQualifiedName;
var bytes = Encoding.UTF8.GetBytes(serializedMessageBody);
var message = new Message(bytes) {ContentType = contentType};
return message;
}
[Test]
public void ReadMessageBytes()
{
var message = CreateMessage();
var body = message.GetBody<byte[]>();
Console.WriteLine(body);
}
[Test]
public void ReadMessageString()
{
var message = CreateMessage();
var body = message.GetBody<string>();
Console.WriteLine(body);
}
[Test]
public void ReadMessageThingy()
{
var message = CreateMessage();
var body = message.GetBody<Thingy>();
Console.WriteLine(body);
}
I found out that this works:
[Test]
public void ReadMessageProperly()
{
var message = CreateMessage();
var body = message.Body;
var text = Encoding.UTF8.GetString(body);
var thingy = JsonConvert.DeserializeObject<Thingy>(text);
Assert.IsInstanceOf<Thingy>(thingy);
Assert.AreEqual("foobar", thingy.Doodad);
}
When creating a BrokeredMessage using custom DataContract type and using DataContractSerializer :
Record recordDataContract = new Record { Id = "DataContract Record" };
BrokeredMessage recordDataContractMessage = new BrokeredMessage(recordDataContract, new DataContractSerializer(typeof(Record)));
You can receive this message as:
Record r = receiveMessage.GetBody<Record>(new DataContractSerializer(typeof(Record)));
When creating a **BrokeredMessage** using custom **DataContract** type and using default serializer (DataContract + Binary Xml):
[DataContract(Namespace = "")]
class Record {
[DataMember]
public string Id { get; set; }
}
Record recordDefault = new Record { Id = "default Record" };
BrokeredMessage recordDefaultMessage = new BrokeredMessage(recordDefault);
You can receive this message as:
Record r = receiveMessage.GetBody<Record>();
For additional reference , you can check this blog. It has detailed example for different scenarios.
Hope it helps.

Is there a construct or pattern similar to C# `using` which will return an object?

I have a WCF message inspector which inspects requests and responses: Message. The inspector works fine. A Message object can only be read once so once you read it, you cannot simply propagate as WCF will complain that the message has been read. Therefore, I am creating a brand new copy of the message and propagating that.
I have designed a class that allows message reading and after the caller has read whatever they want, they need to call Close which will return a copy of the message. Here is the skeleton of my class:
using System.ServiceModel.Channels;
internal abstract class MessageReader
{
internal string ReadSomething(string id)
{
// Return string
}
internal string ReadSomethingElse(string id)
{
// Return string
}
internal Message Close()
{
// Create copy and return it.
}
}
Users of my class may forget to call Close() which is fine because WCF will yell at them. Right now I have documentation to let users know they need to call Close().
Here is the question
Is there a pattern, or something similar, to C#'s using construct but one which returns an object at the end? This will be really convenient because then users of my class can just use a construct like that and at the end it will return the copy of the message. Something like this:
UsingSomeConstruct(var reader = new MessageReader(ref originalMessage))
{
var a = reader.ReadSomething("something");
var b = reader.ReadSomethingElse("something");
// Do something with what was read
}
// At this point originalMessage will be the copy of the message and no longer the original message.
EDIT
I thought about hacking IDisposable to achieve this but I am NOT going to do it that way so looking for other ideas.
There is no such language construct of course.
What I could suggest is to use IDisposable for cleaning up, and add ref Message message argument to each ReadXXX method. I know it will not be so convenient for your users, but from the other side they cannot forget passing the parameter.
So the implementation would be something like this:
internal class MessageReader : IDisposable
{
private MessageBuffer buffer;
private Message message;
private void Release()
{
if (buffer == null) return;
buffer.Close();
buffer = null;
message = null;
}
protected void OnReadRequest(ref Message message)
{
if (message == null) throw new ArgumentNullException("message");
if (this.message == message) return;
Release();
this.buffer = message.CreateBufferedCopy(int.MaxValue);
message = this.message = buffer.CreateMessage();
}
public void Dispose()
{
Release();
}
internal string ReadSomething(ref Message message, string id)
{
OnReadRequest(ref message);
// Return string
}
internal string ReadSomethingElse(ref Message message, string id)
{
OnReadRequest(ref message);
// Return string
}
}
and the sample usage:
using (var reader = new MessageReader())
{
var a = reader.ReadSomething(ref originalMessage, "something");
var b = reader.ReadSomethingElse(ref originalMessage, "something");
// Do something with what was read
}
// At this point originalMessage will be the copy of the message and no longer the original message.
The way I'd do this is as follows:
public MessageReader: IDisposable
{
public static MessageReader Create(ref Message message)
{
var buffer = message.CreateBufferedCopy(/*whatever is fit*/);
try
{
var reader = new MessageReader(buffer);
message = buffer.CreateMessage();
return reader;
}
catch
{
buffer.Close();
throw;
}
}
private readonly MessageBuffer buffer;
private bool disposed;
private MessageReader(MessageBuffer buffer) { this.buffer = buffer; }
public void Dispose()
{
if (disposed)
return;
buffer.Close();
disposed = true;
}
public string Read(string id)
{
var newCopy = buffer.CreateMessage();
//work with new copy...
}
}
And you'd simply use it like this:
using (var reader = MessageReader.Create(ref message))
//message here is already an untouched copy with no need of user active
//intervention and is never touched again by the reader.
{
var a = reader.Read("something"); //reads copy
...
}
IMHO, this is as clean as it can be. Note that MessageReader implements IDisposable exclusively because it holds a reference to the disposable private MessageBuffer.
Thanks to all the help from #InBetween, #quetzalcoatl, and #Ivan Stoev. Upvoted your answers because it helped me arrive at the following.
In the constructor, I create a copy of the message and set the original message to the copy. Since the status of this message is Created WCF will be happy propogating it. I create another copy and use that for reading multiple times.
#Ivan said but what if the user does not ask for anything to be read then the copying was wasted work. That is a good point but in my case, this is an interceptor and all messages are intercepted to be read.
Here is the code I ended up with suggestions from all of you:
public class MessageReader : IDisposable {
private readonly Message message;
public MessageReader(ref Message originalMessage) {
using( var buffer = originalMessage.CreateBufferedCopy( int.MaxValue ) ) {
// Keep original message for reading
this.message = buffer.CreateMessage();
// Set original message to a copy of the original
originalMessage = buffer.CreateMessage();
}
}
public int ReadSomething(string id) {
// Read from this.message;
}
public int ReadSomethingElse(string id) {
// Read from this.message;
}
public void Close() {
this.Dispose();
}
public void Dispose() {
this.message.Close();
}
}
The caller can either use it in a using block or without it. The using block is used for good reasons and not as a hack.
public object AfterReceiveRequest(ref Message request, IClientChannel channel,
InstanceContext instanceContext) {
try {
using( var rdr = new MessageReader(ref request) ) {
var value= rdr.ReadSomething( someIdentifier );
return value;
}
}
catch( System.Exception ex ) {
throw CreateFault( ex, request );
}
}
Nope, there is no such construct. It is simply too specific to exist there out of the box. There are extension methods which often are very helpful, but you won't be able to use them on this ref Message parameter..
However, if you are willing to use ref at all, then why dont simply include all that logic it in Reader's constructor?
Here's an example, somewhat contrived, but it should show what I mean. Like others mentioned in comments, I also suggest implementing IDisposable on the Reader object instead of Close, so I included that already.
TL;DR: In example below, the most important thing is in Reader(ref msg) constructor which clones the message, copies the data, and replaces the original message with a safe-message class which can be read many times..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
// real-world variables, keep them typed as base Message
// to be able to silently replace them with different objects
Message original1;
Message original2;
// let's construct some one-time readable messages
{
var tmp1 = new OneTimeMessage();
tmp1.data["mom"] = "dad";
tmp1.data["cat"] = "dog";
original1 = tmp1;
var tmp2 = new OneTimeMessage();
tmp2.data["mom"] = "dad";
tmp2.data["cat"] = "dog";
original2 = tmp2;
}
// test1 - can't read twice
Console.WriteLine("test0A:" + original1.GetData("mom"));
//Console.WriteLine("test0B:" + original1.GetData("mom")); // fail
// test2 - can read twice with Reader's help
var backup1 = original2;
using(var rd1 = new Reader(ref original2))
{
Console.WriteLine("test1A:" + rd1.ReadSomething("mom"));
}
var backup2 = original2;
using(var rd2 = new Reader(ref original2))
{
Console.WriteLine("test1A:" + rd2.ReadSomething("mom"));
//^ ok - becase Reader replaced 'original2' with SafeMessage
}
// test3: Reader's ctor is intelligent
// so no more SafeMessages created during future usage
var backup3 = original2;
using(var rd3 = new Reader(ref original2))
{
}
var backup4 = original2;
using(var rd4 = new Reader(ref original2))
{
}
Console.WriteLine("checking for copies:" + (original2 == backup1));
Console.WriteLine("checking for copies:" + (original2 == backup2));
Console.WriteLine("checking for copies:" + (original2 == backup3));
Console.WriteLine("checking for copies:" + (original2 == backup4));
}
}
}
public abstract class Message
{
public abstract string GetData(string id);
}
public class OneTimeMessage : Message // this models your current one-time-readable message
{
public IDictionary<string, string> data = new Dictionary<string, string>();
public override string GetData(string id)
{
var tmp = data[id];
data.Remove(id);
// that's nonsense, but I want to show that you can't
// read the same thing twice from this object
return tmp;
}
}
public class SafeMessage : Message
{
public IDictionary<string, string> data;
public override String GetData(string id)
{
return data[id];
}
public SafeMessage(Message msg)
{
// read out the full msg's data and store it
// since this is example, we can do it in a pretty simple way
// in your code that will probably be more complex
this.data = new Dictionary<string,string>(((OneTimeMessage)msg).data);
}
}
public class Reader : IDisposable
{
private Message message;
public Reader(ref Message src)
{
src = src is SafeMessage ? src : new SafeMessage(src);
this.message = src;
}
public string ReadSomething(string id){ return message.GetData(id); }
public void Dispose(){ Close(); }
public void Close(){ message=null; Console.WriteLine("reader closed"); }
}
EDIT: improved example
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Channels;
using System.Text.RegularExpressions;
using System.Xml;
namespace MyProgram
{
public class Program
{
public static void Main(string[] args)
{
// real-world variables, keep them typed as base Message
// to be able to silently replace them with different objects
Message original1;
Message original2;
// let's construct some one-time readable messages
{
original1 = new TheMessage("dad", "dog");
original2 = new TheMessage("dad", "dog");
}
// test1 - can't read twice
Console.WriteLine("test0A:" + original1.GetReaderAtBodyContents().ReadOuterXml());
// Console.WriteLine("test0B:" + original1.GetReaderAtBodyContents().ReadOuterXml()); // fail: InvalidOperationException - it was already read
// test2 - can read ONCE with Reader's help, but the message is replaced and is usable again
var backup1 = original2;
using (var rd1 = new ReaderOnce(ref original2))
{
Console.WriteLine("is message replaced after opening Reader:" + (original2 != backup1));
Console.WriteLine("test1A:" + rd1.ReadBodyXml());
// Console.WriteLine("test1B:" + rd1.ReadBodyXml()); // fail: InvalidOperationException - it was already read
}
// test3 - can read MANY TIMES with ReaderMany's help
// also note we use 'original2' again, which was already used above, so in fact ReaderOnce really works as well
var backup2 = original2;
using (var rd1 = new ReaderMany(ref original2))
{
Console.WriteLine("is message replaced after opening Reader:" + (original2 != backup2));
Console.WriteLine("test2A:" + rd1.ReadBodyXml());
Console.WriteLine("test2B:" + rd1.ReadBodyXml()); // ok
}
Console.WriteLine("Press enter to exit");
Console.ReadLine();
}
}
}
// solution1
public class ReaderOnce : IDisposable
{
private Message localCopy;
public ReaderOnce(ref Message src)
{
// create a WCF MessageBuffer to assist in copying messages
// btw. I suppose you should set some sane limit instead of that below
using (var tempBuffer = src.CreateBufferedCopy(int.MaxValue))
{
src = tempBuffer.CreateMessage(); // FIRST copy for outer use
localCopy = tempBuffer.CreateMessage(); // SECOND copy for internal use in the Reader
}
}
public void Dispose() { Close(); }
public void Close()
{
localCopy.Close(); // but that does NOT affect FIRST copy sent to outer scope outside reader
Console.WriteLine("reader closed");
}
public string ReadBodyXml() // careful: that's again ONE TIME readable
{
return localCopy.GetReaderAtBodyContents().ReadOuterXml();
}
}
// solution2
public class ReaderMany : IDisposable
{
private MessageBuffer localBuffer;
public ReaderMany(ref Message src)
{
localBuffer = src.CreateBufferedCopy(int.MaxValue);
src = localBuffer.CreateMessage(); // FIRST copy for outer use
}
public void Dispose() { Close(); }
public void Close()
{
localBuffer.Close();
Console.WriteLine("reader closed");
}
public string ReadBodyXml() // this is readable multiple times
{
using (var tmp = localBuffer.CreateMessage())
return tmp.GetReaderAtBodyContents().ReadOuterXml();
}
}
// let's fake some Message type to have something to test the Reader on
public class TheMessage : Message
{
public override MessageHeaders Headers => _mh;
public override MessageProperties Properties => _mp;
public override MessageVersion Version => _mv;
private MessageHeaders _mh;
private MessageProperties _mp;
private MessageVersion _mv;
private string data1;
private string data2;
// btw. below: surprise! XmlDictionaryWriter is in "System.Runtime.Serialization", not in "System.Xml"
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteStartElement("foo");
writer.WriteAttributeString("data1", data1);
writer.WriteAttributeString("data2", data2);
writer.WriteEndElement();
}
public TheMessage(string data1, string data2)
{
// remember, this class is just an example, you will work on your own messages you already have
_mv = MessageVersion.Soap12;
_mh = new MessageHeaders(_mv);
_mp = new MessageProperties();
// below: yeah, that's super-naive and wrong, but that's an example
this.data1 = data1;
this.data2 = data2;
}
}
There is no language construct in c# that does what you are asking. As stated in comments, you could abuse IDisposable and the language and use a using block to achieve what you want.
But, I fail see what you are gaining, you are just punting the problem; now users will need to remember to use usinginstead of Close. The latter is simple and clean, the former uses a very known language construct to do something different to what it was thought for, something that will potentially be very confusing.

Mvc .Net.Mail: How to send email with image (logo)

I am using three classes to send email but i cant to combine text email with image, or just to send image. When i get email i see empty image.
Help me to change my code so i can to send email with:
text
image
and style
public class SendService : IDistributionProvider
{
public int Send(System.Xml.Linq.XDocument recipientsData, string subject, string fromName, string fromAccount)
{
foreach (XElement element in recipientsData.Root.Elements())
{
string email = element.Element("email").Value;
string name = element.Element("name").Value;
string message = element.Element("message").Value;
bool result = EmailUtils.SendEmail(fromAccount, fromName, email, name, subject, message.Replace("\n", "<br/>"));
}
return 1;
}
public interface IDistributionProvider
{
int Send(XDocument recipientsData, string subject, string fromName,
string fromAccount);
}
public static class EmailUtils
{
private static string sendHostName;
private static int sendPort;
private static string userName;
private static string password;
private static string defaultFromEmail;
private static string defaultFromName;
static EmailUtils()
{
sendHostName = ConfigurationManager.AppSettings["sendHostName"];
sendPort = int.Parse(ConfigurationManager.AppSettings["sendPort"]);
defaultFromEmail = ConfigurationManager.AppSettings["fromEmail"];
defaultFromName = ConfigurationManager.AppSettings["fromName"];
string credential = Utils.DecryptString(ConfigurationManager.AppSettings["credential"]);
if (!string.IsNullOrEmpty(credential) && credential.Split(";".ToCharArray()).Length > 1)
{
userName = credential.Split(";".ToCharArray())[0];
password = credential.Split(";".ToCharArray())[1];
}
}
public static bool SendEmail(string toEmail, string toName, string subject, string body)
{
return SendEmail(defaultFromEmail, defaultFromName, toEmail, toName, subject, body);
}
public static bool SendEmail(string fromEmail, string fromName, string toEmail, string toName, string subject, string body)
{
try
{
if (string.IsNullOrEmpty(toEmail))
{
return false;
}
if (string.IsNullOrEmpty(toName))
{
toName = toEmail.Substring(0, toEmail.IndexOf("#"));
}
if (string.IsNullOrEmpty(fromEmail))
{
fromEmail = defaultFromEmail;
}
if (string.IsNullOrEmpty(fromName))
{
fromName = defaultFromName;
}
Message message = new Message();
message.Charset = "UTF-8";
message.Subject = Codec.RFC2047Encode(subject, "UTF-8");
message.From = new Address(fromEmail, fromName);
message.To.Add(toEmail, toName);
message.BodyHtml.Format = BodyFormat.Html;
message.BodyHtml.Charset = "UTF-8";
message.BodyHtml.Text = body;
return ActiveUp.Net.Mail.SmtpClient.SendSsl(message, sendHostName, sendPort, userName, password, SaslMechanism.Login);
}
catch
{
return false;
}
}
}
In this way I send email- just text:
string bodyEmail = "<h2>Welcome to website</h2></br><div><p>Thank for using website</p></div>";
EmailUtils.SendEmail("xxx#gmail.com","xxxx","Contact",bodyEmail);
Easiest way to do it is to inline your images using Data URIs.
You essentially inline the image into the HTML of your message. Just follow the format
data:[<MIME-type>][;charset=<encoding>][;base64]
where mime-type may be image/jpeg, charset should be ASCII, and the bytes of the image converted to base64. You can get that by reading the bytes of the image file from disk
byte[] imaeg = File.ReadAllBytes("nekkedladies.jpg");
then convert the byte array to a base 64 string
var base64Imaeg = System.Convert.ToBase64String(imaeg);
slap it together and stick it in your html (stolen from wiki)
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Nekkid Ladies" />
btw, the example image data isn't nekkid ladies. It's this:
sorry
I've actually ran into this same problem and what really helped me was this. In my case I had the html and I had to parse it out using HtmlUtilityPack. I would not recommend using the encoded string as It is not fully supported, and it makes your message bloated. The cid way is also how outlook adds images to an email. I'd add code but I think the example was good enough in my case.

__type and inheritance with WCFService

[DataContract]
public abstract class BusMessage
{
[DataMember(Name = "encoding")]
public string Encoding { get; set; }
[DataMember(Name = "type")]
public virtual MessageType Type
{
get { return _type; }
private set { _type = value; }
}
}
[DataContract]
public class BusTextMessage : BusMessage
{
[DataMember(Name = "type")]
public override MessageType Type
{
get { return MessageType.Text; }
}
[DataMember(Name = "payload")]
public string Payload { get; set; }
}
[ServiceContract]
[ServiceKnownType("GetKnownTypes", typeof(Helper))]
public interface ICommunicationService
{
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/SendMessage")]
string SendMessage(BusMessage jsonMessage);
}
}
When I send request with Postman chrome, if I don't add __type as "__type":"BusTextMessage:#TransportModels.Messages" the object won't be serialized properly because it doesn't know how to instantiate BusMessage class. I have already defined Type property which defines the type of message. Is there any possibility to override __type behaviour for example return proper implementation depending on Type property? I don't want anyone to put __type information to json manually so is there an option to edit json before deserialization and add __type property manually to json if it doesn't exist? For example I want to do something like this:
public void BeforeDeserialization(string json)
{
if(json doesnt include __type)
{
if(json property type(my property) is MessageType.Text)
add to json "__type":"BusTextMessage:#TransportModels.Messages"
///etc
}
}
I Found this methods but it doesn't seem to be usable:
[OnDeserializing()]
internal void OnDeserializingMethod(StreamingContext context)
{
}
I think you need to add the KnownType attribute to the BusMessage class.
[DataContract]
[KnownType(typeof(BusTextMessage)]
public class BusMessage
{
.
.
.
}
This is the quickest solution I discovered. I configure MessageInspector and handle AfterReceiveRequest. Then I check message format(XML,JSON). If it is XML(for example sent from any WCF Client written in C#, WCF is configured to send everything with XML's) then I accept that message because field __type will be automatically inserted by WCF mechanism. Otherwise I Check if it is JSON, for example sent from external client. If it doesn't contain property "__type" I check my property Type and generate proper __type value. For example if my Type is equal to Text I add __type property BusTextMessage:#TransportModels.Messages and insert it into JSON and then recreate the message. I couldn't find quicker and easier solution and it seems to be working. Handling AfterReceiveRequest I found at http://code.msdn.microsoft.com/windowsdesktop/WCF-REST-Message-Inspector-c4b6790b.
public class MessageTypeInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
RecreateMessage(ref request);
return null;
}
}
private void RecreateMessage(ref Message message)
{
WebContentFormat messageFormat = this.GetMessageContentFormat(message);
var ms = new MemoryStream();
XmlDictionaryWriter writer = null;
switch (messageFormat)
{
case WebContentFormat.Default:
case WebContentFormat.Xml:
writer = XmlDictionaryWriter.CreateTextWriter(ms);
break;
case WebContentFormat.Json:
writer = JsonReaderWriterFactory.CreateJsonWriter(ms);
break;
case WebContentFormat.Raw:
this.ReadRawBody(ref message);
break;
}
message.WriteMessage(writer);
writer.Flush();
string messageBody = Encoding.UTF8.GetString(ms.ToArray());
if (messageFormat == WebContentFormat.Json && !messageBody.Contains("__type"))
messageBody = AddTypeField(messageBody);
ms.Position = 0;
ms = new MemoryStream(Encoding.UTF8.GetBytes(messageBody));
XmlDictionaryReader reader = messageFormat == WebContentFormat.Json ?
JsonReaderWriterFactory.CreateJsonReader(ms, XmlDictionaryReaderQuotas.Max) :
XmlDictionaryReader.CreateTextReader(ms, XmlDictionaryReaderQuotas.Max);
Message newMessage = Message.CreateMessage(reader, int.MaxValue, message.Version);
newMessage.Properties.CopyProperties(message.Properties);
message = newMessage;
}
private WebContentFormat GetMessageContentFormat(Message message)
{
WebContentFormat format = WebContentFormat.Default;
if (message.Properties.ContainsKey(WebBodyFormatMessageProperty.Name))
{
WebBodyFormatMessageProperty bodyFormat;
bodyFormat = (WebBodyFormatMessageProperty)message.Properties[WebBodyFormatMessageProperty.Name];
format = bodyFormat.Format;
}
return format;
}
private string AddTypeField(string jsonReply)
{
var typeRegex = new Regex("\"type\":(?<number>[0-9]*)");
Match match = typeRegex.Match(jsonReply);
if (match.Success)
{
int number = Int32.Parse(match.Groups["number"].Value);
var type = (MessageType)number;
var nameFormat = string.Format("Bus{0}Message", type);
string format = string.Format("\"__type\":\"{0}:#TransportModels.Messages\"", nameFormat);
jsonReply = "{" + string.Format("{0},{1}", format, jsonReply.Substring(1));
return jsonReply;
}
else
{
throw new Exception("Wrong message type.");
}
}

Serializing a class to xml using RestSharp.AddBody fails

I try to add a simple test-class to a RestSharp-RestRequest via the RestRequest.AddBody-Method. I tried to serialize using both of the delivered serializers, but i could not get one of them to work (JSON-Serializations works pretty fine with just the same settings...)
This is how i do the serialization:
private void SerializationTest()
{
RestRequest request = new RestRequest();
request.XmlSerializer = new RestSharp.Serializers.DotNetXmlSerializer();
//request.XmlSerializer = new RestSharp.Serializers.XmlSerializer();
request.RequestFormat = DataFormat.Xml;
//request.RequestFormat = DataFormat.Json;
request.AddBody(new Dummy()); // uses JsonSerializer
label1.Text = request.Parameters[0].Value.ToString();
}
The dummy-class I'm using is:
private class Dummy
{
public string A = "Some string";
public string B = "Some string";
}
Using RestSharp.Serializers.XmlSerializer() I get: "<Dummy />" (missing both strings)
Using RestSharp.Serializers.DotNetXmlSerializer() I get nothing, the programm just dosen't get over the serialization-step.
Using JSON request.RequestFormat = DataFormat.Json;, everything works fine.
.
{
"A": "Some string",
"B": "Some string"
}
How do i get the class so serialize proper to XML?
Thanks for your help!
Those are fields, not properties. The underlying XmlSerializer only looks for public properties. Update it to this and it should work:
class Dummy
{
public string A { get; set; };
public string B { get; set; };
public Dummy() {
A = "Some string";
B = "Some string";
}
}
The reason the JSON one works is because it defers to JSON.NET's default serializer which (apparently) supports fields. I think this is the wrong design decision personally.

Categories