Message Deserialization failing due to revision number?

So here’s the scenario:

  1. Project A has a messaging library that it publishes to NuGet via the build server. This allows other projects to use the same assembly to issue commands as the service that handles the commands.
  2. When project A builds, the NuGet packages are versioned as Major.Minor.Patch.Revision where Revision is the build number determined by the build server. So the package may be pushed up as 2.1.0, but is modified at the build server to include the build number as the revision and ends up to be something like 2.1.0.123 which we will use for this example
  3. Project B uses the library that was just published by Project A’s build process so it now has a dependency on version 2.1.0.123.
  4. For local testing, I am running project A which is still just version 2.1.0
  5. Project B creates a message with messaging library v2.1.0.123 and Sends it over the bus
  6. Project A receives the message and throws an exception stating that deserialization failed because it could not load the metadata for JObject etc.

On a hunch, based on the fact that the fully qualified name of the message class was contained in the message headers, I went back to project A (the local one that I was currently running) and changed the messaging library version to 2.1.0.123, cleaned the solution and then re-ran it and tried again, and all was fine so I am assuming that the precision of the version is the problem.

This is problematic because of the problem mentioned above but I can see this becoming a bigger problem when trying to debug locally against different environments (e.g. Integration environments) while trying to keep all the versions aligned, because the build process will basically ensure that the versions are almost never in alignment and having to change it manually every time I make a change during development is going to be a bit of a hassle.

Once upon a time, I was told (Google groups I think) that the deserialization process is supposed to only look for the major and minor versions, but this doesn’t appear to be the case.

Is this expected behavior? Is there a decent way around this?

Hi Jeremy

By default the enclosed message type header ships the AssemblyQualified name which contains the public key token as well as the assembly version. We recommend our customers to do the following:

  • Keep the message assembly version as stable as possible, increase the file version if necessary
  • When message definitions change adding stuff to messages is usually not a problem. When the contract changes create a new message by putting the version name into the message name if the contract is a contract which belongs to your published language. All contracts subscribe outside the boundaries of a service need to be supported for a long period of time usually and thus should remain as stable as possible. See Pat Hellands excellent paper http://cidrdb.org/cidr2005/papers/P12.pdf

If ducktyping or consumer driven contracts is required switch to a serializer that supports it like XmlSerializer. See Consumer-driven Contracts sample • NServiceBus Samples • Particular Docs by the way the sample also works with Json, see Feedback: 'Consumer Driven Contracts' · Issue #3479 · Particular/docs.particular.net · GitHub

Hope that helps

Regards
Daniel

Sorry for the delay, apparently I wasn’t subscribed to replies.

I think the main issue we run into with this is Nuget. Our messaging libraries are shared via nuget so that other services can place the correct versions of the command/event on the bus as needed by the handler in some other service. For example, service A handles event 1; in order for serviceB to fire that event, it needs a reference to that assembly. To solve it, service A builds a nuget package that service B can pull down and use to form the message. The issue arises when the build server increments the revision, now the projects cannot be run locally because service B is using the nuget package that was published by service A but local service A is expecting a different version that is being provided by service B since the versions are now out of alignment.

We tried just avoiding the revision and only increment the version when there’s a breaking change, but then Microsoft’s new Nuget caching strategy screws it all up. If I publish the new package with the same version number, then nuget manager ignores it or rather pulls the existing one from the cache. In order to get around this, I have to clear the cache and clean the solution, and in order to do that, I have to shut down VS to release the files first. This makes for a very unproductive development process.

Hi Jeremy,

I hear you that is a painful experience. Have you considered doing the following?

Keep the assembly version stable, let’s say 1.0.0
Update the file version with every build, let’s say 1.0.12354 (and counting :wink: )
Update the nuget package version as well with every release

Would that work for you?

Regards
Daniel

Would that cause the nuget manager to always pull the latest file version then? I haven’t messed with that before; I typically leave file version alone. I need to see if AppVeyor will change that on build, but I could give that a try and get back to you.