asp.netwebformsweb-configexpressionbuilder

Registering a Custom ASP.NET ExpressionBuilder Programmatically


Is it possible to register a custom ExpressionBuilder class programmatically during application startup?

The equivalent web.config declaration is obviously:

  <system.web>
    <compilation>
      <expressionBuilders>
        <add expressionPrefix="MyPrefix" type="MyNamespace.MyExpressionBuilder">
      </expressionBuilders>
    </compilation>
  </system.web>

How would I register this dynamically either during a custom HTTP module Init(), application startup, or BeginRequest, without modifying the web.config?


Solution

  • I found the ExpressionBuilderCollection Class

    Which included the following example

    class UsingExpressionBuildCollection {
        static void Main(string[] args)
        {
          try
          {
            // Set the path of the config file.
            string configPath = "";
    
            // Get the Web application configuration object.
            Configuration config =
              WebConfigurationManager.OpenWebConfiguration(configPath);
    
            // Get the section related object.
            CompilationSection configSection =
              (CompilationSection)config.GetSection("system.web/compilation");
    
            // Display title and info.
            Console.WriteLine("ASP.NET Configuration Info");
            Console.WriteLine();
    
            // Display Config details.
            Console.WriteLine("File Path: {0}",
              config.FilePath);
            Console.WriteLine("Section Path: {0}",
              configSection.SectionInformation.Name);
    
            // Create a new ExpressionBuilder reference.
            ExpressionBuilder myExpressionBuilder =
              new ExpressionBuilder("myCustomExpression", "MyCustomExpressionBuilder");
            // Add an ExpressionBuilder to the configuration.
            configSection.ExpressionBuilders.Add(myExpressionBuilder);
    
            // Add an ExpressionBuilder to the configuration.
            ExpressionBuilder myExpressionBuilder2 =
              new ExpressionBuilder("myCustomExpression2", "MyCustomExpressionBuilder2");
            configSection.ExpressionBuilders.Add(myExpressionBuilder2);
    
            // Display the ExpressionBuilder count.
            Console.WriteLine("ExpressionBuilder Count: {0}",
              configSection.ExpressionBuilders.Count);
    
            // Display the ExpressionBuildersCollection details.
            int i = 1;
            int j = 1;
            foreach (ExpressionBuilder expressionBuilder in configSection.ExpressionBuilders)
            {
              Console.WriteLine();
              Console.WriteLine("ExpressionBuilder {0} Details:", i);
              Console.WriteLine("Type: {0}", expressionBuilder.ElementInformation.Type);
              Console.WriteLine("Source: {0}", expressionBuilder.ElementInformation.Source);
              Console.WriteLine("LineNumber: {0}", expressionBuilder.ElementInformation.LineNumber);
              Console.WriteLine("Properties Count: {0}", expressionBuilder.ElementInformation.Properties.Count);
              j = 1;
              foreach (PropertyInformation propertyItem in expressionBuilder.ElementInformation.Properties)
              {
                Console.WriteLine("Property {0} Name: {1}", j, propertyItem.Name);
                Console.WriteLine("Property {0} Value: {1}", j, propertyItem.Value);
                ++j;
              }
              ++i;
            }
    
            // Remove an ExpressionBuilder.
            configSection.ExpressionBuilders.RemoveAt
              (configSection.ExpressionBuilders.Count-1);
    
            // Remove an ExpressionBuilder.
            configSection.ExpressionBuilders.Remove("myCustomExpression");
    
            // Update if not locked.
            if (!configSection.SectionInformation.IsLocked)
            {
              config.Save();
              Console.WriteLine("** Configuration updated.");
            }
            else
            {
              Console.WriteLine("** Could not update, section is locked.");
            }
          }
    
          catch (Exception e)
          {
            // Unknown error.
            Console.WriteLine(e.ToString());
          }
    
          // Display and wait.
          Console.ReadLine();
        }
      }
    }
    

    The important part being

    Configuration config =
          WebConfigurationManager.OpenWebConfiguration(configPath);
    
    // Get the section related object.
    CompilationSection configSection =
      (CompilationSection)config.GetSection("system.web/compilation");
    
    //...
    
    // Create a new ExpressionBuilder reference.
    var myExpressionBuilder = new ExpressionBuilder(
        expressionPrefix: "MyPrefix", 
        theType: "MyNamespace.MyExpressionBuilder"
    );
    // Add an ExpressionBuilder to the configuration.
    configSection.ExpressionBuilders.Add(myExpressionBuilder);
    
    //...
    
    // Update if not locked.
    if (!configSection.SectionInformation.IsLocked) {
      config.Save();
    }
    

    The above would be equivalent to this configuration sample.

      <system.web>
        <compilation>
          <expressionBuilders>
            <add expressionPrefix="MyPrefix" type="MyNamespace.MyExpressionBuilder">
          </expressionBuilders>
        </compilation>
      </system.web>
    

    This opens up the ability to search first for your custom builder and add it if necessary, check versions...etc.

    Update addressing concerns about modifying config file

    After reviewing the .net reference source it looks like the page parser loads the expression builders directly from config via the internal ExpressionBuilder.GetExpressionBuilder.

    I have not been able to find any other extensibility points other than what has been shown so far when one would be able to inject custom builders programmaticaly.

    Also given the closed source nature of System.Web I doubt there will be one any time in the future.