// ПРИМЕР
string sourcePage = "";
using (StreamReader sr = new StreamReader(AppDomain.CurrentDomain.BaseDirectory + @"Default.tmpx", Encoding.Default, true, 0x1000))
sourcePage = sr.ReadToEnd();
AspNetGenerator gen = new AspNetGenerator();
CodeCompileUnit ccu = null;
try
{
ccu = gen.CreateCode(sourcePage, @"Default");
}
catch (AspNetGeneratorHostException exc)
{
....
}
ICodeGenerator ics = (new CSharpCodeProvider()).CreateGenerator();
StringWriter sw = new StringWriter();
IndentedTextWriter itw = new IndentedTextWriter(sw);
CodeGeneratorOptions cgo = new CodeGeneratorOptions();
cgo.BlankLinesBetweenMembers = true;
ics.GenerateCodeFromCompileUnit(ccu, itw, cgo);
textBox1.Text = sw.ToString();
// AspNetGenerator CLASS
using System;
using System.CodeDom;
using System.IO;
using System.Reflection;
using System.Web;
using System.Web.Hosting;
namespace XXX.AspNetGenerator
{
public class AspNetGenerator
{
private const string APP_NAME = @"XXX ASP.NET Generator";
private const string DOMAIN_NAME = APP_NAME + @" domain";
private const string TEMP_DIRECTORY = APP_NAME;
internal const string FAKE_ASPX_FILE = @"fake.aspx";
public AspNetGenerator()
{}
public CodeCompileUnit CreateCode(string templateText, string pragmaFileName)
{
return GeneratorHost().CreateCode(templateText, pragmaFileName);
}
private AspNetGeneratorHost GeneratorHost()
{
string appPath = AppDomain.CurrentDomain.BaseDirectory;
CreateFakeAspxFile(appPath);
AppDomainSetup setup = new AppDomainSetup();
setup.PrivateBinPath = "";
setup.PrivateBinPathProbe = "*";
setup.ShadowCopyFiles = "true";
setup.ApplicationBase = (new Uri(appPath, true)).ToString();
setup.ApplicationName = APP_NAME;
Assembly entryAssembly = Assembly.GetEntryAssembly();
setup.DisallowCodeDownload = true;
AppDomain dom = AppDomain.CreateDomain(DOMAIN_NAME, null, setup);
dom.SetData(".appPath", appPath);
dom.SetData(".appDomain", "*");
dom.SetData(".appVPath", "/");
dom.SetData(".domainId", dom.FriendlyName);
dom.SetData(".hostingVirtualPath", "/");
dom.SetData(".hostingInstallDir", HttpRuntime.AspInstallDirectory);
MethodInfo mi = typeof(ApplicationHost).GetMethod("InitConfigInNewAppDomain", BindingFlags.Static | BindingFlags.NonPublic);
mi.Invoke(null, BindingFlags.Static | BindingFlags.NonPublic, null, new object[]{dom}, null);
return (AspNetGeneratorHost)dom.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(AspNetGeneratorHost).FullName);
}
private FileInfo CreateFakeAspxFile(string appPath)
{
if (null == _fakeAspxFile)
{
_fakeAspxFile = new FileInfo(appPath + AspNetGenerator.FAKE_ASPX_FILE);
if (!_fakeAspxFile.Exists)
{
using (StreamWriter sw = _fakeAspxFile.CreateText())
{
sw.Write(@"");
sw.Flush();
}
}
}
return _fakeAspxFile;
}
private FileInfo _fakeAspxFile;
}
}
// AspNetGeneratorHost CLASS
using System;
using System.IO;
using System.Web;
using System.Web.Hosting;
using System.Web.UI;
using System.Reflection;
using System.CodeDom;
namespace XXX.AspNetGenerator
{
internal class AspNetGeneratorHost: MarshalByRefObject
{
public AspNetGeneratorHost(): base()
{}
internal CodeCompileUnit CreateCode(string templateText, string pragmaFileName)
{
CodeCompileUnit unit = null;
try
{
unit = CreateCompileUnit(Parse(templateText, pragmaFileName));
}
catch (Exception exc)
{
if (null == exc.InnerException) throw new AspNetGeneratorHostException(exc);
throw new AspNetGeneratorHostException(exc, new AspNetGeneratorHostException(exc.InnerException));
}
finally
{
HttpRuntime.UnloadAppDomain();
}
return unit;
}
protected internal PageParser Parse(string templateText, string pragmaFileName)
{
// Формирование "поддельного" http контекста
StringWriter writer = new StringWriter();
HttpWorkerRequest request = new SimpleWorkerRequest(AspNetGenerator.FAKE_ASPX_FILE, null, writer);
HttpContext context = new HttpContext(request);
// Создаем, настраиваем парсер и парсируем
PageParser parser = new PageParser();
SetNotPublicProperty(typeof(BaseParser), "Context", parser, context);
SetNotPublicField(typeof(TemplateParser), "_lineNumber", parser, 1);
SetNotPublicField(typeof(TemplateParser), "_fIgnoreNextSpaceString", parser, true);
SetNotPublicField(typeof(TemplateParser), "_currentPragmaFile", parser, pragmaFileName);
InvokeNotPublicMethod(typeof(TemplateParser), "PrepareParse", parser, new object[]{});
InvokeNotPublicMethod(typeof(TemplateParser), "ParseStringInternal", parser, new object[]{templateText});
return parser;
}
protected internal CodeCompileUnit CreateCompileUnit(PageParser parser)
{
// Создаем компайлер и необходимый для его работы ресур-билдер
object pageCompiler = Activator.CreateInstance(WebCompilation.GetType("System.Web.Compilation.PageCompiler"),
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, new object[]{parser}, null);
object stringResourceBuilder = Activator.CreateInstance(WebCompilation.GetType("System.Web.StringResourceBuilder"),
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, new object[]{}, null);
// Инициализируем компайлер
Type typeBaseCompiler = WebCompilation.GetType("System.Web.Compilation.BaseCompiler");
SetNotPublicField(typeBaseCompiler, "_stringResourceBuilder", pageCompiler, stringResourceBuilder);
// Создаем codeDom
InvokeNotPublicMethod(typeBaseCompiler, "BuildSourceDataTree", pageCompiler, new object[]{});
return (CodeCompileUnit)GetNotPublicField(typeBaseCompiler, "_sourceData", pageCompiler);
}
protected internal Assembly WebCompilation
{
get
{
if (null == _webCompilation)
{
// Ищем среди всех сборок домена сборку System.Web.dll
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach(Assembly a in assemblies)
if (@"System.Web" == a.GetName().Name)
{
_webCompilation = a;
break;
}
if (null == _webCompilation)
throw new AspNetGeneratorHostException("Can't to find the assembly 'System.Web' in current application domain.");
}
return _webCompilation;
}
}
protected internal Assembly _webCompilation;
protected internal void SetNotPublicProperty(Type type, string propertyName, object targetObject, object value)
{
PropertyInfo pi = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic);
pi.SetValue(targetObject, value, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetProperty, null, null, null);
}
protected internal void SetNotPublicField(Type type, string fieldName, object targetObject, object value)
{
FieldInfo fi = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(targetObject, value, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetProperty, null, null);
}
protected internal object GetNotPublicField(Type type, string fieldName, object targetObject)
{
FieldInfo fi = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
return fi.GetValue(targetObject);
}
protected internal void InvokeNotPublicMethod(Type type, string methodName, object targetObject, object[] args)
{
MethodInfo mi = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic);
mi.Invoke(targetObject, BindingFlags.Instance | BindingFlags.NonPublic, null, args, null);
}
}
}
// AspNetGeneratorHostException CLASS
using System;
using System.Runtime.Serialization;
namespace XXX.AspNetGenerator
{
[Serializable]
public class AspNetGeneratorHostException: Exception
{
protected AspNetGeneratorHostException(SerializationInfo info, StreamingContext context): base(info, context)
{
_innerCallStack = info.GetString("_innerCallStack");
_originalExceptionType = info.GetString("_originalExceptionType");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("_innerCallStack", _innerCallStack);
info.AddValue("_originalExceptionType", _originalExceptionType);
}
public AspNetGeneratorHostException(string message): base(message)
{
}
public AspNetGeneratorHostException(Exception localException): this(localException.Message)
{
Init(localException);
}
public AspNetGeneratorHostException(Exception localException, Exception innerException): base(localException.Message, innerException)
{
Init(localException);
}
private void Init(Exception exception)
{
_innerCallStack = exception.StackTrace;
_originalExceptionType = exception.GetType().FullName;
}
public string InnerCallStack
{
get { return _innerCallStack ; }
}
private string _innerCallStack = "";
public string OriginalExceptionType
{
get { return _originalExceptionType ; }
}
private string _originalExceptionType = "" ;
}
}