|
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.Configuration.Internal;
using System.Xml;
using System.Xml.Serialization;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using Microsoft.VisualBasic;
namespace DirectoryWatcher
{
/// <summary>
/// A snippet of runtime-compiled code that we are to run in response to a filesystem event.
/// </summary>
public class ProgramCode : ConfigurationElement
{
/// <summary>
/// The text of the actual code that we are to compile.
/// </summary>
private string text = null;
/// <summary>
/// Line number in the configuration file for this element (used for possible exception
/// messages).
/// </summary>
private int lineNumber = 0;
/// <summary>
/// Path to the configuration file in which this element resides (used for possible
/// exception messages).
/// </summary>
private string fileName = "";
/// <summary>
/// Assembly that results when we compile the code.
/// </summary>
private Assembly assembly = null;
/// <summary>
/// The language for this code snippet.
/// </summary>
[ConfigurationProperty("language", IsRequired = true)]
public ProgramLanguage Language
{
get
{
return (ProgramLanguage)base["language"];
}
}
/// <summary>
/// Text representing the actual code.
/// </summary>
public string Text
{
get
{
return text;
}
}
/// <summary>
/// Collection of referenced assemblies for this snippet of code.
/// </summary>
[ConfigurationProperty("referencedAssemblies")]
public ReferencedAssemblyCollection ReferencedAssemblies
{
get
{
return (ReferencedAssemblyCollection)base["referencedAssemblies"];
}
}
/// <summary>
/// Assembly representing the compiled results of the code.
/// </summary>
public Assembly Assembly
{
get
{
// If the code has not already been compiled, do so now
if (assembly == null)
{
CodeDomProvider codeProvider = null;
// Get the proper code provider based on the code's language
if (Language == ProgramLanguage.CSharp)
codeProvider = new CSharpCodeProvider();
else if (Language == ProgramLanguage.VisualBasic)
codeProvider = new VBCodeProvider();
CompilerParameters compilerParameters = new CompilerParameters();
// Set the compiler options so that we don't generate an assembly on disk and
// we create a library assembly that does not contain debug information
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
compilerParameters.IncludeDebugInformation = false;
compilerParameters.CompilerOptions = "/target:library /optimize";
compilerParameters.ReferencedAssemblies.Add("System.dll");
compilerParameters.ReferencedAssemblies.Add(AppDomain.CurrentDomain.BaseDirectory + "\\DirectoryWatcher.exe");
// Add any assembly references (besides System.dll and DirectoryWatcher.exe,
// which everyone gets) specified for this code
foreach (ReferencedAssembly referencedAssembly in ReferencedAssemblies)
compilerParameters.ReferencedAssemblies.Add(referencedAssembly.Name);
// Generate the assembly
CompilerResults results = codeProvider.CompileAssemblyFromSource(compilerParameters, text);
// Check the return code and throw an exception if the compilation failed
if (results.NativeCompilerReturnValue != 0)
throw new CompilationException(results.Errors);
assembly = results.CompiledAssembly;
}
return assembly;
}
}
/// <summary>
/// Handler for the case where we encounter an unrecognized element while attempting to
/// deserialize the class from XML; deals with "custom" properties, specifically the Text
/// property, whose value is set in an element node instead of an attribute.
/// </summary>
/// <param name="elementName">
/// Name of the unrecognized element.
/// </param>
/// <param name="reader">
/// Reader object that is involved in the deserialization.
/// </param>
/// <returns>
/// True if we actually recognize the element, false otherwise.
/// </returns>
protected override bool OnDeserializeUnrecognizedElement(string elementName, XmlReader reader)
{
if (elementName == "text")
{
text = reader.ReadString();
reader.Read();
return true;
}
return base.OnDeserializeUnrecognizedElement(elementName, reader);
}
/// <summary>
/// Instantiates the object using data stored in XML; records the filename and line number
/// (for use later in possible exceptions) and then calls the base method.
/// </summary>
/// <param name="reader">
/// Reader object that is involved in the deserialization.
/// </param>
/// <param name="serializeCollectionKey">
/// True to serialize only the collection key properties, false otherwise.
/// </param>
protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey)
{
lineNumber = ((IConfigErrorInfo)reader).LineNumber;
fileName = ((IConfigErrorInfo)reader).Filename;
base.DeserializeElement(reader, serializeCollectionKey);
}
/// <summary>
/// Called after the deserialization process is complete; validates the object's data.
/// </summary>
protected override void PostDeserialize()
{
if (text == null)
throw new ConfigurationErrorsException("\"text\" is a required element.", fileName, lineNumber);
base.PostDeserialize();
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I'm a software architect in the truest sense of the word: I love writing code, designing systems, and solving tough problems in elegant ways. I got into this industry not for the money, but because I honestly can't imagine myself doing anything else. Over my career, I've worked on just about every major Microsoft web technology, running the gamut from SQL Server 7.0 to 2008, from .NET 1.1 to 4.0, and many others. I've made a name for myself and have risen to my current position by being able to visualize and code complex systems, all while keeping the code performant and extensible.
Both inside and outside of work, I love researching new technologies and using them sensibly to solve problems, not simply trying to force the newest square peg into the round hole. From emerging Microsoft projects like AppFabric to third party or open source efforts like MongoDB, nServiceBus, or ZeroMQ, I'm constantly trying to find the next technology that can eliminate single points of failure or help scale my data tier.
Outside of work, I'm a rabid DC sports fan and I love the outdoors, especially when I get a chance to hike or kayak.