【问题标题】:Using the Web Application version number from an assembly (ASP.NET/C#)使用程序集中的 Web 应用程序版本号 (ASP.NET/C#)
【发布时间】:2009-04-16 13:06:35
【问题描述】:

如何在引用的程序集中获取调用 Web 应用程序的版本号?

我尝试过使用 System.Reflection.Assembly.GetCallingAssembly().GetName() 但它只是给了我动态编译的程序集(返回版本号 0.0.0.0)。

更新:就我而言,我需要一个不需要引用回 Web 应用程序程序集中的类的解决方案。 Jason 在下面的回答(标记为已接受)满足了这一要求 - 这里提交的许多其他人都没有。

【问题讨论】:

  • "...我需要一个不需要引用回 Web 应用程序程序集中的类的解决方案" - 我很想知道您为什么需要这个。我必须说我认为 Yodan Tauber 的解决方案在我看来比公认的答案要干净得多 - 尽管我会使用 typeof(Global) 而不是特定于应用程序的类名。
  • @Joe - 该方法位于各种解决方案中使用的共享程序集中。这些应用程序可能是也可能不是 Web 应用程序。无论哪种方式,我都需要能够获取应用程序的版本号,而无需实际引用应用程序中的类。
  • @David 我发现这是一个令人困惑且措辞不佳的问题,即使您的更新也是如此。如果您选择的答案是您真正想要的,那么问题需要修改以避免混淆。您应该包括可能被非 Web 应用程序调用的要求,并且您不知道 HttpApplication (global.cs) 类型或程序集中的任何类型。如果是这种情况,我会考虑重构这个接口。

标签: c# .net asp.net reflection assemblies


【解决方案1】:

这是我使用的一些代码,它支持从 Web 或非 Web 应用程序获取应用程序的“主”程序集,然后您可以使用 GetName().Version 来获取版本。

它首先为非 Web 应用程序尝试 GetEntryAssembly()。这在 ASP.NET 下返回 null。 然后它查看 HttpContext.Current 以确定这是否是一个 Web 应用程序。然后它使用当前 HttpHandler 的类型 - 但如果调用是从 ASPX 页面进行的,则此类型的程序集可能是生成的 ASP.NET 程序集,因此它遍历 HttpHandler 的 BaseType 链,直到找到不在其中的类型ASP.NET 为其生成的类型(“ASP”)使用的命名空间。 这通常是主程序集中的一种类型(例如,代码隐藏文件中的页面)。然后我们可以使用该类型的程序集。 如果所有其他方法都失败,则回退到 GetExecutingAssembly()。

这种方法仍然存在潜在问题,但它适用于我们的应用程序。

    private const string AspNetNamespace = "ASP";

    private static Assembly getApplicationAssembly()
    {
        // Try the EntryAssembly, this doesn't work for ASP.NET classic pipeline (untested on integrated)
        Assembly ass = Assembly.GetEntryAssembly();

        // Look for web application assembly
        HttpContext ctx = HttpContext.Current;
        if (ctx != null)
            ass = getWebApplicationAssembly(ctx);

        // Fallback to executing assembly
        return ass ?? (Assembly.GetExecutingAssembly());
    }

    private static Assembly getWebApplicationAssembly(HttpContext context)
    {
        Guard.AgainstNullArgument(context);

        object app = context.ApplicationInstance;
        if (app == null) return null;

        Type type = app.GetType();
        while (type != null && type != typeof(object) && type.Namespace == AspNetNamespace)
            type = type.BaseType;

        return type.Assembly;
    }

更新: 我已将此代码汇总到GitHubNuGet 上的一个小项目中。

【讨论】:

  • 这是我一直在寻找的答案 - 它似乎是唯一真正检索“Web 应用程序”版本(而不是您所在的程序集版本)而不依赖于在配置文件中记录版本。不错。
  • getWebApplicationAssembly 的版本对我不起作用,因为 IHttpHandler 为空。我想出了一个使用httpContext.ApplicationInstance 而不是context.CurrentHandler 的版本。
  • 感谢克里斯蒂的提示。我猜 context.CurrentHandler 仅适用于直接为 asp.net 请求提供服务的线程,并且仅在创建 IHttpHandler 之后才有效。
  • @Cristi: 应该回答这个问题
  • @toddkitta:Yodan 的回答将引入从引用的程序集 BACK 到 Web 应用程序中的类的依赖关系。我更喜欢我可以使用的解决方案,它不引用该项目中的任何类。
【解决方案2】:

我发现获取“主”程序集(而不是动态程序集)版本的最简单的单行方法是:

typeof(MyMainClass).Assembly.GetName().Version

使用您的顶级类,它不可能“改变其含义”或作为重构工作的一部分被替换,如MyMainClass。您知道这个类是在哪个程序集中定义的,并且不会再混淆版本号的来源。

【讨论】:

  • +1,在我看来,这似乎是最明显和最干净的解决方案,尽管 OP 的更新声明他想要一个不需要引用 Web 应用程序程序集中的类的解决方案(它会如果他说原因,请提供帮助)。如果它是一个 ASP.NET Web 应用程序项目,那么明显要使用的类是 Global,它是 Global.asax 的代码隐藏基类。
  • 唯一的问题是我的带有getversion代码的dll无法访问包含mainclass的顶级dll。
【解决方案3】:

我更喜欢 Web.Config 来存储站点的当前版本。

您也可以尝试在 Web 应用程序根目录中创建一个 AssemblyInfo.cs 文件,该文件具有以下内容:

using System.Reflection;
using System.Runtime.CompilerServices;
...
[assembly: AssemblyVersion("1.0.*")]
...

然后通过如下代码访问值:

System.Reflection.Assembly.GetExecutingAssembly()

这里有更多关于 AssemblyInfo 类的 informaiton

【讨论】:

  • 从实际的 Web 应用程序中检索版本相当容易,但只能在后面的代码中完成 - 使用 System.Reflection.GetExecutingAssembly().GetName().Version.ToString()。我会认为有一些方法可以从引用的程序集中检索它......
  • @David:可能你的意思是System.Reflection.Assembly.GetExecutingAssembly()... :)
  • 在 web.config 中存储应用程序版本可以很容易地从执行代码之外的脚本中检索。我将从 AssemblyVersion 属性切换到 web.config
