问题
I've looked and tried every single solution posted here, with no avail.
My problem is:
On a web solution (ASP.NET MVC 3 C# / Razor), I'm using Json.Net to serialize the data displayed on some reports, to be able to send it over to a WPF application. These reports results are a collection of Model objects.
I have the same Model objects on the WPF application, so when I deserialize the Json string, I would like to bind the results accordingly (keeping the original Model object).
The Assembly name and Object type are different on each end (Web / App) - different namespaces.
Here's what I've tried so far:
On the web solution:
// MyModel
public class MyModel
{
public long Id { get; set; }
public string Name { get; set; }
}
...
// data = IEnumerable<MyModel>
var jsonData = JsonConvert.SerializeObject(data.ToArray(), data.ToArray().GetType(),
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
On the app:
// MyModel
public class MyModel
{
[JsonProperty("Id")]
public long Id { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
}
...
var jsonArray = JsonConvert.DeserializeObject(e.jsonObject,
null,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
Binder = new MySerializationBinder()
});
...
public class MySerializationBinder : DefaultSerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
return typeof(MyModel);
}
}
Can anyone give me a hand on this, please?
Thanks!
UPDATE
As per @Marc Gravell comment:
I forgot to mention the main issue here. I need to send the Object type across to the WPF app, because the listener will be expecting data from many reports - which are collections of different Models. So, when binding it back, I know which Object should be binded.
回答1:
I stand by my original answer - type information in serialization data is just really messy - it would be far better to change the code not to need this, but to "fix" it (not sure that is the right word) - look carefully at the typeName
- it isn't always what you are expecting:
public class MySerializationBinder : DefaultSerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
switch(typeName)
{
case "WebSolution.MyModel[]": return typeof(Application.MyModel[]);
case "WebSolution.MyModel": return typeof(Application.MyModel);
default: return base.BindToType(assemblyName, typeName);
}
}
}
Incidentally, once the array type is known, the element type is implicit - so you can save some effort by only including the array type:
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Arrays
}
But I still advise: don't do it this way.
The "mistake" here is including the full type names in the first place; the presence of type names in json should usually be the warning sign of a code-smell. Remove those, and there is nothing to do - it just works:
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
static class Program
{
static void Main()
{
// here imagine we're in the web tier, serializing
var data = GetData();
var jsonData = JsonConvert.SerializeObject(
data.ToArray(), Formatting.None);
// now imagine we're at the application, deserializing
var appData = JsonConvert.DeserializeObject<Application.MyModel[]>(
jsonData);
// and it all works fine
}
static IEnumerable<WebSolution.MyModel> GetData()
{
yield return new WebSolution.MyModel { Id = 123, Name = "abc" };
yield return new WebSolution.MyModel { Id = 456, Name = "def" };
}
}
namespace WebSolution
{
// MyModel
public class MyModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
namespace Application
{
// MyModel
public class MyModel
{
[JsonProperty("Id")]
public long Id { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
}
}
来源:https://stackoverflow.com/questions/17485955/how-to-change-the-assemby-and-the-object-type-on-the-newtonsoft-json-serializati