NServiceBus Xml Serialization issue with messages that have an IEnumerable<T> property - xml-serialization

I'm trying to send a message with an IEnumerable property, am i correct that the NServiceBus Xml serializer cannot support this ?
If i switch to using an array rather than IEnumerable it will work, if i use the binary serializer it also works
My message look like this
[Serializable]
public class Parent : IMessage
{
public string Identifier { get; private set; }
public IEnumerable<Child> Children { get; private set; }
public Parent(string identifier, IEnumerable<Child> children)
{
this.Identifier = identifier;
this.Children = children;
}
}
[Serializable]
public class Child
{
public string Identifier { get; private set; }
}
If the default Xml serializer cannot cater for this, is there any way to configure an alternative Xml serializer such as the BCL's DataContractSerializer ?
Thanks in advance
Pat

First, a note that XML serialization in NServiceBus is not the same thing as .NET XML Serialization. The .NET variant is all about being able to tailor the resultant XML with attributes to produce specific XML schemas, potentially for interoperability with other languages. The NServiceBus XML serializer is an extremely small subset of functionality tailored to transfer predefined message schemas to and from XML as efficiently as possible.
While the result of NServiceBus serialization is readable (which is really nice when inspecting error queues) it doesn't support all types or all formatting options. It does what it does and it does it pretty well.
That said, the problem with an IEnumerable is that it could be so many things. It could, in reality, just be an array, but it could just as easily be a complex Linq-to-SQL expression that will invoke a database query. In order to serialize the IEnumerable, you'd have to represent it as a collection (a list or array) anyway, so you have to enumerate the items. When exactly would you do that? What problems with transactions might that raise? That's why the performance-conscious NServiceBus XML serializer doesn't bother.
An NServiceBus message is just a contract to pass message data. I would suggest just using an array. It's easy enough to convert an IEnumerable to an array (with the ToArray() extension method) and back (with the AsEnumerable() extension method) so why is it important to have it as an IEnumerable?
To fully answer your question, it should be possible to swap out the serializer by writing your own class that implements IMessageSerializer and configuring the dependency injection framework to use it, but I have not tried this myself. It would be quite an undertaking, since every single endpoint would have to utilize this same serializer, and you'd also have to make modifications in order to use the Distributor, TimeoutManager, Gateway, etc.
Edit: Noticed this question was cross-posted on NSB group at http://tech.groups.yahoo.com/group/nservicebus/message/8838

is there any way to configure an alternative Xml serializer such as the BCL's DataContractSerializer ?
Yes, that is certainly possible. We use the DataContractSerializer for some of our services. To get this working, you need to implement the IMessageSerialzer interface, which does the work, then register that serializer with NServiceBus during the NServiceBus.Configure method chain.
Here's the code for the message serializer. It is pretty straightforward.
public class WcfMessageSerializer : IMessageSerializer
{
private readonly IList<Type> knownTypes = new List<Type>();
public IList<Type> MessageTypes
{
get { return knownTypes; }
set
{
knownTypes.Clear();
foreach (var type in value)
{
if (!type.IsInterface && typeof(IMessage).IsAssignableFrom(type)
&& !knownTypes.Contains(type))
{
knownTypes.Add(type);
}
}
}
}
public void Serialize(IMessage[] messages, Stream stream)
{
var xws = new XmlWriterSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var xmlWriter = XmlWriter.Create(stream, xws))
{
var dcs = new DataContractSerializer(typeof(IMessage), knownTypes);
foreach (var message in messages)
{
dcs.WriteObject(xmlWriter, message);
}
}
}
public IMessage[] Deserialize(Stream stream)
{
var xrs = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var xmlReader = XmlReader.Create(stream, xrs))
{
var dcs = new DataContractSerializer(typeof(IMessage), knownTypes);
var messages = new List<IMessage>();
while (false == xmlReader.EOF)
{
var message = (IMessage)dcs.ReadObject(xmlReader);
messages.Add(message);
}
return messages.ToArray();
}
}
}
In order to plug this in, you could use an extension method such as the following:
public static class ConfigureWcfSerializer
{
public static Configure WcfSerializer(this Configure config)
{
var messageTypes = Configure.TypesToScan
.Where(t => typeof(IMessage).IsAssignableFrom(t))
.ToList();
config.Configurer
.ConfigureComponent<WcfMessageSerializer>(ComponentCallModelEnum.Singleton)
.ConfigureProperty(ms => ms.MessageTypes, messageTypes);
return config;
}
}
This would be invoked when you configure NServiceBus like so:
NServiceBus.Configure
// Other configuration...
.WcfSerializer()
// Other configuration...
.CreateBus()
.Start();