【解决方案4】:

添加到已经发布的响应者。为了在 ASP.Net Web 应用程序中获取程序集版本,您需要在代码隐藏文件中放置一个方法,类似于:

protected string GetApplicationVersion() {
    return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
}

在ASPX页面中你要显示的版本号只需放置:

<%= GetApplicationVersion() %>

【讨论】:

  • 谢谢,这正是我所追求的。
【解决方案5】:

以防万一有人仍然感兴趣;这应该可以解决问题,并且应该比仅使用 BaseTypeApplicationInstance 来实现 Global.asax 更安全。

Global.asax 始终与 AssemblyInfo.cs 中的程序集属性编译到相同的程序集中,因此这应该适用于定义 Global.asax 的所有 Web 应用程序。

对于那些没有定义自己的 Global.asax,它会回退到生成的 global_asax 类型的版本,它总是 0.0.0.0,对于不是 web 应用程序的应用程序,它会根本不返回任何版本。

奖金;使用BuildManager需要一个活动的HttpContext 实例,这意味着您应该也可以从应用程序启动代码中使用它。

public static Version GetHttpApplicationVersion() {
  Type lBase = typeof(HttpApplication);
  Type lType = BuildManager.GetGlobalAsaxType();

  if (lBase.IsAssignableFrom(lType))
  {
    while (lType.BaseType != lBase) { lType = lType.BaseType; }
    return lType.Assembly.GetName().Version;
  }
  else
  {
    return null;
  }
}

