I have a .dll that deserializes a class. When I call this .dll from a project or not using reflection it works fine. When I call the .dll using reflection I get an error on the line that deserializes. I know this is due isolation that happens when I use reflection to load an assembly. Wondering if anyone has any fix or an idea of how to implement this? BTW, the serialization works just fine, it's just the deserialization that doesnt work.
I tried both binary and xml, here's the code:
static public object SerializeLoad(string sFilename)
{
try
{
List<ElementTodo> _object = null;//ElementTodo _object = null;
Stream stream = File.Open(sFilename, FileMode.Open);
//BinaryFormatter bformatter = new BinaryFormatter();
XmlSerializer bformatter = new XmlSerializer(typeof(ElementTodo), "ToDo");
//_object = (_object.GetType())bformatter.Deserialize(stream);
_object = (List<ElementTodo>)bformatter.Deserialize(stream);
stream.Close();
return _object;
}
catch(Exception e)
{
string error = e.Message;
return null;
}
}
The generated XML is as follows:
<
?xml version="1.0"?>
<ArrayOfElementTodo xmlns:xsi="w3.org/2001/XMLSchema-instance"; xmlns:xsd="w3.org/2001/XMLSchema"; xmlns="ToDo">
<ElementTodo Title="a" content="aa" isDone="false" />
<ElementTodo Title="b" content="bb" isDone="false" />
<ElementTodo Title="c" content="cc" isDone="false" />
<ElementTodo Title="d" content="dd" isDone="false" />
</ArrayOfElementTodo>
I assume that ElementTodo is in an assembly that both your code and the assembly loaded using reflection have access to? What you have to be careful of is that your loaded assembly is using the same dependent assembly and doesn't load a new copy. Otherwise you wind up with fun errors like 'Object X (of type ElementTodo) is not of type ElementTodo', since two copies of the types are loaded. It's hard to say for sure that this is your issue without more information on the specific error, however.
If this is your problem, you can address it by forcing assemblies to resolve to the version that's already loaded using something like this:
In your startup code somewhere:
//This is required because we load assemblies at runtime
//If this is not used, there can be problems when Reflecting over Types
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
Implementation:
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
return AppDomain.CurrentDomain.GetAssemblies().
FirstOrDefault(assembly => assembly.FullName == args.Name);
}
Related
I use easyhook and SharpDX to get fps data from a DirectX game. Sometimes it works. However, when I start it next time (maybe just some minutes later), it throws the exception System.IO.FileNotFoundException: Could not load file or assembly SharpDX.
When I restart it for several times, it can work. Why? Does anyone have the same problems as mine?
SharpDX version:2.4.2
I don't use EasyHook, but the following code should work for you too. Instead of using ILMerge, which has some limitations, do the following:
1) Link the signed copiy of SharpDx.dll and all other needed SharpDx assemblies to your project. Set the "Local Copy" property to "False".
2) Add those libraries to your project (as you would with .cs files) and set the properties of the files to "Embedded Resource" and "Don't copy to output folder". Make sure those files are exactly the same you linked in step 1.
3) After injecting, first call the following function in your entrypoint, which loads arbitrary assemblies (managed or unmanaged) from your resources if found.
private static void LoadAssemblyFromResources() {
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
try {
Assembly asm = Assembly.GetExecutingAssembly();
string name = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";
string rsc = asm.GetManifestResourceNames().FirstOrDefault(s => s.EndsWith(name));
if (rsc == null) return null; //assembly not found in resources
byte[] module;
using (Stream stream = asm.GetManifestResourceStream(rsc)) {
if (stream == null) return null;
module = new byte[stream.Length];
stream.Read(module, 0, module.Length);
}
try {
return Assembly.Load(module); //Load managed assembly as byte array
} catch (FileLoadException) {
string file = Path.Combine(Path.GetTempPath(), name);
if (!File.Exists(file) || !module.SequenceEqual(File.ReadAllBytes(file)))
File.WriteAllBytes(file, module);
return Assembly.LoadFile(file); //Load unmanaged assembly as file
}
} catch {
return null;
}
};
}
So I have a WPF project that is pulling in dlls that are used by another project here at my job. It's a mess of dependencies, I've been using the technique here: http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application to embed the dependencies into a single executable.
Now, when I'm calling a specific method inside one of the dependencies, I hit the AssemblyResolve event. My OnResolveAssembly event runs, it finds the assembly as an embedded resource (cool!), and does "return Assembly.Load(assembyRawBytes)". If I hit F11 at this point (with a breakpoint at the beginning of OnResolveAssembly), I get another call into the same event. It's for the same assembly too (args.Name is the same).
If I let this run I hit a stack overflow, since I can never seem to escape this recursive event calling.
The MSDN docs don't really say when Assembly.Load can fail, except with a FileNotFoundException or BadImageFormatException.
I've tried unhooking the OnResolveAssembly at the moment before I call Assembly.Load, but then my application dies a mysterious death, even under VS it just goes poof.
I'm probably breaking several rules here, but some ideas of where to start looking for problems would be welcome.
I'm going to start poking around in the problematic DLL to see if there are hints about what is wrong with it (maybe it's a mixed assembly?).
Here's my OnResolveAssembly handler:
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
string path = assemblyName.Name + ".dll";
if (assemblyName.CultureInfo.Equals(System.Globalization.CultureInfo.InvariantCulture) == false)
{
path = String.Format(#"{0}\{1}", assemblyName.CultureInfo, path);
}
using (Stream stream = executingAssembly.GetManifestResourceStream(path))
{
if (stream == null)
return null;
byte[] assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
assemblyDictionary.Add(assemblyName.Name, Assembly.Load(assemblyRawBytes));
return assemblyDictionary[assemblyName.Name];
}
}
For the time being, I've resolved it by iterating through all of my resources and attempting Assembly.Load on them, and storing them in a dictionary for retrieval (during the OnResolveAssembly event):
[STAThread]
public static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string[] resources = executingAssembly.GetManifestResourceNames();
foreach (string resource in resources)
{
if (resource.EndsWith(".dll"))
{
using (Stream stream = executingAssembly.GetManifestResourceStream(resource))
{
if (stream == null)
continue;
byte[] assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
try
{
assemblyDictionary.Add(resource, Assembly.Load(assemblyRawBytes));
}
catch (Exception ex)
{
System.Diagnostics.Debug.Print("Failed to load: " + resource + " Exception: " + ex.Message);
}
}
}
}
App.Main();
}
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
string path = assemblyName.Name + ".dll";
if (assemblyDictionary.ContainsKey(path))
{
return assemblyDictionary[path];
}
return null;
}
It seems be working fine now (the "failing" assembly will load fine in my second snippet), but I'd be interested to learn why it doesn't work in the first.
Loading an assembly from byte[] is a good way to end up in .dll hell (the place you go for too many/complex dependencies). Problem here is that although you loaded the dll to an AppDomain it is not automatically resolved, when you need it again for dependent types.
I commented on this problem here: AssemblyResolve Does not fire
Long story short, Assemblies are loaded into different "contexts" inside of AppDomains. The context used by Load(byte[]) does not resolve Assemblies automatically.
The solution is keeping track of the loaded assemblies and returning the already loaded assembly instead of loading it a second time. There is a starting point to this approach in my answer to:
Need to hookup AssemblyResolve event when DisallowApplicationBaseProbing = true
But I think you got it right with your workaround.
BTW. Loading an assembly twice is a way to get identical but incompatible types. Ever cast an object of MyType from MyAssembly into MyType from the very same assembly and got null?
That's a warm "Welcome to .dll hell".
I'm working on a C# program that uses iTextSharp.dll and WebCam_Capture.dll. When I build the program, it creates executable in the debug folder and it also copies these two dll's to the debug folder as expected. I want to merge them into a single executable, however I failed. These two libraries are visible in the references normally in the solution explorer. I also add them as resources. Executable size got bigger which equals the sum of three files, nevertheless the executable still requires these libraries in its directory... I played with "build action" property of the resource files but no change. I also tried ILmerge but it gave me an error. so what should I do?
Update: This is what I get from ILmerge:
An exception occurred during merging:
Unresolved assembly reference not allowed: System.Core.
at System.Compiler.Ir2md.GetAssemblyRefIndex(AssemblyNode assembly)
at System.Compiler.Ir2md.GetTypeRefIndex(TypeNode type)
It is just a windows application by the way, a form to be filled and printed as pdf with a photo taken via webcam if available. Thanks all!
You can use ILMerge to merge multiple assemblies together. You've already said you did this, and you've received an error. Though I don't know why, you can use an alternative: if the libraries are open source (and their licenses are compatible with yours), you can download the source code, add it to your project and compile. This will result in a single assembly.
The ILMerge page also lists Jeffrey Richter's blog as yet another alternative to solve your issue:
Many applications consist of an EXE file that depends on many DLL
files. When deploying this application, all the files must be
deployed. However, there is a technique that you can use to deploy
just a single EXE file. First, identify all the DLL files that your
EXE file depends on that do not ship as part of the Microsoft .NET
Framework itself. Then add these DLLs to your Visual Studio project.
For each DLL file you add, display its properties and change its
“Build Action” to “Embedded Resource.” This causes the C# compiler to
embed the DLL file(s) into your EXE file, and you can deploy this one
EXE file.
At runtime, the CLR won’t be able to find the dependent DLL
assemblies, which is a problem. To fix this, when your application
initializes, register a callback method with the AppDomain’s
ResolveAssembly event. The code should look something like this:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
String resourceName = "AssemblyLoadingAndReflection." +
new AssemblyName(args.Name).Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(resourceName)) {
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
Now, the first time a thread calls a method that references a type in
a dependent DLL file, the AssemblyResolve event will be raised and the
callback code shown above will find the embedded DLL resource desired
and load it by calling an overload of Assembly’s Load method that
takes a Byte[] as an argument.
Add the DLL files to your Visual Studio project.
For each file go to "Properties" and set its Build Action to "Embedded Resource"
On your code retrive the resource using the GetManifestResourceStream("DLL_Name_Here") this returns a stream that can be loadable.
Write an "AssemblyResolve" event handler to load it.
Here is the code:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
namespace WindowsForm
{
public partial class Form1 : Form
{
Dictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
public Form1()
{
InitializeComponent();
AppDomain.CurrentDomain.AssemblyResolve += FindDLL;
}
private Assembly FindDLL(object sender, ResolveEventArgs args)
{
string keyName = new AssemblyName(args.Name).Name;
// If DLL is loaded then don't load it again just return
if (_libs.ContainsKey(keyName)) return _libs[keyName];
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("YourNamespaceGoesHere." + keyName + ".dll")) // <-- To find out the Namespace name go to Your Project >> Properties >> Application >> Default namespace
{
byte[] buffer = new BinaryReader(stream).ReadBytes((int)stream.Length);
Assembly assembly = Assembly.Load(buffer);
_libs[keyName] = assembly;
return assembly;
}
}
//
// Your Methods here
//
}
}
Hope it helps,
Pablo
I modified Pablo's code a little bit and it worked for me.
It was not getting the DLL's resource name correctly.
IDictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
public Form1()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
InitializeComponent();
}
// dll handler
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string keyName = new AssemblyName(args.Name).Name;
// If DLL is loaded then don't load it again just return
if (_libs.ContainsKey(keyName)) return _libs[keyName];
using (Stream stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream(GetDllResourceName("itextsharp.dll"))) // <-- To find out the Namespace name go to Your Project >> Properties >> Application >> Default namespace
{
byte[] buffer = new BinaryReader(stream).ReadBytes((int)stream.Length);
Assembly assembly = Assembly.Load(buffer);
_libs[keyName] = assembly;
return assembly;
}
}
private string GetDllResourceName(string dllName)
{
string resourceName = string.Empty;
foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
if (name.EndsWith(dllName))
{
resourceName = name;
break;
}
}
return resourceName;
}
The answer you are looking for:
// To embed a dll in a compiled exe:
// 1 - Change the properties of the dll in References so that Copy Local=false
// 2 - Add the dll file to the project as an additional file not just a reference
// 3 - Change the properties of the file so that Build Action=Embedded Resource
// 4 - Paste this code before Application.Run in the main exe
AppDomain.CurrentDomain.AssemblyResolve += (Object sender, ResolveEventArgs args) =>
{
String thisExe = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
System.Reflection.AssemblyName embeddedAssembly = new System.Reflection.AssemblyName(args.Name);
String resourceName = thisExe + "." + embeddedAssembly.Name + ".dll";
using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return System.Reflection.Assembly.Load(assemblyData);
}
};
Check out the AssemblyResolve event on the app domain.
I don't have a sample but you basically check what is asked for and stream back the resource DLL. I believe LinqPAD does this well - you could have a look at Joseph Albahari's implementation with a decompiler etc.
Add this anonymous function code on the top of our application constructor. This will add dll from embedded resource in same project.
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string resourceName = new AssemblyName(args.Name).Name + ".dll";
string resource = Array.Find(this.GetType().Assembly.GetManifestResourceNames(), element => element.EndsWith(resourceName));
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource))
{
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
I know that topic is old but i'll write it for future persons that will want to use it.
i base on code by userSteve.
i would suggest to change this.
String thisExe = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
into this
String thisExe = System.Reflection.Assembly.GetExecutingAssembly().EntryPoint.DeclaringType.Namespace;
that way it would work even if namespace is different than assembly name
also if you want to use DLL from directory you can use it like that (directory Resources as Example)
String resourceName = thisExe + ".Resources." + embeddedAssembly.Name + ".dll";
if you still can't find where place this code in C# Form application paste it inside file "Program.cs" above line:
Application.Run(new Form_1());
and below lines:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
You didn't reference using WPF, but if you are, this could be the cause of your error. If not, ILMerge should work fine for you. If you are using WPF, here is a solution that works well:
http://blogs.interknowlogy.com/2011/07/13/merging-a-wpf-application-into-a-single-exe/
using the code How to embed a satellite assembly into the EXE file provided by csharptest.net, I've created a custom assembly resolver and embedded my assemblies in my resources.
I can successfully resolve my assemblies used in but somehow AppDomain.CurrentDomain.AssemblyResolve asks for an assembly called 'AppName.resources' specifically "MyProgram.resources, Version=0.15.3992.31638, Culture=en-US, PublicKeyToken=null" which i don't know how to resolve?
I've tried to disable loading my custom assemblies from resources (placed all my assembly dll's in program directory) and just enabled AppDomain.CurrentDomain.AssemblyResolve, but it was still asking for it.
I'm a bit confused about this, will appreciate a lot if you can help me on this.
Here's my code for interested ones;
static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
string name = args.Name.Substring(0, args.Name.IndexOf(','));
if (name == "MyProgram.resources") return null;
else name = string.Format("MyProgram.Resources.Assemblies.{0}.dll", name);
lock (_loadedAssemblies)
{
if (!_loadedAssemblies.TryGetValue(name, out assembly))
{
using (Stream io = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
{
if (io == null)
{
MessageBox.Show("MyProgram can not load one of it's dependencies. Please re-install the program", string.Format("Missing Assembly: {0}", name), MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(-1);
}
using (BinaryReader binaryReader = new BinaryReader(io))
{
assembly = Assembly.Load(binaryReader.ReadBytes((int)io.Length));
_loadedAssemblies.Add(name, assembly);
}
}
}
}
return assembly;
}
Answering on my own;
Adding this line to AssemblyInfo.cs solves it and resolver will not get asked for resources any-more.
[assembly: NeutralResourcesLanguageAttribute("en-US", UltimateResourceFallbackLocation.MainAssembly)]
Though this is a work-around should be carefully considered multi-language applications.
More Info:
https://connect.microsoft.com/VisualStudio/feedback/details/526836/wpf-appdomain-assemblyresolve-being-called-when-it-shouldnt
http://blogs.msdn.com/b/kimhamil/archive/2008/11/11/what-does-the-neutralresourceslanguageattribute-do.aspx
http://forums.devshed.com/net-development-87/c-wpf-appdomain-assemblyresolve-being-called-when-it-shouldn-t-669567.html
http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx
This approach fails for machines with non en-US cultures. A better approach is ignoring resources on assembly resolver;
public Assembly Resolver(object sender, ResolveEventArgs args)
{
lock (this)
{
Assembly assembly;
AssemblyName askedAssembly = new AssemblyName(args.Name);
string[] fields = args.Name.Split(',');
string name = fields[0];
string culture = fields[2];
// failing to ignore queries for satellite resource assemblies or using [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)]
// in AssemblyInfo.cs will crash the program on non en-US based system cultures.
if (name.EndsWith(".resources") && !culture.EndsWith("neutral")) return null;
/* the actual assembly resolver */
...
}
}
My situation was a bit more complex and the above solution did not work for me. (That is changing the AssemblyInfo.cs file)
I have moved all my form and image resources to a seperate dll and the moment any of the images are used the 'filenotfoundexception' exception is thrown.
The important information is the following:
Beginning with the .NET Framework 4, the ResolveEventHandler event is raised for all assemblies, including resource assemblies. See the following reference
https://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve(v=vs.110).aspx
The solution turned out to be very simple. If a resource file is requested in the form 'dllname.resources.dll' always return null;
Here is the event code that I have adapted from other samples found. (I have commented the debugging lines - un-comment them if you have a problem using the code.
Add this line in your class. It is used to prevent loading a dll more than once
readonly static Dictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
This is the event method.
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
string keyName = new AssemblyName(args.Name).Name;
if (keyName.Contains(".resources"))
{
return null; // This line is what fixed the problem
}
if (_libs.ContainsKey(keyName))
{
assembly = _libs[keyName]; // If DLL is loaded then don't load it again just return
return assembly;
}
string dllName = DllResourceName(keyName);
//string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); // Uncomment this line to debug the possible values for dllName
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(dllName))
{
if (stream == null)
{
Debug.Print("Error! Unable to find '" + dllName + "'");
// Uncomment the next lines to show message the moment an assembly is not found. (This will also stop for .Net assemblies
//MessageBox.Show("Error! Unable to find '" + dllName + "'! Application will terminate.");
//Environment.Exit(0);
return null;
}
byte[] buffer = new BinaryReader(stream).ReadBytes((int) stream.Length);
assembly = Assembly.Load(buffer);
_libs[keyName] = assembly;
return assembly;
}
}
private static string DllResourceName(string ddlName)
{
if (ddlName.Contains(".dll") == false) ddlName += ".dll";
foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
if (name.EndsWith(ddlName)) return name;
}
return ddlName;
}
We save and read files by (de) serializing a class named "DocumentClass".
All was working well, untill we added 2 more fields to the documentclass. (We think that's the problem)
When we now try to open files that were serialized by the previous edition, we get an error.
System.ArgumentException: Object of type 'System.Int32' cannot be converted to type 'System.String'.
at SoftwareProject.Componenten.Bestand.DocumentClass.d(String A_0)
at de..ctor(String A_0)
at g.a(String A_0)
The method generating the error is the method "Read". (DocumentClass.d() is the obfuscated name )
But things get weirder: when we open the file in VS debug mode, no error is generated, but all fields in the documentclass are 0 or null ???
We are lost here ... please help ...
We've added the [OptionalField] attribute to the new fields, but that doesn't help ..
Why are all values null in debug mode ??
And where is the runtime error coming from ? How can we debug it ?
Thanks in advance!!
public static DocumentClass Read(string fullFilePath)
{
DocumentClass c = new DocumentClass();
Stream s = File.OpenRead(fullFilePath);
BinaryFormatter b = new BinaryFormatter();
//b.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
b.Binder = new MyCustomBinder();
try
{
c = (DocumentClass)b.Deserialize(s);
}
catch( Exception exc )
{
s.Close();
throw exc;
}
finally
{
s.Close();
}
return c;
}
public class MyCustomBinder : SerializationBinder {
public override Type BindToType(string assemblyName, string typeName) {
Type tyType = null;
string sShortAssemblyName = assemblyName.Split(',')[0];
Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies();
if (sShortAssemblyName.ToLower() == "debugAssemblyName")
{
sShortAssemblyName = "AppAssemblyName";
}
foreach (Assembly ayAssembly in ayAssemblies) {
if (sShortAssemblyName == ayAssembly.FullName.Split(',')[0]) {
tyType = ayAssembly.GetType(typeName);
break;
}
}
return tyType;
}
}
.Net has something called "Version Tolerant Serialization" which most likely solves this issue ;)
You should check out this easy to understand example on object serialization:
http://programming.flashadventures.com/c-sharp/writing-objects-to-files-serialization/
I assume you are using BinaryFormatter? This serializer is notoriously brittle, since it (by default) includes the field-name in the stream; this impacts obfuscation particularly badly. Presumably the obfuscator is now choosing new named for the fields (perhaps at random, perhaps due to the new fields), and so it can't deserialize correctly.
A few options:
don't obfuscate the DTO
implement ISerializable so the field names don't matter
use a serializer that doesn't care about field names
I'd personally opt for the latter, but I'm a bit biased ;-p I know of people using protobuf-net with obfuscated classes; the data only includes numeric markers, so the meaning isn't really exposed (except of course, by inspection of the data - post codes etc, but that is the job of encryption).
I think you need to use Custom Serialization