可以创建自定义 ASP.NET(不是 MVC)指令吗?

Create a custom ASP.NET (not MVC) directive possible?

我正在为我在工作中开发的一些网站开发一个有点高级的自定义框架,我正在为它实现一个小的插件系统。我想以某种方式在 ASPX 文件中注册插件,这样我就可以在我的 Page_Init 函数中按顺序调用它们之后连接到不同的页面事件(加载、预渲染等)。我将直接跳到代码,这样您就可以看到我想要做什么:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Plugin TypeName="MyFramework.Plugin.Core" Arg1="arg1" Arg2="arg2" %>
<%@ Plugin TypeName="MyFramework.Plugin.MainMenu" Arg1="arg1" Arg2="arg2" %>
<%@ Plugin TypeName="MyFramework.Plugin.IE6Hacks" Arg1="arg1" Arg2="arg2" %>
<%@ Plugin TypeName="MyFramework.Plugin.Footer2015" Arg1="arg1" Arg2="arg2" %>
<%@ Plugin TypeName="MyFramework.Plugin.SortableGridViews" Arg1="arg1" Arg2="arg2" %>

<!DOCTYPE html>
<html>
<head runat="server">
    <title>blah</title>
</head>
<body>      
    <form id="form1" runat="server"> Blah... </form>
</body>
</html>

看到那些 <% Plugin %> 指令了吗?它们在 ASP.NET 中不存在,但我想创建它们。我在 google 上找不到任何关于此内容的信息。是否可以创建一个自定义的?

我的想法是,一旦他们 "registered" 使用这些指令,我就可以遍历所有这些指令(每次指令被命中时存储在一个数组中,或者在 Page_Init 事件中) 并采取相应行动。

我的另一个想法是改用代码块:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<% RegisterPlugin("MyFramework.Plugin.Core"); %>
<% RegisterPlugin("MyFramework.Plugin.MainMenu"); %>
<% RegisterPlugin("MyFramework.Plugin.IE6Hacks"); %>
<% RegisterPlugin("MyFramework.Plugin.Footer2015"); %>
<% RegisterPlugin("MyFramework.Plugin.SortableGridViews"); %>

<!DOCTYPE html>
<html>
<head runat="server">
    <title>blah</title>
</head>
<body>      
    <form id="form1" runat="server"> Blah... </form>
</body>
</html>

但是函数在之后所有页面事件被调用而不是在它们之前(或至少在Page_Load之前)运行,这让我毫无办法检测我是否注册了插件以便在我的基本页面的 Page_Load 事件等中采取相应的行动。

非常感谢任何想法:)。提前致谢!

ASP.NET 页面解析器不支持自定义指令(尽管它支持 Page 或 MasterPage 指令上的自定义属性)。 但是您仍然可以使用服务器控件做您想做的事。

假设您有一个基础插件 class,如下所示:

// we derive from control, so all plugins are automatically
// added to the Page.Controls collection
public class MyPluginBase : Control
{
}

例如,两个插件 class 是这样的:

public class MyPlugin : MyPluginBase
{
    public string MyFirstProperty { get; set; }
    public int MySecondProperty { get; set; }
}

public class MyOtherPlugin : MyPluginBase
{
    public string MyFirstProperty { get; set; }
    public int MySecondProperty { get; set; }
}

然后你可以像这样写一个 ASPX 网络表单(或 ASCX):

<%@ Page ... standard attributes ... %>

<plugins:MyPlugin runat="server" MyFirstProperty="blah" MySecondProperty="1"></plugins:MyPlugin>
<plugins:MyOtherPlugin runat="server" MyFirstProperty="blahblah" MySecondProperty="2"></plugins:MyOtherPlugin>

etc...

请注意,要使其正常工作,您必须在某处声明插件前缀,例如在 web.config 中,如下所示:

<configuration>
  <system.web>
    <pages>
      <controls>
        <!-- all assemblies & namespaces that contain plugins classes -->
        <add assembly="WebApplication1" namespace="WebApplication1.Code" tagPrefix="plugins" />
        <add assembly="MyOtherPlugins" namespace="MyOtherPlugins.Plugins" tagPrefix="plugins" />
      </controls>
    </pages>
  </system.web>
</configuration>

在 class 后面的代码中,您将可以自动访问插件,在包括 Init 在内的所有事件中,代码如下:

public partial class WebForm1 : Page
{
    protected void Page_Init(object sender, EventArgs e)
    {
        // get all plugins on the page
        var plugins = Controls.OfType<MyPluginBase>();
    }
}

使用像Autofac that has support for WebForms这样的依赖注入容器。

您可能会对使用 Enumeration or Metadata Integerrogation 关系类型来完成您的插件感兴趣 registration/resolution。

您可能还会发现将 MEF 与 WebForms 结合使用的一些吸引力。 WebForms and MEF Sample