Related

How to prevent Json.NET from using the Entity Framework proxy type name?

In my design I have a class that has a property whose type can be inherited from:
public class Feed
{
...
[JsonProperty(TypeNameHandling = TypeNameHandling.Auto)]
public FeedSource Source { get; set; }
...
}
public abstract class FeedSource { ... }
public class CsvSource : FeedSource { ... }
public class DbSource : FeedSource { ... }
I'm using the Entity Framework to load and store this object to a database and I'm using Json.NET to serialize this object into JSON for further processing.
The problem I stumbled on is that the $type property is containing the typename of the EF proxy instead of the "real" typename. So instead of:
$type: "System.Data.Entity.DynamicProxies.CsvSource_0B3579D9BE67D7EE83EEBDDBFA269439AFC6E1122A59B4BB81EB1F0147C7EE12"
which is meaningless to other clients, I would like to get:
$type: "MyNamespace.CsvSource"
in my JSON.
What's the best way to achieve this?
Another way which doesn't require you to make changes to your EF configuration is to use a custom SerializationBinder, e.g.:
class EntityFrameworkSerializationBinder : SerializationBinder
{
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
if (serializedType.Namespace == "System.Data.Entity.DynamicProxies")
typeName = serializedType.BaseType.FullName;
else
typeName = serializedType.FullName;
}
public override Type BindToType(string assemblyName, string typeName)
{
throw new NotImplementedException();
}
}
Usage:
string json = JsonConvert.SerializeObject(entityFrameworkObject, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, Binder = new EntityFrameworkSerializationBinder() });
You can do two things:
disabling tracking proxies, by setting ProxyCreationEnabled to false. You can find this property in your context's Configuration property. If you use a context for a single GetXxx method, you can do it without interfering other context instanced.
using the AsNoTracking() extension method when you recover your entity, like this:
MyContext.MyTable.AsNoTracking(). // rest of the query here
This indicates that you don't want a tracking proxy for your entity, so you'll get the entity class. This has no interference with the afore mentioned configuration.

Getting JSON Serialization Entity Framework Self Reference Loop error even after ProxyCreation false when using explicit Include

