System.Reflection.Assembly.FullName返回过时信息?

时间:2011-08-31 15:46:47

标签: .net reflection .net-assembly

在停止服务后,我用新版本替换了Windows服务的EXE。 EXE绝对是新版本,Windows资源管理器属性显示新版本。

但是,程序集(加载System.Reflection.Assembly.LoadFile时)会报告.FullName,这似乎表明它不是最新版本。

这在我部署到的第一个站点上没有发生,所以现在我的版本报告系统似乎表明该站点未升级。 (版本报告由单独的ASP.NET Web服务管理,该服务在某些目录中发布程序集的所有版本,正是此Web服务调用System.Reflection.Assembly.LoadFile)。

这里有什么?是否存在某种缓存(Web服务最后会在升级之前检查该程序集?)

代码很基本:

System.IO.DirectoryInfo assemblies = new System.IO.DirectoryInfo(DirectoryName);
foreach (var f in assemblies.GetFiles(Pattern))
{
    var a = System.Reflection.Assembly.LoadFile(f.FullName);
    l.Add(new VersionManager.Assembly(f.Name, f.LastWriteTime, a.FullName));
}
return l; // l is List<VersionManager.Assembly>

删除EXE并替换它(而不是仅覆盖它)无效。

我写了一个小的控制台应用程序,并在上次查询Web服务约3.5小时后直接在系统上运行它,并且非常惊讶地发现它返回了正确的版本。然后我查询了Web服务,它返回了正确的版本。

二进制或Web服务没有任何改变(尽管它所属的Web应用程序可能已被回收,但Web服务本身并不存储它检索到的有关程序集的信息,它只是在响应中将它们发送出去)

更新 - 2011-12-20:

此问题已重新发生。我部署到一个站点,然后在所有站点上运行我的库存程序,并且站点报告了正确的版本。我部署到另外两个站点,DLL上的属性提供了正确的版本,但通过在另外两个站点上加载System.Reflection报告的版本信息已过期。它似乎在第一次通话后被缓存,并重新用于第二次通话。

澄清

有一个IIS ASP.NET(.NET 2.0)Web服务,它报告系统目录中的组件的DLL版本(不属于Web服务的目录)。其中一个目录包含Windows服务的EXE和配置。当Windows服务停止,EXE被替换并且Web服务被询问时,它有时会报告旧版本。如果暂时没有调用Web服务,则会在下次查询时正确报告替换EXE。如果在替换之前调用了Web服务,则在替换之后它不会报告任何更改,尽管已经替换了EXE并通过Windows资源管理器等报告了正确的版本。

我注意到LoadFile没有伴随任何类型的卸载。即使对程序集的引用超出了范围,我想知道它是否仍然保持加载状态(因此在后续调用中不会刷新,因此仍然会报告过期信息),直到IIS或其他任何内容过期。有没有办法卸载组件?有没有办法获得汇编文件的版本信息而不首先加载它?

2 个答案:

答案 0 :(得分:1)

使用System.Reflection.Assembly.LoadFile(FileName)加载程序集,在没有完全卸载AppDomain的情况下无法卸载程序集。

为了检查装配而不加载它,另一种方法是改变:

var a = System.Reflection.Assembly.LoadFile(f.FullName);

到此:

var a = System.Reflection.AssemblyName.GetAssemblyName(f.FullName);

答案 1 :(得分:1)

不应该使用Inspect Appdomain解决问题吗?或安全性是否禁止创建新的domaion?

using System;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create a new domain for loading extra Assemblies
            AppDomain inspectDomain = AppDomain.CreateDomain("Inspect");

            // attach handler to show that no assemblies are loaded in the current domain
            AppDomain.CurrentDomain.AssemblyLoad +=new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad);

            // another prove
            int startcount = AppDomain.CurrentDomain.GetAssemblies().Length;

            // now call the inspection method in the inspectionDomain
            inspectDomain.DoCallBack(new CrossAppDomainDelegate(Inspect));

            // what is the count on assemblies in the curent domain
            int endcount = AppDomain.CurrentDomain.GetAssemblies().Length;

            // show it
            Console.WriteLine("Appdomain {2} # start: {0}  and end {1}", 
                startcount, 
                endcount, 
                AppDomain.CurrentDomain.FriendlyName);

            // unload our inspectdomain and therefor the loaded assemblies
            AppDomain.Unload(inspectDomain);

            // pause so we can see
            Console.ReadLine();
        }

        static void  CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
        {
            // write a line for a loaded assembly
            Console.WriteLine("program domain: {0}", args.LoadedAssembly.FullName);
        }

        public static void Inspect()
        {
            Console.WriteLine("Inspecting...");
            int startcount = AppDomain.CurrentDomain.GetAssemblies().Length;
            var assemblies = new DirectoryInfo(
                    @"C:\Windows\Microsoft.NET\Framework64\v2.0.50727");
            foreach (var f in assemblies.GetFiles("System.Data.*.dll"))
            {
                var a = System.Reflection.Assembly.LoadFile(f.FullName);
                Console.WriteLine("name:{0}, rt:{1}", a.FullName, a.ImageRuntimeVersion);
            }
            int endcount = AppDomain.CurrentDomain.GetAssemblies().Length;
            Console.WriteLine("Appdomain {2} start: {0}  and end {1}", 
                startcount, 
                endcount, 
                AppDomain.CurrentDomain.FriendlyName);
            Console.WriteLine("Done Inspecting...");
        }
    }
}