XinL

导航

Asp.net 编译原理 之二: 提供程序

      从asp.net 1.0中,如果用户定义了一个新的组件(cs文件),需要预编译组件后application才可以使用。在Asp.net 2.0开始改变了这种使用方式。asp.net 2.0将website的结构进行重组,新添了一些默认的文件夹,这些文件夹用于不同的场合。可以通过“Add Asp.net Folder”添加可用的特殊文件夹。

      其中有个App_Code的文件夹,IDE可以自动编译此文件夹内的文件,即:当用户往此文件夹添加或拖入一个新文件时,IDE会自动编译,Application的其它地方可以直接使用编译后的类,并享受VS的IntellSense功能。.net的这个特性是由BuildProvider支持的。BuildProvider提供程序是一个可以插入ASP.NET编译系统,为某些文件类型提供自定义编译支持的组件。通过在编译时解析源文件内容,build提供程序可以自动生成一个合适的源代码代理类。build提供程序生成可编译的代码,并使它与源文件保持同步。当源文件发生变化时,build提供程序再次执行,并更新一切。

      内置的提供程序

      在Asp.net系统级web.config文件中定义了系统的内置提供程序。

            <buildProviders>
                
<add extension=".aspx" type="System.Web.Compilation.PageBuildProvider"/>
                
<add extension=".ascx" type="System.Web.Compilation.UserControlBuildProvider"/>
                
<add extension=".master" type="System.Web.Compilation.MasterPageBuildProvider"/>
                
<add extension=".asmx" type="System.Web.Compilation.WebServiceBuildProvider"/>
                
<add extension=".ashx" type="System.Web.Compilation.WebHandlerBuildProvider"/>
                
<add extension=".soap" type="System.Web.Compilation.WebServiceBuildProvider"/>
                
<add extension=".resx" type="System.Web.Compilation.ResXBuildProvider"/>
                
<add extension=".resources" type="System.Web.Compilation.ResourcesBuildProvider"/>
                
<add extension=".wsdl" type="System.Web.Compilation.WsdlBuildProvider"/>
                
<add extension=".xsd" type="System.Web.Compilation.XsdBuildProvider"/>
                
<add extension=".js" type="System.Web.Compilation.ForceCopyBuildProvider"/>
                
<add extension=".lic" type="System.Web.Compilation.IgnoreFileBuildProvider"/>
                
<add extension=".licx" type="System.Web.Compilation.IgnoreFileBuildProvider"/>
                
<add extension=".exclude" type="System.Web.Compilation.IgnoreFileBuildProvider"/>
                
<add extension=".refresh" type="System.Web.Compilation.IgnoreFileBuildProvider"/>
                
<add extension=".xoml" type="System.ServiceModel.Activation.WorkflowServiceBuildProvider, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
                
<add extension=".svc" type="System.ServiceModel.Activation.ServiceBuildProvider, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
            
</buildProviders>

 

      这些提供程序只是实现了System.Web.Compilation.BuildPrivder抽象类的类。BuildProvider包含一个重要的函数:

public virtual void GenerateCode(AssemblyBuilder assemblyBuilder)
{
}

      这个函数用于生成虚拟目录下特定文件类型的源代码,并把生成的源代码添加到指定的程序集生成器(AssemblyBuilder)中。方法内需要使用System.CodeDom命名空间下的类来构建源代码。该命名空间包含可用于生成源代码文档的元素和结构的类,可用来建立源代码文档结构的模型。

      定制BuildProvider

      分三步完成定制过程:
            1  定义要编译的文件结构
            2  BuildProvider根据文件结构生成源代码类
            3  使用定制的BuildProvider

      1  定义文件结构

      假设要根据定制.car文件中的设置动态构建一个Car类,以便使该类能够在项目中被多次利用。定做一.car文件类型的结构如下:
      <?xml version="1.0" encoding="utf-8" ?>
      <car name="">
            <color/>
            <door/>
            <speed/>
      </car>

      BuildProvider将根据xml文件的信息创建一个类文件。

      2  定制BuildProvider

