C# 可执行文件失败,出现异常

C# 可执行文件失败,出现异常,c#,.net,quartz.net,ilmerge,C#,.net,Quartz.net,Ilmerge,我正在C#NET 4.0 Windows服务应用程序中使用ILMerge和Quartz.NET。该应用程序在不使用ILMerge的情况下运行良好,但现在我们即将发布,我想将所有DLL合并到一个可执行文件中 问题是,ILMerge似乎工作正常,但当我运行组合的可执行文件时,它会引发以下异常: public static T InstantiateType<T>(Type type) { if (type == null) {

我正在C#NET 4.0 Windows服务应用程序中使用ILMerge和Quartz.NET。该应用程序在不使用ILMerge的情况下运行良好,但现在我们即将发布,我想将所有DLL合并到一个可执行文件中

问题是,ILMerge似乎工作正常,但当我运行组合的可执行文件时,它会引发以下异常:

    public static T InstantiateType<T>(Type type)
    {
        if (type == null)
        {
            throw new ArgumentNullException("type", "Cannot instantiate null");
        }
        ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);
        if (ci == null)
        {
            throw new ArgumentException("Cannot instantiate type which has no empty constructor", type.Name);
        }
        return (T) ci.Invoke(new object[0]);
    }
未处理的异常:Quartz.SchedulerException:无法实例化线程池类型“Quartz.siml.SimpleThreadPool”。-->System.InvalidCastException:无法将类型为“Quartz.siml.SimpleThreadPool”的对象强制转换为类型为“Quartz.Spi.IThreadPool”。
在Quartz.Util.ObjectUtils.InstanceType[T](类型)中:第0行
在Quartz.Impl.StdSchedulerFactory.Instantiate()中:第0行
---内部异常堆栈跟踪结束---
在Quartz.Impl.StdSchedulerFactory.Instantiate()中:第0行
第0行中的Quartz.Impl.StdSchedulerFactory.GetScheduler()处

有人知道这是为什么吗?我已经浪费了4个多小时,我想不出来了。如果不与ILMerge结合,那么一切都会正常运行(Quartz.dll和Common.Logging.dll位于同一目录中)


我相信以前一定有人尝试过这样打包Quartz.net,有什么想法吗?

您可以尝试创建自己的ISchedulerFactory,避免使用反射加载所有类型。 StdSchedulerFactory使用此代码创建线程池。这是您的错误发生的地方,也是开始考虑进行更改的地方:

        Type tpType = loadHelper.LoadType(cfg.GetStringProperty(PropertyThreadPoolType)) ?? typeof(SimpleThreadPool);

        try
        {
            tp = ObjectUtils.InstantiateType<IThreadPool>(tpType);
        }
        catch (Exception e)
        {
            initException = new SchedulerException("ThreadPool type '{0}' could not be instantiated.".FormatInvariant(tpType), e);
            throw initException;
        }
Type tpType=loadHelper.LoadType(cfg.GetStringProperty(PropertyThreadPoolType))??typeof(SimpleThreadPool);
尝试
{
tp=ObjectUtils.InstanceType(tpType);
}
捕获(例外e)
{
initException=new SchedulerException(“无法实例化线程池类型“{0}”。.FormatInvariant(tpType),e);
抛出initException;
}
调用的ObjectUtils.InstanceType方法是此方法,最后一行是引发异常的方法:

    public static T InstantiateType<T>(Type type)
    {
        if (type == null)
        {
            throw new ArgumentNullException("type", "Cannot instantiate null");
        }
        ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);
        if (ci == null)
        {
            throw new ArgumentException("Cannot instantiate type which has no empty constructor", type.Name);
        }
        return (T) ci.Invoke(new object[0]);
    }
publicstatict实例化类型(Type)
{
if(type==null)
{
抛出新ArgumentNullException(“类型”,“无法实例化null”);
}
ConstructorInfo ci=type.GetConstructor(type.EmptyTypes);
if(ci==null)
{
抛出新ArgumentException(“无法实例化没有空构造函数的类型”,type.Name);
}
返回(T)ci.Invoke(新对象[0]);
}

在工厂的这一部分之后,数据源使用相同的模式加载,然后作业本身也动态加载,这意味着您还必须编写自己的JobFactory。由于Quartz.Net在运行时动态加载了大量的比特和片段,沿着这条路走下去意味着您可能最终会重写相当多的内容。

免责声明:我根本不了解Quartz.Net,尽管我花了一些时间在ILMerge上。当我终于明白它的局限性。。。我停止使用它

ILMerge的应用程序在包含“反射”一词的所有内容上都有问题。 我可以猜测(我从未使用过Quartz.NET)某些类是使用反射解析的,并由配置文件驱动的

类不仅由其名称(带有名称空间)标识,而且由它来自的程序集标识(不幸的是,它没有显示在异常消息中)。 所以,让我们假设您(在合并之前)有两个程序集A(用于您的应用程序)和Q(用于Quartz.NET)。 程序集“A”引用程序集“Q”,并使用实现“Q:QIntf”的类“Q:QClass”。 合并后,这些类变成了“A:QClass”和“A:QIntf”(它们从程序集Q移到了A),代码中的所有引用都被替换为使用这些(完全)新的类/接口,因此“A:QClass”现在正在实现“A:QIntf”。 但是,它没有更改任何可能仍然引用“Q:QClass”的配置文件/嵌入字符串

所以,当应用程序读取这些未更新的配置文件时,它仍然会加载“Q:QClass”(为什么它会发现这是一个不同的问题,可能是您将程序集“Q”留在了当前文件夹中,也可能是在GAC中-请参阅1)。 无论如何,“Q:QClass”并没有实现“A:QIntf”,即使它们是二进制相同的,它仍然实现“Q:QIntf”——所以你不能将“Q:QClass”强制转换为“A:QIntf”

不理想但可行的解决方案是“嵌入”程序集,而不是“合并”它们。我写了一个开源工具来实现它(嵌入而不是合并),但它与这个问题无关。所以,如果你决定嵌入,就问我

  • 你可以通过删除(隐藏,任何对你有用的东西)你电脑上Q.dll的每个实例来测试它。如果我是对的,异常现在应该是“FileNotFound”

  • 这是您第一次尝试将其与ILMerge相结合吗?或者它在最近的更改之前工作吗?我第一次尝试使用ILMerge时,运行它,不再工作了。我想它一定是ILMerge,尝试了internalize标志,没有改变任何东西。删除ILMerge,它是正常编译的(就像我在尝试之前所做的那样),所有都可以工作(如果DLL在同一个目录中)。ILMerge不能处理的事情之一是从外部程序集加载类型(这种情况可能是基于对stacktrace的浏览)。也许还可以研究@rene发现的一种替代方法,这是否意味着我应该尝试在启动时手动加载这些外部程序集(不确定是哪个)?这能解决问题吗?@rene stracktrace的哪一部分会告诉您缺少一个程序集?它在抱怨无效的强制转换?我最终没有使用ILMERGE,它根本不起作用,而且似乎它需要做的工作比在部署运行中减少一个文件的好处多得多。我还尝试了嵌入,动态加载程序集,这有助于我了解更多的s背后的内容