C# System.Runtime.Serialization.SerializationException:无法找到程序集 MyAssembly
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14990980/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
System.Runtime.Serialization.SerializationException: Unable to find assembly MyAssembly
提问by Geesu
So I've found a bunch of threads on this topic but I don't think I've found one that applies yet.
所以我在这个主题上找到了一堆主题,但我认为我还没有找到一个适用的主题。
Basically my .exe loads a .dll (MyAssembly) file which does the serialization and loading. Obviously it serializes quite fine.
基本上我的 .exe 加载一个 .dll (MyAssembly) 文件,它执行序列化和加载。显然它序列化得很好。
But when I go to deserialize the file within the MyAssembly.dll file it explodes with the error in the title of this post.
但是当我去反序列化 MyAssembly.dll 文件中的文件时,它会因这篇文章标题中的错误而爆炸。
Anyone have any ideas? I don't understand how it can't find the assembly that is calling the code!
谁有想法?我不明白它怎么找不到调用代码的程序集!
My code:
我的代码:
// deserialize
using (var target = new System.IO.FileStream(Path, System.IO.FileMode.OpenOrCreate))
{
var bin = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
var Obj = bin.Deserialize(target);
if (Obj != null)
{
ObjectToStore = (ObjectTypeInMyAssembly)Obj;
}
}
// serialize
using (var target = new System.IO.FileStream(Path, System.IO.FileMode.OpenOrCreate))
{
var bin = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
bin.Serialize(target, ObjectToStore);
}
回答by SASS_Shooter
What I see in your code with both your serialize and deserialize is the use of the System.IO.Path class instead of the actual path to the file. I usually execute this as follows:
我在您的序列化和反序列化代码中看到的是 System.IO.Path 类的使用,而不是文件的实际路径。我通常按如下方式执行:
static void Main(string[] args)
{
string filepath = @"C:\FileLocation\";
string filename = "datasaved.bin";
MyClass something = new MyClass();
// serialize
using ( FileStream strm = File.OpenWrite(Path.Combine(filepath, filename)))
{
BinaryFormatter ser = new BinaryFormatter();
ser.Serialize(strm, something);
}
// deserialize
using (FileStream strm = File.OpenRead(Path.Combine(filepath, filename)))
{
BinaryFormatter ser = new BinaryFormatter();
something = ser.Deserialize(strm) as MyClass;
}
}
Note two things: doing the Deserialize aswill handle the object being null or not the expected type. Also I don't abuse the use of var.
请注意两件事:执行Deserialize as将处理对象为 null 或不是预期类型。此外,我不滥用 var 的使用。
回答by RoadBump
Is the DLL in the same folder like the EXE?
I see you serialize/deserialize a object that lives in the DLL ("MyAssembly"). When deserialize, the formatter determines the name of the type from serialized data, and tries to find this type in the assembly at the main executable folder, that is- EXE folder.
Solution- move the DLL to EXE folder. There is a way to cause the formatter to search in another assembly, capture the event AppDomain.AssemblyResolve
and return your DLL. See MSDN.
DLL 和 EXE 是否在同一个文件夹中?
我看到您序列化/反序列化位于 DLL 中的对象(“MyAssembly”)。反序列化时,格式化程序根据序列化数据确定类型的名称,并尝试在主可执行文件夹(即 EXE 文件夹)的程序集中找到此类型。
解决方案 - 将 DLL 移动到 EXE 文件夹。有一种方法可以让格式化程序在另一个程序集中搜索、捕获事件AppDomain.AssemblyResolve
并返回您的 DLL。请参阅MSDN。
回答by Sean Ed-Man
Well, I used a trick that worked!
好吧,我使用了一个有效的技巧!
sealed class CustomizedBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type returntype = null;
string sharedAssemblyName = "SharedAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
assemblyName = Assembly.GetExecutingAssembly().FullName;
typeName = typeName.Replace(sharedAssemblyName, assemblyName);
returntype =
Type.GetType(String.Format("{0}, {1}",
typeName, assemblyName));
return returntype;
}
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
base.BindToName(serializedType, out assemblyName, out typeName);
assemblyName = "SharedAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
}
}
use the binder for binary formatters, like this:
将绑定器用于二进制格式化程序,如下所示:
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new CustomizedBinder();
回答by klugerama
I'd like to build on Sean Ed-Man's answer, which is good, but doesn't work in my case.
我想以Sean Ed-Man的答案为基础,这很好,但在我的情况下不起作用。
If you can instantiatethe class but the BinaryFormatter
can't resolve it, this may work for you.
如果您可以实例化该类但BinaryFormatter
无法解决它,则这可能对您有用。
In my case, the calling assembly (PluginAssembly
for this example) is being run as a plugin from the executable, in the form of a zip file. For some reason I can directly resolve the class (from NeededAssembly
) when instantiating, but the BinaryFormatter
can't resolve it. NeededAssembly
is, of course, included as a reference to the PluginAssembly
project, which is why I can instantiate. I don't know why the BinaryFormatter
is different.
在我的例子中,调用程序集(PluginAssembly
对于这个例子)作为一个插件从可执行文件中以 zip 文件的形式运行。出于某种原因,我可以NeededAssembly
在实例化时直接解析类 (from ),但BinaryFormatter
无法解析它。NeededAssembly
当然,作为对PluginAssembly
项目的引用包含在内,这就是我可以实例化的原因。不知道为什么不BinaryFormatter
一样
Regardless, this is what worked for me:
无论如何,这对我有用:
public class PluginAssembly
{
// (class code here)
private sealed class CustomizedBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
Type returntype = null;
if (typeName.StartsWith("NeededAssembly.RemoteClient.MessagePayload"))
{
returntype = typeof(MessagePayload);
}
else if (typeName.StartsWith("NeededAssembly.RemoteClient.ResultsPayload"))
{
returntype = typeof(ResultsPayload);
}
else if (typeName.Equals("System.Collections.Generic.List`1[[NeededAssembly.ShortResult, NeededAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"))
{
returntype = typeof(List<ShortResult>);
}
else
{
returntype =
Type.GetType(String.Format("{0}, {1}",
typeName, assemblyName));
}
return returntype;
}
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
base.BindToName(serializedType, out assemblyName, out typeName);
if (serializedType.ToString().Contains("NeededAssembly"))
{
assemblyName = typeof(MessagePayload).Assembly.FullName;
}
}
}
}
Of course, don't forget to use it:
当然,不要忘记使用它:
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new CustomizedBinder();
Basically I simply get a typeof
for the needed class, which works.
基本上,我只是typeof
为所需的课程获得了一个,这很有效。
回答by andrew pate
I would check if Marc Gravell's answer hereapplies... in short "One option would be to move the type to a library dll that both the other projects reference - then it is only defined once, and it will be happy"
我会检查是否马克Gravell的答案在这里适用......总之“一个选择是将类型移动到库DLL,无论是其他项目的参考-那么它仅仅定义一次,它会很高兴”
In my case I had temporarily created a copy of the class that I intended to serialize (in the assembly doing the serializing) early in development, but forgot about it when deserializing! So the deserializer never did have access to the same class that did the serialising!
在我的例子中,我临时创建了一个我打算在开发早期序列化(在程序集中进行序列化)的类的副本,但在反序列化时忘记了它!所以反序列化器从来没有访问过进行序列化的同一个类!
It is also worth checking out the properties of the project containing the class being serialized - Check for typos in its assembly name. You might want to try flattening out your namespace hierachy too to see if that helps.
还值得检查包含正在序列化的类的项目的属性 - 检查其程序集名称中的拼写错误。您可能还想尝试扁平化您的命名空间层次结构,看看是否有帮助。
回答by Artfunkel
There is yet another solution to this problem, which is to list the folder containing the assembly in App.config. You do this by adding a probing
element, like this:
这个问题还有一个解决方案,就是在 App.config 中列出包含程序集的文件夹。您可以通过添加一个probing
元素来完成此操作,如下所示:
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin;bin2\subbin;bin3"/>
</assemblyBinding>
</runtime>
</configuration>
回答by Brad Oestreicher
I had a specific case of the SerializationException described by the OP, and found a relatively simple solution. In my case, I am implementing a DeepClone extension method using the BinaryFormatter technique. My application also makes use of plug-ins, assemblies that I load programmatically. I encountered the SerializationException when the BinaryFormatter.Deserialize method was called for an object whose class is contained in a plug-in.
我有OP描述的SerializationException的一个具体案例,并找到了一个相对简单的解决方案。就我而言,我正在使用 BinaryFormatter 技术实现 DeepClone 扩展方法。我的应用程序还使用了我以编程方式加载的插件和程序集。当为某个类包含在插件中的对象调用 BinaryFormatter.Deserialize 方法时,我遇到了 SerializationException。
I find this very strange, because, by definition, the containing assembly is loaded into my AppDomain. (I couldn't call an extension method on the object if it wasn't!) Apparently, the BinaryFormatter does not check the AppDomain to resolve assemblies.
我觉得这很奇怪,因为根据定义,包含程序集已加载到我的 AppDomain 中。(如果不是,我就不能在对象上调用扩展方法!)显然,BinaryFormatter 不会检查 AppDomain 来解析程序集。
Many of the solutions suggested here for solving this problem seem to involve hard coding the name of the assembly, or class, into a custom SerializationBinder. This is not useful, as I want my DeepClone method to be as generic as possible. My answer to this problem (shown below) hooks the AssemblyResolve event in the current AppDomain and then searches the AppDomain (using LINQ) for the requested assembly. No hard coded assembly or class names required.
此处建议的许多解决此问题的解决方案似乎涉及将程序集或类的名称硬编码到自定义 SerializationBinder 中。这没有用,因为我希望我的 DeepClone 方法尽可能通用。我对这个问题的回答(如下所示)将当前 AppDomain 中的 AssemblyResolve 事件挂钩,然后在 AppDomain(使用 LINQ)中搜索请求的程序集。不需要硬编码的程序集或类名。
Here is the code:
这是代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
namespace StackOverflowDemo
{
public static class Extend
{
/// <summary>
/// Static initializer is used to register the Resolve Event Handler
/// </summary>
static Extend()
{
AppDomain.CurrentDomain.AssemblyResolve += ResolveEventHandler;
}
/// <summary>
/// This resolver will find any Assembly that is already loaded into
/// the current AppDomain and return it.
/// <para/>
/// You would think this would not be necessary, but the
/// BinaryFormatter.Deserialize method apparently can not
/// find an assembly that has been loaded programmatically
/// as a plug-in, and whose DLL does not reside in the same
/// folder as the executable file.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
/// <returns></returns>
private static Assembly ResolveEventHandler( object sender, ResolveEventArgs args )
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
Assembly result = (from a in assemblies where args.Name.Equals(a.FullName) select a).FirstOrDefault();
return result;
}
/// <summary>
/// Slow, and requires that the source be marked as [Serializable], but
/// clones *everything* and is not complicated.
/// <para/>
/// Note that by itself, this method will fail if an attempt is made to
/// create a deep copy of an object whose class is contained in an assembly
/// that was loaded programmatically (i.e., loaded as a plug-in).
/// <para/>
/// See https://stackoverflow.com/a/1213649
/// <para/>
/// and https://stackoverflow.com/a/23017515
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="src"></param>
/// <returns></returns>
public static T DeepClone<T>( this T src )
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException(string.Format("[Extend.DeepClone] Type '{0}' is not Serializable", typeof(T).Name));
}
if (Object.ReferenceEquals(src, null))
{
return default(T);
}
using (Stream stream = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, src);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
}
}
回答by Sandy Skelton
I had a problem with this exception. I am writing a WPF plugin for a third party application. The application loads my assembly which should deserialize a type from another dll, MyType for example, which is in a private assembly added as a reference to my plugin and in the same directory as the plugin dll.
我遇到了这个异常的问题。我正在为第三方应用程序编写 WPF 插件。应用程序加载我的程序集,它应该反序列化来自另一个 dll 的类型,例如 MyType,该程序集位于作为对我的插件的引用添加的私有程序集中,并且与插件 dll 位于同一目录中。
What seems strange to me was that I can instantiate MyType in the plugin, but it throws this exception when deserializing in the same class.
我觉得奇怪的是,我可以在插件中实例化 MyType,但是在同一个类中反序列化时它会抛出这个异常。
The solution for me was suggested by RoadBumpand is very straightforward, but I don't understand why the surrounding code can find the assembly (if it can't this method will not work) but the deserialization call in the same code, can't.
RoadBump为我提供的解决方案非常简单,但我不明白为什么周围的代码可以找到程序集(如果不能,此方法将不起作用)但在同一代码中进行反序列化调用,则可以'吨。
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyTypeResolveEventHandler);
private Assembly MyTypeResolveEventHandler(object sender, ResolveEventArgs args)
{
return typeof(MyType).Assembly;
}