65.9K
CodeProject 正在变化。 阅读更多。
Home

扩展 ASP.NET 2.0 第一部分:创建自定义生成提供程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.37/5 (16投票s)

2005年11月7日

2分钟阅读

viewsIcon

53746

downloadIcon

404

通过为自定义项目资源创建自定义生成提供程序来扩展 ASP.NET 运行时。

Sample Image - main.jpg

引言

ASP.NET 是一个出色的托管环境,支持对其注册资源的动态编译。本文的目的是展示如何通过使用自定义生成提供程序来利用动态编译。

BuildProvider 类

System.Web.Compilation.BuildProvider 抽象类提供了一组方法和属性,允许 ASP.NET 生成源代码。要使用此类,必须实现它,并在 web.config(或 Web 服务器的 machine.config)下的 system.web/compilation/buildProviders 部分下添加一个元素。

此列表概述了 ASP.NET 构建环境如何使用您的 BuildProvider 实例

  • 构建环境会查找 web.config 中注册的生成提供程序。
  • 当环境遇到 App_Code 特殊文件夹中与配置条目的 extension 属性匹配的文件扩展名时,将创建您的提供程序的实例。
  • 一个 AssemblyBuilder 对象被传递到构建器的 GenerateCode 方法中。
  • 您的提供程序使用 AssemblyBuilder 和其他 System.Web.Compilation 类,将文件的源代码添加到整个程序集中。

要了解有关 BuildProvider 类的更多信息,请参见参考部分。

一个 ZipCode BuildProvider

本文使用一个简单的生成提供程序,该提供程序解析包含邮政编码信息的文件。 该提供程序为文件中的每一行创建一个状态类,并将邮政编码公开为属性。 自定义文件和生成的类如下所示

All.zipcode 文件的内容

Iowa|IA|50311;51442;50111;50021;50023
Nebraska|NE|12345;67890
Texas|TX|99999;12345

生成的 state 类

A custom zip class

如前所述,必须在 web.config 中注册提供程序,运行时才能连接您的提供程序。ZipCodeBuildProvider 的条目如下所示

<buildProviders>
    <add appliesTo="Code" 
        extension=".zipCode" 
        type="Lozanotek.Examples.ZipCodeBuildProvider, BuildProvider"/>
</buildProviders>

为了生成将被编译到程序集中的源代码,您必须使用 System.Web.Compilation 命名空间下的类来创建一个抽象语法树 (AST),并通过 AssemblyBuilder 类将其提供给运行时。 CreateClassCreateFieldCreateProperty 方法用于通过解析文件中的一行并创建其相应的编译单元来创建自定义状态类。

/// <summary>

/// Creates a class by parsing the given line

/// </summary>

/// <param name="line">Line to parse</param>

/// <returns>A class declaration for a custom state class</returns>

private CodeTypeDeclaration CreateClass(string line)
{
    // Parse out the tokens

    string[] values = line.Split(new string[1] { "|" },          
                            StringSplitOptions.RemoveEmptyEntries);

    // Set the name of the class

    string className = values[0];
    CodeTypeDeclaration cls = new CodeTypeDeclaration(className);

    // Set an internal field and its value

    string fieldName = values[1];
    CodeMemberField abbrField = CreateField(fieldName);
    cls.Members.Add(abbrField);

    // Get the zip codes listed for the states

    string[] zipCodes = values[2].Split(new string[1] { ";" }, 
                               StringSplitOptions.RemoveEmptyEntries);

    // Create a property for each of the zip codes found

    foreach (string zipCode in zipCodes)
    {
        string tempZip = zipCode.Trim();
        CodeMemberField zipField = CreateField(tempZip);
        CodeMemberProperty zipProperty = CreateProperty(tempZip);

        cls.Members.Add(zipField);
        cls.Members.Add(zipProperty);
     }

     return cls;
}

/// <summary>

/// Creates a private string field to store the value for the zip code

/// </summary>

/// <param name="fieldName">Name of the fild to create</param>

/// <returns>A unit representing an private string field</returns>

private CodeMemberField CreateField(string fieldName)
{
    // Specify that you want to create a string field with the given name

    CodeMemberField field = new CodeMemberField(typeof(String), 
                                  string.Format("_{0}", fieldName));

    // Make the field private and static

    field.Attributes = MemberAttributes.Private | MemberAttributes.Static;

    // Assign the value of the field to the zip code

    field.InitExpression = 
      new CodeSnippetExpression(string.Format("\"{0}\"", fieldName));

    return field;
}

/// <summary>

/// Creates a property that returns the value of a string field

/// </summary>

/// <param name="propertyName">Name of the property to create</param>

/// <returns>A unit representing a public static property</returns>

private CodeMemberProperty CreateProperty(string propertyName)
{
    CodeMemberProperty prop = new CodeMemberProperty();
    prop.Name = string.Format("zip{0}", propertyName);
    prop.Type = new CodeTypeReference(typeof(String));

    prop.Attributes = MemberAttributes.Public | MemberAttributes.Static;

    // Build the body of the property by assigning it a get statement

    prop.GetStatements.Add(new CodeMethodReturnStatement(
                    new CodeFieldReferenceExpression(null,
                    string.Format("_{0}", propertyName))));

    return prop;
}

结论

我希望本文向您展示了开发人员如何利用 ASP.NET 运行时的可扩展性。 在我的下一篇扩展 ASP.NET 2.0 的文章中,我将演示如何通过创建自定义表达式生成器来进一步扩展 ASP.NET。

请随时使用下面的论坛对本文提出任何意见或建议。

参考文献

在撰写本文期间,我使用了以下资源

© . All rights reserved.