我正在创建一个简单的独立.net winforms应用程序。它引用了.Net Framework 4的程序集Microsoft.SqlServer.SqlWmiManagement
,它可能存在于客户端计算机上,也可能不存在。如果该程序集不存在,那么在运行时我希望我的应用程序正常失败而不会崩溃。
我有一个开始的组件:
...
using Microsoft.SqlServer.SqlWmiManagement;
...
try {
// do something that uses SqlWmiManagement
}
catch {
// handle the missing assembly
}
不幸的是,在我的小块尝试块之前,当组件加载时抛出未处理的异常。
这样做的正确方法是什么?
没有安装程序,这应该是一个拖放式exe。
答案 0 :(得分:7)
如果找不到程序集,则会触发AssemblyResolve事件。您可以尝试捕获并退出应用程序。 See this MSDN
public static void Main()
{
// Note: AssemblyResolve occurs when the resolution of an assembly fails.
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
}
private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
if ( args.Name.Contains("SqlWmiManagement"))
{
// assembly not found
}
return null;
}
答案 1 :(得分:2)
当函数是JIT时抛出异常。将您的代码更改为:
void DoSomethingThatUsesSqlWmiManagement_()
{
...
}
void DoSomethingThatUsesSqlWmiManagement()
{
try
{
DoSomethingThatUsesSqlWmiManagement_();
}
catch
{
handle the missing assembly
}
}
您可能应该catch
仅限Exception
。
答案 2 :(得分:2)
确保包含Main()函数的类不引用与程序集相关的任何内容。
如果它被定义为主表单的一部分,请在自己的类中将其删除。
然后,在方法的最开始使用Assembly.Load()。您必须将SqlWmiManagement.dll程序集的完全限定名称作为参数传递。
答案 3 :(得分:2)
我想我通过纠正代码中的范围来解决这个问题。使用这篇文章:
我将需要Microsoft.SqlServer.SqlWmiManagement
的方法移动到一个单独的类中。分离它意味着我可以从try {}
块内部调用它,该块在范围之前启动,导致组件被隐式加载。这意味着我可以从失败的程序集负载中捕获异常。
而不是:
using Microsoft.SqlServer.SqlWmiManagement;
// .net implicitly loads assembly when current class is instantiated
// ... code ...
try {
// problem method using missing assembly
}
catch {
// this is ineffective because the ass'y load already failed before the try block
}
我能够:
try {
// invoke problem method in another class
// implicitly loads assembly here instead, inside the try block
}
catch {
// this now catches ass'y load failure
}
答案 4 :(得分:0)
虽然@CC Inc的答案在调用Main()
后加载引用时有效,但对于使用静态对象或类的引用,需要在ResolveEventHandler
之前安装Main()
调用。你可以尝试:
private static bool gAutoLoad = ExecuteBeforeMain();
private static bool ExecuteBeforeMain()
{
// Note: AssemblyResolve only occurs when the resolution of an assembly fails.
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolveErrorHandler;
return true;
}
private static System.Reflection.Assembly AssemblyResolveErrorHandler(object sender, ResolveEventArgs args)
{ ... }
我认为没有保证ExecuteBeforeMain()
足够早地执行(在尝试加载引用之前),但是当我包含我的记录器时它适用于我,如下所示:< / p>
ReferenceNamespace.LoggerClass.StaticActiveLogger.LogMethod(string);