JSON Serialization (ASP.Net Web API) fails because of self-referencing loop (it’s a common problem, Reason: an entity being requested lazy loads child entities and every child has a back reference to parent entity).
Work around I found, but doesn’t help me:
Use [JsonIgnore] for navigation properties to be ignored:
This solution works but doesn’t apply in my case. For Example: To get a Customer information along with his Orders, I would quickly add [JsonIgnore] to Customer property in Order class, but when I want to get an Order information along with the Customer details, since there’s [JsonIgnore] on Customer property, it won’t include Customer details.
Change JSON.Net Serializer Settings to Preserve References:
Can’t Preserve because I don’t need Circular referenced data.
Disable Proxy Creation at the Data Context and use explicit loading(this should ideally solve the problem):
Disabling proxy creation stops Lazy Loading and returns data without error, but when I explicitly Include child entities, I again the get the unexpected self-referencing loop error! The error is at the back-reference level to parent entity.
Any experiences along the same lines/suggestions?
I tried all the suggested solutions but didn't work. Ended up with Overriding the JSON.Net Serializer’s DefaultContractResolver to this:
public class FilterContractResolver : DefaultContractResolver
{
Dictionary<Type, List<string>> _propertiesToIgnore;
public FilterContractResolver(Dictionary<Type, List<string>> propertiesToIgnore)
{
_propertiesToIgnore = propertiesToIgnore;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
List<string> toIgnore;
property.Ignored |= ((_propertiesToIgnore.TryGetValue(member.DeclaringType, out toIgnore) || _propertiesToIgnore.TryGetValue(member.DeclaringType.BaseType, out toIgnore)) && toIgnore.Contains(property.PropertyName));
return property;
}
}
Then created a Static Class which returns a dictionary of Properties to be Ignored based on the Controller:
public static class CriteriaDefination
{
private static Dictionary<string, Dictionary<Type, List<string>>> ToIgnore = new Dictionary<string, Dictionary<Type, List<string>>>
{
{
"tblCustomer", new Dictionary<Type, List<string>>{
{
typeof(tblCustomer), new List<string>{
//include all
}
},
{
typeof(tblOrder), new List<string>{
"tblCustomer"//ignore back reference to tblCustomer
}
}
}
},
{
"tblOrder", new Dictionary<Type, List<string>>{
{
typeof(tblCustomer), new List<string>{
"tblOrders"//ignore back reference to tblOrders
}
},
{
typeof(tblOrder), new List<string>{
//include all
}
}
}
}
};
public static Dictionary<Type, List<string>> IgnoreList(string key)
{
return ToIgnore[key];
}
}
And inside every controller change the JSON Formatter something like:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new FilterContractResolver(CriteriaDefination.IgnoreList("tblCustomer"));
This is what I ended up settling on, hopefully it helps someone else.
Say the EF classes are structured like this:
public partial class MyEF
{
public virtual ICollection<MyOtherEF> MyOtherEFs {get; set;}
}
public partial class MyOtherEF
{
public virtual MyEF MyEF {get; set;}
}
To keep serialization form happening in JSON.NET, you can extend the class and add a method with the name "ShouldSerialize" + property name like so:
public partial class MyEF
{
public bool ShouldSerializeMyOtherEFs() { return false; }
}
If you wanted to get a little more fancy, you could add logic in the method so that it would serialize in certain cases. This allows you to keep serialization logic out of the EF Model First code creation as long as this code is in a different physical code file.
Instead of letting the Entity Framework generate the model, use Code First with an existing database. Now you are more in control.
See this blog entry from Scott Guthrie

What are the options for creating an object model that need caching using entity framework and postsharp?

I am working with an internet application that has high demands for performance which means that a good caching functionality is crucial for our success.
The solution is built with Entity Framework Code First for the database access and Postsharp for caching. For the moment the model looks something like below.
public class Article
{
private readonly IProducerOperator _producerOperator;
public Article(IProducerOperator operator)
{ _producerOperator = operator; }
public int Id { get; set; }
...
public int ProducerId { get; set; }
public Producer Producer {
get { return _producerOperator.GetProducer(ProducerId); }
}
}
The operations classes looks like below.
public class ArticleOperations : IArticleOperations
{
private readonly IDataContext _context;
public ArticleOperations(IDataContext context)
{ _context = context; }
[Cache]
public Article GetArticle(int id)
{
var article = _context.Article.Find(id);
return article;
}
}
public class ProducerOperations : IProducerOperations
{
private readonly IDataContext _context;
public ProducerOperations(IDataContext context)
{ _context = context; }
[Cache]
public Producer GetProducer(int id)
{
var producer = _context.Producer.Find(id);
return producer;
}
}
I am NOT fond of having dependendencies in the business objects but the argument for it is to having lazy loading from the cache... for the most. This solution also means that caching is done only once for producer... at GetProducer. Normally I would not even consider having dependencies there. The objects should be POCOs, nothing more. I would really need some new inputs on this one. How can I do it instead? Is this the best way?
We also need to resolve the opposite, ie, from a producer that is cached we should be able to retrieve all its articles.
First, i wish to say, there are actually some (one?) solutions that uses entity framework code first in combination with caching using postsharp. Ideablades has released Devforce code first that actually is doing exactly this. That kind of framework actually resolves it all and we can use the entity framework as it is supposed to be used, and in combination with caching.
But that did not become the solution in this case. We went for complete separation of concern, meaning that the business objects only concern went to be only containing the data. The operations classes got the responsibility to fill the business objects.

Issue with passing objects to domain method

