我有一个框架,其中包含许多基类,可以派生它们来开发许多应用程序。在这些类中有一个System.Windows.Forms.Panel的子类,我为它编写了自己的设计器。 Visual Studio 2005一切正常,但当我尝试迁移到VS2010时出现问题。这是我正在做的简化版本:
我有一个名为CoreClasse的项目,它包含一个接口和两个类:
public interface IConf
{
string foo { get; set; }
void InitFoo();
}
public class SimpleClass
{
public string foo;
}
public class ConfLoader
{
public static IConf LoadConf()
{
AssemblyName anAssemblyName = new AssemblyName("ConfClasses");
Assembly anAssembly = Assembly.Load(anAssemblyName);
IConf result = (IConf)anAssembly.CreateInstance("ConfClasses.ConfClass");
result.InitFoo();
return result;
}
}
然后有一个项目ConfClasses引用CoreClasses并且只包含一个实现IConf的类:
public class ConfClass : IConf
{
public SimpleClass confVal;
public string foo
{
get { return confVal.foo; }
set { confVal.foo = value; }
}
public void InitFoo()
{
confVal = new SimpleClass();
confVal.foo = "bar";
}
}
最后有一个控件项目,它只引用CoreClasses并包含Panel的子类和相关的设计器:
[Designer("MyControls.Design.SimplePanelDesigner", typeof(IRootDesigner))]
public class SimplePanel : Panel
{
public SimpleClass dummy = new SimpleClass();
}
public class SimplePanelDesigner : DocumentDesigner
{
public IConf DesignerConf;
public SimplePanelDesigner()
: base()
{
DesignerConf = ConfLoader.LoadConf();
}
}
现在我创建另一个引用所有这些dll的解决方案,并包含一个SimplePanel的空子类。当我在SolutionExplorer中双击此类时,将执行SimplePanelDesigner的构造函数并调用ConfLoader的方法LoadConf。这意味着ConfClasses.dll以dinamically方式加载,并创建一个ConfClass实例。到目前为止一切都很好,但是当调用InitFoo时,会引发异常:
无法加载文件或程序集“CoreClasses,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null”或其依赖项之一。系统找不到指定的文件。
为了使事情变得更难,在这个例子中实际上没有提出异常,但这正是我真正的应用程序正在执行的那种结构,以及我得到的异常。我还没有弄清楚这里发生了什么。 VS正在执行CoreClasses中的IS方法。为什么要再次加载它?它在哪里寻找它?我也检查了当前的AppDomain,但它在加载的程序集中有CoreClasses,它似乎没有改变。
只是为了添加更多细节,每个项目都是在一个公共文件夹中构建的(不是项目文件夹中常用的obj / debug文件夹),而且当我启动我的时候,PC上没有其他的dll副本测试。然后所有引用的dll的副本在我的userprofile的AppData \ Local \ Microsoft \ VisualStudio \ 10.0 \ ProjectAssemblies文件夹中的一系列文件夹中完成,这似乎是VS在Assembly.Load中查找程序集的地方执行,我可以在那里找到CoreClasses的副本。我试图清理所有文件夹,重建所有内容,并在每个组合中保持打开/关闭不同的解决方案,但没有任何改进。
编辑:
正如GranMasterFlush建议的那样,这是由异常生成的FusionLog:
=== Pre-bind state information ===
LOG: User = FCDB\fc0107
LOG: DisplayName = XEngine.Core, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null (Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio 10.0/Common7/IDE/
LOG: Initial PrivatePath = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: The same bind was seen before, and was failed with hr = 0x80070002.
ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).
编辑2
为了添加一些信息,我看了一下我的简单示例生成的融合日志,发现在尝试加载CoreClasses时生成了完全相同的日志,但是VisualStudio找到了解决它的方法。
答案 0 :(得分:4)
我刚刚发现了正在发生的事情。简单示例和真实事物之间的区别在于涉及AddIn。
这是一个相当日志的故事,但就是这样。
从代码示例中可以看出,我通过反射加载ConfClasses dll,以避免添加对它的引用。这在运行时很好,但设计师抱怨说它无法将IConf转换为IConf。发生这种情况是因为CoreClasses.dll是在设计器启动时从AppData \ Local \ Microsoft \ VisualStudio \ 10.0 \ ProjectAssemblies加载的,但ConfClasses.dll是从我的bin文件夹加载的,因此它的引用也是如此,因此有两个版本的CoreClasses.dll和不同版本的IConf。
为了绕过这个问题,我开发了一个AddIn,当在设计时使用Assembly.Load加载程序集时,添加对该程序集的引用,然后在关闭最后一个设计器窗口时清除引用。
VS2005一切正常,但使用ProcMon.exe我发现VS2010添加了一个新的文件夹,其中插件寻找程序集:程序文件(x86)\ Microsoft Visual Studio 10.0 \ Common7 \ IDE \ CommonExtensions \ DataDesign
我在那里复制了我的装配,一切都恢复了。现在只需要找到一种手动添加东西的方法。
答案 1 :(得分:2)
您是否尝试过使用程序集绑定日志查看器来调查加载程序集失败的原因?
http://msdn.microsoft.com/en-us/library/e74a18c4%28v=vs.71%29.aspx
这里有另一篇关于使用它的文章:
http://blogs.msdn.com/b/suzcook/archive/2003/05/29/57120.aspx
编辑:
DLL存储在哪里?这个forum post详细说明了一个类似的问题,问题在于引用的DLL不在GAC,可执行目录或可执行目录的子文件夹中: