📜 ⬆️ ⬇️

Using Compile Providers in Asp.net

As an introduction



In Asp.net, any webpage is presented in the form of two files: * .aspx and * .aspx.cs. The * .aspx files contain the html-like markup of the page itself, and the * .aspx.cs files contain C # code, which is represented as a separate class.

You can add server controls to the page layout, for example, with the <asp: Button ID = "MyButton" runat = "server" /> tag.
')
And with each such declaration a variable will be associated, that is, in our case, we will get access to a variable of type Button and the name MyButton, although at first glance this variable is not declared anywhere. (Although in the first version of Asp.net, variable declarations were inserted into the same file.)

In fact, it is not. The class described in the * .aspx.cs file is partial (it is marked with the partial modifier), one part of it is described in the * .aspx.cs file, and the second is in a temporary file that is generated based on viewing the * .aspx file . The compilation provider deals with the generation of this temporary file.

Writing compilation provider



1. Decide what the compilation provider will do.

In order not to be too wise, let it perform the conversion of the xml file of the form:

  1. < classes >
  2. < class name = "C1" >
  3. < property type = "int" name = "x1" value = "17" />
  4. < property type = "string" name = "x2" value = "Hello, World!" />
  5. </ class >
  6. < class name = "C2" >
  7. < property type = "int" name = "x1" value = "- 5" />
  8. < property type = "string" name = "x2" value = "This is a string!" />
  9. </ class >
  10. </ classes >
* This source code was highlighted with Source Code Highlighter .


to a static class containing constants.

2. Create a new project. As the project type, select “Class Library”, call it “MyLib”.

3. All compilation providers are derived from the “System.Web.Compilation.BuildProvider” class, so we will add a link to the “System.Web” assembly and the namespaces used.

The class constructor does not do anything, but we need to override the “GenerateCode” method. The result should be the following:

  1. using System;
  2. using System.Web.Compilation;
  3. using System.Xml;
  4. using System.IO;
  5. using System.Web.Hosting;
  6. namespace mylib
  7. {
  8. public class MyBP: BuildProvider
  9. {
  10. public MyBP () {}
  11. public override void GenerateCode (AssemblyBuilder assemblyBuilder)
  12. {
  13. // In the writer variable we will write the generated code
  14. using (TextWriter writer = assemblyBuilder.CreateCodeFile ( this ))
  15. {
  16. // Create an xml document using the path to the file being analyzed
  17. XmlDocument xml = new XmlDocument ();
  18. xml.Load (VirtualPathProvider.OpenFile ( base .VirtualPath));
  19. // Get all the classes
  20. XmlNodeList classes = xml.GetElementsByTagName ( "class" );
  21. foreach ( XmlNode _class in classes)
  22. {
  23. // Get the class name
  24. string cName = _class.Attributes [ "name" ] .Value;
  25. if (cName == null || cName.Length == 0) continue ;
  26. // Get the class fields
  27. string cProperties = "" ;
  28. // Get all the fields
  29. XmlNodeList properties = _class.ChildNodes;
  30. foreach ( XmlNode property in properties)
  31. {
  32. if (property.Name! = "property" ) continue ;
  33. // Get the field type
  34. string pType = property.Attributes [ "type" ] .Value;
  35. if (pType == null || pType.Length == 0) continue ;
  36. // Get the field name
  37. string pName = property.Attributes [ "name" ] .Value;
  38. if (pName == null || pName.Length == 0) continue ;
  39. // Get the field value
  40. string pValue = property.Attributes [ "value" ] .Value;
  41. if (pValue == null || pValue.Length == 0) continue ;
  42. // If the field has a string type, put it in quotes
  43. if (pType == "string" ) pValue = string .Format ( "\" {0} \ "" , pValue);
  44. // Add a field
  45. cProperties + = string .Format ( "public const {0} {1} = {2};" , pType, pName, pValue);
  46. }
  47. // Add a class
  48. writer.Write ( "public static partial class" + cName + "{" + cProperties + "}" );
  49. }
  50. }
  51. }
  52. }
  53. }
* This source code was highlighted with Source Code Highlighter .


Compile and get the build.

4. Create a new site (let's call it “MySite”). The first thing to do is create the bin and App_Code folders. Copy the newly created library into the bin folder. Now you need to connect the compilation provider. To do this, go to the Web.config file and add a block in the “compilation” section:

  1. < buildProviders >
  2. < add type = "MyLib.MyBP, MyLib" extension = ". cc" />
  3. </ buildProviders >
* This source code was highlighted with Source Code Highlighter .


This definition says that the files with the extension “cc” will be used by the compilation provider MyLib.MyBP, which will be taken from the MyLib assembly. "

5. Create a file "my.cc" in the folder "App_Code" with xml-code, like the one above. After some time (usually ten seconds when the file is processed) in any C # code you can use the classes "C1" and "C2" and their constant fields. (The results can be seen in the screenshots)

6. Screenshots:

Document processed by the compilation provider:


The classes "C1" and "C2" appeared:


And their fields:


Well, as an ending



Certainly, this example cannot claim to be a full-fledged compilation provider, but only shows the general idea, in the code I omitted many checks, and exception handling sacrificed optimality for the sake of code reduction.

PS: I did not find a way not to put the provider in a separate assembly, but simply add the class to the App_Code folder. In this case, an error occurs about the inability to load the type.

I hope that there will be people who know the solution to this problem.
Literature: Dino Esposito “Asp.net 2.0 Advanced Study.”

Many thanks to the zabr user for advice and assistance, as well as to everyone who helped publish this topic.

Source: https://habr.com/ru/post/40047/


All Articles