I have WCF Ria Services App with DTO objects. I defined relations between my DTO objects:
[Include]
[Association("FK_Items_OrderID", "ID", "OrderID")]
public List<Item> Items { get; set; }
So I can see collection of Items on the client and operate with it. Then I want to save changes and call this method:
[Invoke]
public void SaveOrderChanges(Order order)
{
_dataManager.SaveOrderChanges(order);
}
It is domain service method. But I see than collection of related Items in Order object here is already NULL, but when I call this method on the client and pass order to this method collection is filled.
Does anybody know what to do? Thanks.
That's happen because the client side serializer don't include assocations. Wcf ria services has a different way to handle this kind of scenarious, but this involves the use of DomainContext and the standard Get/Insert/Update/Delete methods.
My advice is to change the sign of your save method to something like
[Invoke]
public void SaveOrderChanges(string serializedOrder)
{
Order order = MyCustomSerializer.Deserialize<Order>(serializedOrder);
_dataManager.SaveOrderChanges(order);
}
Thi`s is an utilities class that I use to serialize and deserialize objects, however it should be tricked to include the Items collection.
public static class Serialization
{
public static string Serialize<T>(T obj)
{
//Create a stream to serialize the object to.
var ms = new MemoryStream();
// Serializer the User object to the stream.
var ser = new DataContractSerializer(typeof (T));
ser.WriteObject(ms, obj);
byte[] array = ms.ToArray();
ms.Close();
return Encoding.UTF8.GetString(array, 0, array.Length);
}
public static T Deserialize<T>(string obj) where T : class
{
if (obj == null)
return null;
var serializer = new DataContractSerializer(typeof (T));
var stream = new MemoryStream(Encoding.UTF8.GetBytes(obj));
var result = serializer.ReadObject(stream) as T;
return result;
}
}
Of course, you need to do the opposite client-side and serialize your order and items.
This is the easiest way to go that I know, however you could also take a look here.
Eventually, try to refactor your code in the way WCF Ria is meant to go (Context based)
Hope this helps,
Marco

Persist derived objects using Mongo C# driver

I have the following class hierarchy
[BsonKnownTypes(typeof(MoveCommand))]
public abstract class Command : ICommand
{
public abstract string Name
{
get;
}
public abstract ICommandResult Execute();
}
public class MoveCommand : Command
{
public MoveCommand()
{
this.Id = ObjectId.GenerateNewId().ToString();
}
[BsonId]
public string Id { get; set; }
public override string Name
{
get { return "Move Command"; }
}
public override ICommandResult Execute()
{
return new CommandResult { Status = ExecutionStatus.InProgress };
}
}
if I save the command like so:
Command c = new MoveCommand();
MongoDataBaseInstance.GetCollection<Command>("Commands").Save(c);
and then query the DB, I don't see the derived properties persisted.
{ "_id" : "4df43312c4c2ac12a8f987e4", "_t" : "MoveCommand" }
I would expect a Name property as a key in the document.
What am I doing wrong?
Also, is there a way to avoid having a BsonKnowTypes attribute on the base class for persisting derived instances? I don't see the why a base class needs to know about derived classes. This is bad OO design and is being forced on my class hierarchy by the BSON library. Am I missing something here?
1.Name property was not saved into database because it haven't setter. Serializers not serialize properties that's haven't setters (because if serializer serialize such property it will not able deserialize it back). So if you want serialize Name property then just add fake setter(into ICommand need to add it also):
public override string Name
{
get { return "Move Command"; }
set{}
}
2.If you don't want use BsonKnownTypes attribute there is another way to notify serializer about know types it might encounter during deserialization. Just Register maps once, on app start event:
BsonClassMap.RegisterClassMap<MoveCommand>();
//all other inherited from ICommand classes need register here also
So you should use or KnownTypes attribute or register BsonClassMap for each polymorphic class, otherwise you will get 'unknown descriminator' error during deserializtion:
var commands = col.FindAllAs<ICommand>().ToList();
3 You said:
This is bad OO design and is being
forced on my class hierarchy by the
BSON library.
In any way even without KnownTypes atribute your code using Bson lib through BsonId attribute.
If you want avoid it you can:
BsonClassMap.RegisterClassMap<MoveCommand>(cm => {
cm.AutoMap();
cm.SetIdMember(cm.GetMemberMap(c => c.Id));
});
So now you can remove reference to Mongodb.Bson lib from your domain code lib.