Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
407 views
in Technique[技术] by (71.8m points)

serialization - Maintain .NET Serialized data compatability when moving classes

I have data that's been serialized. The classes associated with the serialized data is part of a large legacy project which has a number of 3rd party references which are not needed for this core set of data. Now I have a need to read this data into another application. I'd like to refactor out the data classes into a separate project which can be shared between the 2 application so I don't end up needing all the 3rd party libraries. I also want to maintain compatibility with data that's been previously saved. I don't need to change any fields in the classes, just the project where they are located.

So far, I've moved the classes to a new project. I've kept the namespaces the same as they were in the old project. But, this hasn't been sufficient to read the objects. I get a SerializationException stating "Parse Error, no type associated with Xml key a1 MyCorp.MyApp.DatabaseRoot MyCorp.MyApp". Looking at the SOAP generated XML, the schemas referenced have changed. For example, I have a class MyCorp.Dashboard.DatabaseRoot originally in project DashboardLibrary. This was moved to project DashboardData (but still using namespace MyCorp.Dashboard.DatabaseRoot). The XML changed in this way:

Orig: <a1:DatabaseRoot id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/MyCorp.Dashboard/MyCorp.Dashboard">
New:  <a1:DatabaseRoot id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/MyCorp.Dashboard/DashboardData">

So, my questions are

  • Is it possible to move classes and keep compatibility? I appear close to pulling it off.
  • If so, how do I control the last bit schema information (MyCorp.Dashboard vs. DashboardData). The original seems based on directory location while the second is project name. I've tried changing the directory structure in the new project, but have had no luck. Anything else I'm missing?

Thanks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You need to implement a custom SerializationBinder. Override the BindToType method to select the type to load based on its name:

public override Type BindToType(string assemblyName, string typeName)
{
    if (assemblyName == "MyOldAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
    {
        if (typeName == "MyOldNamespace.MyOldClass")
        {
            return typeof(MyNewClass);
        }
    }
    // Fall back to the default behavior, which will throw
    // a SerializationException if the old assembly can't be found
    return null;
}

(this is a very basic implementation, in a real-world scenario you would probably use a better mapping logic).

You can also override BindToName if you need to reserialize the data so that it can still be read by the old assembly. This allows you to customize the assembly and type name of the serialized object.

Once you have your custom SerializationBinder, you just need to assign it to the Binder property of the formatter, and use it normally from there.

If you need to change the structure of the types (add or rename fields, change types...), you will need to implement a ISerializationSurrogate to map the old data to the new type structure.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...