3

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?

qJake
  • 16,821
  • 17
  • 83
  • 135

1 Answers1

2

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.

Community
  • 1
  • 1
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Correct, however, I am concerned that `config.Save()` will actually attempt to write back to the physical web.config file and update it, as that's not what I want. Does it do that? – qJake Oct 09 '18 at 14:05
  • @qJake yes save can be used to update or create a new config file. – Nkosi Oct 09 '18 at 14:12
  • @qJake after reviewing the .net reference source it looks like the page parser loads the expression builders directly from config via the internal [ExpressionBuilder.GetExpressionBuilder](https://referencesource.microsoft.com/#System.Web/Compilation/ExpressionBuilder.cs,fdb51a80a99385a9,references). I am not finding any other extensibility points other than what has been shown so far when one would be able to inject builders. – Nkosi Oct 09 '18 at 15:22
  • Thanks for the info. We'll have to evaluate if we want to actually update the web.config programmatically or via some other means, but it's good to know how the API works. Thanks! – qJake Oct 15 '18 at 16:55