using System;
using System.IO;
using System.Web.Compilation;
using System.Xml;
using System.CodeDom;

namespace MyBuildProvider
{
    
public class CarBuildProvider : BuildProvider
    
{
        
public CarBuildProvider ()
        
{
        }


        
public override void GenerateCode(AssemblyBuilder assemblyBuilder)
        
{
            XmlDocument carXmlDoc 
= new XmlDocument();

            
using (Stream passedFile = this.OpenStream())
            
{
                carXmlDoc.Load(passedFile);
            }


            XmlNode mainNode 
= carXmlDoc.SelectSingleNode("/car");
            
string selectionMainNode = mainNode.Attributes["name"].Value;

            XmlNode colorNode 
= carXmlDoc.SelectSingleNode("/car/color");
            
string selectionColorNode = colorNode.InnerText;

            XmlNode doorNode 
= carXmlDoc.SelectSingleNode("/car/door");
            
string selectionDoorNode = doorNode.InnerText;

            XmlNode speedNode 
= carXmlDoc.SelectSingleNode("/car/speed");
            
string selectionSpeedNode = speedNode.InnerText;

            CodeCompileUnit ccu 
= new CodeCompileUnit();
            CodeNamespace cn 
= new CodeNamespace();
            CodeMemberProperty cmp1 
= new CodeMemberProperty();
            CodeMemberProperty cmp2 
= new CodeMemberProperty();
            CodeMemberMethod cmm1 
= new CodeMemberMethod();

            cn.Imports.Add(
new CodeNamespaceImport("System"));

            cmp1.Name 
= "Color";
            cmp1.Type 
= new CodeTypeReference(typeof(string));
            cmp1.Attributes 
= MemberAttributes.Public;
            cmp1.GetStatements.Add(
new CodeSnippetExpression("return \"" + selectionColorNode + "\""));

            cmp2.Name 
= "Door";
            cmp2.Type 
= new CodeTypeReference(typeof(int));
            cmp2.Attributes 
= MemberAttributes.Public;
            cmp2.GetStatements.Add(
new CodeSnippetExpression("return " + selectionDoorNode));

            cmm1.Name 
= "Go";
            cmm1.ReturnType 
= new CodeTypeReference(typeof(int));
            cmm1.Attributes 
= MemberAttributes.Public;
            cmm1.Statements.Add(
new CodeSnippetExpression("return " + selectionSpeedNode));

            CodeTypeDeclaration ctd 
= new CodeTypeDeclaration(selectionMainNode);
            ctd.Members.Add(cmp1);
            ctd.Members.Add(cmp2);
            ctd.Members.Add(cmm1);

            cn.Types.Add(ctd);
            ccu.Namespaces.Add(cn);

            assemblyBuilder.AddCodeCompileUnit(
this, ccu);
        }

    }

}

      CarBuildProvider读取文件的元素及属性,利用System.CodeDom命名空间下的类创建源代码类。

      要使定制的BuildProvider起作用,就需要在web.config配置段中注册:

    <system.web>    
       
<compilation debug="true">
           
<buildProviders>
               
<add extension=".car" type="MyBuildProvider.Car"/>
        
    </buildProviders>
       
</compilation>
    
</system.web>

 

      3  使用定制的BuildProvider

      定义一个.car示例文件如下:
      <?xml version="1.0" encoding="utf-8" ?>
      <car name="EvjenCar">
            <color>Red</color>
            <door>4</door>
            <speed>150</speed>
      </car> 

      将car示例文件添加到App_Code文件夹下,IDE会自动调用MyBuildProvider为文件生成源代码类。示例文件生成的类代码如下:

using System;

public class EvjenCar {
    
    
public virtual string Color {
        
get {
            
return "Red";
        }

    }

    
    
public virtual int Door {
        
get {
            
return 4;
        }

    }

    
    
public virtual int Go() {
        
return 150;
    }

}

      在Application的其它地方就可以访问这个类,并使用VS的智能提示。
      

 

posted on 2009-06-26 16:02  XinL  阅读(343)  评论(0编辑  收藏  举报