【讨论】:

  • 终于,可行的方法!尝试使用 null 的 entryassembly,使用 null 的 httpcontext 并迭代我的堆栈跟踪,这也不起作用。
【解决方案6】:

HttpContext.Current.ApplicationInstance 派生自 global.asax.cs 中的类。您可以执行以下操作

 var instance = HttpContext.Current.ApplicationInstance;
 Assembly asm = instance.GetType().BaseType.Assembly;
 System.Version asmVersion = asm.GetName().Version;

它适用于 ASP.NET (ASPX) 和 ASP.NET MVC

【讨论】:

    【解决方案7】:

    我遇到了类似的问题,并认为您可能会发现该解决方案很有用。

    我需要从自定义服务器控件报告(Web 应用程序项目的)当前应用程序版本,其中服务器控件包含在不同的库中。问题是“最简单”的装配吸气剂没有提供正确的装配。

    • Assembly.GetExecutingAssembly() 返回包含控件的程序集;而不是应用程序集。
    • Assembly.GetCallingAssembly() 根据我在调用树中的位置返回不同的程序集;通常是 System.Web,有时是包含控件的程序集。
    • Assembly.GetEntryAssembly() 返回null
    • new StackTrace().GetFrames()[idx].GetMethod().DeclaringType.Assembly 在索引idx 处检索堆栈跟踪中的帧的组装;然而,除了不优雅、昂贵且容易对帧索引进行错误计算之外,堆栈跟踪可能不包含对应用程序程序集的任何调用。
    • Assembly.GetAssembly(Page.GetType()) 给我打分了包含动态生成页面的 App_Web_@#$@#$%@ 程序集。当然,动态页面从我的应用程序集中继承了一个类,因此导致了最终的解决方案:

    Assembly.GetAssembly(Page.GetType().BaseType)
    

    有了程序集引用,您可以通过它的名称钻取到版本:

    var version = Assembly.GetAssembly(Page.GetType().BaseType)
                          .GetName()
                          .Version;
    

    现在,此解决方案有效,因为我从应用程序程序集中引用了一个类型。我们不使用任何从背后代码继承的页面,因此它恰好对我们有效,但如果您的组织的编码实践不同,您的里程可能会有所不同。

    编码愉快!

    【讨论】:

    • 简化为:(HttpContext.Current.ApplicationInstance).GetType().BaseType.Assembly.GetName.Version.ToString()
    【解决方案8】:
    Version version = new Version(Application.ProductVersion);
    string message = version.ToString();
    

    【讨论】:

    • 这适用于 Web 应用程序还是仅适用于 Windows 窗体应用程序?
    【解决方案9】:

    这里有一些信息:http://www.velocityreviews.com/forums/showpost.php?p=487050&postcount=8

    在 asp.net 2.0 中,每个页面都内置在它自己的程序集中,所以只有 dll AssemblyInfo.cs 内置于 will 返回正确答案。只需添加一个 AssemblyInfo.cs 的静态方法 返回版本信息,并调用 此方法来自您的其他页面。

    --布鲁斯(sqlwork.com)

    但我写了一个简单的方法来做到这一点:

        public static string GetSystemVersion(HttpServerUtility server)
        {
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.Load(server.MapPath("~/web.config"));
            System.Xml.XmlNamespaceManager ns = new System.Xml.XmlNamespaceManager(doc.NameTable);
            ns.AddNamespace("bla", "http://schemas.microsoft.com/.NetConfiguration/v2.0");
    
            System.Xml.XmlNode node = doc.SelectSingleNode("/bla:configuration/bla:system.web/bla:authentication/bla:forms[@name]", ns);
    
            string projectName = "";
            if (node != null && node.Attributes != null && node.Attributes.GetNamedItem("name") != null)
                projectName = node.Attributes.GetNamedItem("name").Value; //in my case, that value is identical to the project name (projetname.dll)
            else
                return "";
    
            Assembly assembly = Assembly.Load(projectName);
            return assembly.GetName().Version.ToString();
        }
    

    【讨论】:

      【解决方案10】:

      如果您正在从 Web 控件中查找此内容,则一种技巧是查找代码隐藏 Page 的类型(即从 System.Web.UI.Page 继承的类)。这通常在消费者的 Web 程序集中。

      Type current, last;
      current = Page.GetType();
      do
      {
          last = current;
          current = current.BaseType;
      } while (current != null && current != typeof(System.Web.UI.Page));
      return last;
      

      希望有更好的办法。

      【讨论】:

        【解决方案11】:

        问题说明没有参考(实例)它(最初)没有说不知道网络应用程序类型。

        编辑 OP 澄清说是的,他们确实不需要了解调用 Web 程序集中的类型,因此答案是适当的。但是我会认真考虑重构这样的解决方案,以便将版本传递到其他程序集中。

        如果您知道自定义 HttpApplication 类型,那么对于这种情况下的大多数人:

         typeof(MyHttpApplication).Assembly.GetName().Version
        

        如果你只有动态生成的类型:

         typeof(DynamiclyGeneratedTypeFromWebApp).BaseType.Assembly.GetName().Version
        

        不要再投票给我这个答案了 :)

        【讨论】:

        • 您在该代码中有硬编码类型,因此您需要参考。解决方案应该是可以放入 NuGet 包并安装到任何 Web 应用程序中的东西(因此,您不能使用硬编码的“MyHttpApplication”)。我的目的是创建一个可重复使用的启动屏幕,显示应用程序版本和标题(来自 AssemblyTitleAttribute)。
        • 正如我在回答中所说的,问题是“没有参考”。类型名称不是参考,因此对于很多人(并且正如问题所表达的那样)这是最简单的解决方案。它没有提到安装在任何 Web 应用程序或 NuGet 包中。
        • 我认为问题要求“无参考”的原因是因为代码必须存在于一个单独的库中,该库必须不知道将在其中使用的 Web 应用程序的编译时知识(今天“ MyHttpApplication”,明天是“AnotherHttpApplication”)。如果您将代码直接复制并粘贴到 Web 应用程序中(并对类型进行硬编码),那么您当然可以访问这些类型并且不需要引用。
        【解决方案12】:

        所以,我必须从引用的 dll 中获取程序集。

        在 asp.NET MVC/WebAPI 世界中,总会有至少一个类继承自 System.Web.HttpWebApplication。下面的实现会搜索该类。

        using System;
        using System.Linq;
        
        static Assembly GetWebAssembly() => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetExportedTypes().Any(t => t.BaseType?.FullName == "System.Web.HttpApplication"));
        

        上面使用System.Linq 来找到那个关系,但这也可以不用实现。

        首先,我们获取所有加载的程序集

        AppDomain.CurrentDomain.GetAssemblies()
        

        然后,通过IEnumerable&lt;Assembly&gt;枚举,得到所有直接位于程序集中的类型。

        a.GetExportedTypes()
        

        然后,看看有没有继承自System.Web.HttpWebApplication的类型

        t.BaseType?.FullName == "System.Web.HttpApplication"
        

        在我的实现中,我确保此代码只会被调用一次,但如果不能保证,我会将其高度包装在 Lazy&lt;T&gt; 或其他缓存的延迟加载实现中,因为继续执行该代码相当昂贵盲目搜索。

        using System;
        using System.Linq;
        
        // original method
        private static Assembly GetWebAssembly() => AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetExportedTypes().Any(t => t.BaseType?.FullName == "System.Web.HttpApplication"));
        
        // lazy load implementation
        private static Lazy<Assembly> _webAssembly = new Lazy<Assembly>(GetWebAssembly);
        public static Assembly WebAssembly { get => _webAssembly.Value; }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-02-22
          • 1970-01-01
          • 1970-01-01
          • 2011-02-02
          • 2010-09-21
          • 2010-10-14
          • 2013-01-13
          相关资源
          最近更新 更多