【问题标题】:Finding Page or Page assembly from current context从当前上下文中查找页面或页面程序集
【发布时间】:2012-02-06 08:50:08
【问题描述】:

我试图在运行时查找页面请求的程序集。我使用了Get current System.Web.UI.Page from HttpContext? 的代码,它适用于大多数呼叫,但存在一个问题。

如果我在我的 aspx.cs 中实例化类顶部的类变量 HttpContext.Current.CurrentHandler 为 null。

示例
我有一个名为 Business.dll 的 DLL,它具有根据上述 SO 问题获取页面类型的功能。

在我的页面中,FrontEnd.dll 中的 default.asp 我有以下调用:

public partial class FrontEnd: Page
{
   private readonly Type _t = Business.GetPageType();

上面的代码返回 HttpContext.Current.CurrentHandler 为 null 并且 HttpContext.Current.ApplicationInstance 返回 HttpApplication 作为类型,因此 System.Web 作为程序集。

如果我这样写:

public partial class FrontEnd: Page
{
   readonly Type _t;

   protected override void OnInit(EventArgs e)
   {
      _t = Business.GetPageType();    

它工作得很好,我得到了对 CurrentHandler 和页面的引用。我当然可以重构所有地方并将变量初始化移动到 OnInit,但这需要应用程序中的约定和更高程度的维护。

使用Assembly.GetEntryAssembly() return null 作为示例,Assembly.GetExecutingAssembly() 返回 Business.dll,所以我也不能使用它们。

是否有其他方法可以找到类型/dll,也许使用请求 URL 来查找它源自的类型/dll?

[更新]
到目前为止,我有这段代码,因为我所有的 dll 都使用已知密钥签名(不包括检查签名密钥的额外方法):

StackTrace stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames();
Assembly firstAssembly = null;
foreach (StackFrame stackFrame in stackFrames)
{
    var method = stackFrame.GetMethod();
    Type t = method.DeclaringType;
    if (t != null && t.Assembly.Is(SignedBy.Me))
    {
        firstAssembly = t.Assembly;
    }
}
if( firstPzlAssembly != null)
{
    return firstPzlAssembly;
}

虽然它有效,但它似乎是错误的,如果经常调用,可能会对性能造成影响。

【问题讨论】:

    标签: c# asp.net .net


    【解决方案1】:

    当你这样做时:

    private readonly Type _t = Business.GetPageType();
    

    它实际上被编译成一个字段初始化在构造函数中。 这意味着对象(您的页面)尚未构建。它还不存在,它正在“诞生”。在这个阶段你只是在构造函数中

    在构建您的对象(页面)之前,ASP.NET 基础结构无法将其分配给 HttpContext.Current.CurrentHandler 静态属性。好吧,因为处理程序(您的页面)还不存在并且正在构造 id。

    所以你不能做你想做的事。

    您可以做的是创建一个 PageBase 类,覆盖 OnInit 方法并在其中添加此代码:

    public abstract class PageBase
    {
         protected Type PageType { get; private set; }
    
         protected override void OnInit(EventArgs e)
         {
            PageType = Business.GetPageType();
         } 
    }
    

    现在只需从这个基类派生您的页面:

    public partial class FrontEnd: PageBase { .... }
    

    (或直接在 ASPX 文件中将 PageBase 指定为基类,无论您做什么。

    【讨论】:

    • 这是有道理的。猜猜我可能不得不选择重新编写代码并使用约定,即不允许在它自己的类中初始化变量,但必须在 OnInit 或类似的过程中这样做。谢谢。
    【解决方案2】:

    一种选择是定义一个基本页面,根据需要设置 OnInit 函数,然后确保所有其他页面都继承自该页面。

    例如:

    public class CustomBasePage: Page
    {
        readonly Type _t;
    
        protected override void OnInit(EventArgs e)
        {
            _t = Business.GetPageType();
        }
    }
    

    然后将所有页面更改为继承自此而不是普通的 Page 类:

    public partial class FrontEnd: CustomBasePage
    

    这意味着您只需定义一次逻辑,并在其余应用程序页面上放置最小的开销。 如果任何页面出于其他原因需要覆盖OnInit,它只需要包含对base.OnInit(); 的调用,这不会太繁琐。

    您需要确保您的 Business.GetPageType(); 返回您期望的结果。我不清楚它到底在做什么,以及它是否会返回 FrontEndCustomBasePage 类,(你的应用程序逻辑也不能接受其中的哪一个)。

    【讨论】:

    • 如果 business.dll 关于正在使用的基类是新的(我有一个),则该方法将起作用。但我也有其他应用程序使用相同的共享 Business.dll 但使用其他页面基类。问题是它们都在同一个实例(SharePoint)中运行,所以我必须弄清楚是哪一个执行了调用。
    猜你喜欢
    • 1970-01-01
    • 2012-03-18
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 2021-09-02
    • 2017-02-01
    • 2013-05-09
    相关资源
    最近更新 更多