DynamicCallMethodExpressionTreeInvokerHelper CodeDom 动态编译代码 执行代码
namespace Test
{
using System;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
using Microshaoft;
public class ContextInfo
{
public string F1;
}
class Program
{
static void Main(string[] args)
{
string codeSnippet1 = @"
Console.WriteLine(x);
Console.WriteLine(y.F1);
//TResult r;
return true;
";
string codeSnippet2 = @"
Console.WriteLine(x);
Console.WriteLine(y.F1);
Console.WriteLine(z);
//TResult r;
//return true;
";
string codeSnippet3 = @"
//Console.WriteLine(x);
//Console.WriteLine(y.F1);
Console.WriteLine(""Action()"");
//TResult r;
//return true;
";
SourceCodeDynamicCompilerInvokers invokers = new SourceCodeDynamicCompilerInvokers();
invokers
.Add
(
new string[] { "System.dll", @"Noname3.exe" }
, new string[] { "System", "System", "Test" }
, "Func<string, ContextInfo, bool>"
, "Call"
, new string[] { "x", "y" }
, codeSnippet1
);
invokers
.Add
(
new string[] { "System.dll", "System.dll", @"Noname3.exe" }
, new string[] { "System", "System.Text", "Test" }
, "Action<int, ContextInfo, bool>"
, "Call2"
, new string[] { "x", "y", "z" }
, codeSnippet2
);
invokers
.Add
(
new string[] { "System.dll", "System.dll", @"Noname3.exe" }
, new string[] { "System", "System.Text", "Test" }
, "Action"
, "Call3"
, null //new string[] { "x", "y", "z" }
, codeSnippet3
);
invokers.Build();
//Func<string, ContextInfo, bool> func = (Func<string, ContextInfo, bool>) cr["Call"];
dynamic func = invokers["Call"];
var r = func("xxxx", new ContextInfo() { F1 = "FF1" });
Console.WriteLine(r);
//Action<int, ContextInfo, bool> action = (Action<int, ContextInfo, bool>) cr["Call2"];
dynamic action = invokers["Call2"];
action(999, new ContextInfo() { F1 = "FFF1" }, false);
//Action action = (Action) cr["Call3"];
dynamic action2 = invokers["Call3"];
action2();
Console.ReadLine();
}
}
}
namespace Microshaoft
{
using System;
using System.CodeDom.Compiler;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using System.Text;
public class SourceCodeDynamicCompilerInvokers
{
private string _codeTemplate = @"
namespace Microshaoft.Temp
{{
{0}
public static partial class InvokersManager
{{
public static
{1} //方法签名定义,如: Func<string, string, bool>
{2} //方法名称
()
{{
var invoker = new {1} //方法签名定义,如: Func<string, string, bool>
(
(
{3} //参数列表
) =>
{{
{4} //代码
}}
);
return invoker;
}}
}}
}}
";
private class CodeTemplatePlaceHolder
{
public string[] ReferencedAssemblies;
public string[] UsingsTargets;
public string MethodDefinitionStatment;
public string MethodName;
public string[] MethodArgs;
public string EmbedInlineCodeSnippet;
public Delegate MethodInvoker;
}
public Delegate this[string key]
{
get
{
return
_sourceCodes[key].MethodInvoker;
}
}
private ConcurrentDictionary<string, CodeTemplatePlaceHolder> _sourceCodes
= new ConcurrentDictionary<string, CodeTemplatePlaceHolder>();
private void Compile
(
string[] referencedAssemblies
, string sourceCode
)
{
CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("CSharp");
var compilerParameters = new CompilerParameters();
Array
.ForEach
(
referencedAssemblies
, (x) =>
{
compilerParameters
.ReferencedAssemblies
.Add(x);
}
);
compilerParameters.GenerateExecutable = false;
compilerParameters.GenerateInMemory = true;
//Console.WriteLine(code);
var compilerResults = codeDomProvider
.CompileAssemblyFromSource
(
compilerParameters
, sourceCode
);
var assembly = compilerResults.CompiledAssembly;
var codes = _sourceCodes.AsEnumerable();
var stringBuilder = new StringBuilder();
foreach (var kvp in codes)
{
MethodInfo mi = assembly
.GetType("Microshaoft.Temp.InvokersManager")
.GetMethod(kvp.Key);
Delegate invoker = (Delegate) mi.Invoke(null, null);
kvp.Value.MethodInvoker = invoker;
}
}
public void Add
(
string[] referencedAssemblies
, string[] usingsTargets
, string methodSignatureDefinition
, string methodName
, string[] methodArgs
, string embedInlineCodeSnippet
)
{
_sourceCodes
.TryAdd
(
methodName
, new CodeTemplatePlaceHolder()
{
ReferencedAssemblies = referencedAssemblies
,
UsingsTargets = usingsTargets
,
MethodDefinitionStatment = methodSignatureDefinition
,
MethodName = methodName
,
MethodArgs = methodArgs
,
EmbedInlineCodeSnippet = embedInlineCodeSnippet
}
);
}
public void Build()
{
string[] referencedAssemblies
= _sourceCodes
.SelectMany
(
(x) =>
{
return
x
.Value
.ReferencedAssemblies;
}
).Distinct()
.ToArray();
var sourceCodes = _sourceCodes.AsEnumerable();
var stringBuilder = new StringBuilder();
foreach (var kvp in sourceCodes)
{
var usingStatement = "using {0};";
var usingsTargets = kvp
.Value
.UsingsTargets
.Distinct();
var usingsStatementsItems
= usingsTargets
.Select
(
(xx) =>
{
var rr = string.Format(usingStatement, xx);
return rr;
}
);
var usingsStatements = string.Join("\r\n", usingsStatementsItems);
var methodArgs = kvp
.Value
.MethodArgs;
var methodArgsStatement = string.Empty;
if
(
methodArgs != null
&&
methodArgs.Length > 0
)
{
methodArgsStatement = string.Join(", ", methodArgs);
}
var sourceCode = string
.Format
(
_codeTemplate
, usingsStatements
, kvp.Value.MethodDefinitionStatment
, kvp.Value.MethodName
, methodArgsStatement
, kvp.Value.EmbedInlineCodeSnippet
);
stringBuilder
.AppendLine(sourceCode);
}
Compile(referencedAssemblies, stringBuilder.ToString());
}
}
}
|
namespace ConsoleApplication
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Mail;
using System.Net.Mime;
using Microshaoft;
public class Class1
{
static void Main(string[] args)
{
Console.WriteLine("生成 eml 文件");
string html = "<html><body><a href=\"http://www.live.com\"><img src=\"cid:attachment1\"></a>";
html += "<script src=\"cid:attachment2\"></script>中国字";
html += "<a href=\"http://www.google.com\"><br><img src=\"cid:attachment1\"></a><script>alert('mail body xss')<script></body></html>";
AlternateView view = AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html);
//LinkedResource picture = new LinkedResource(@"pic.JPG", MediaTypeNames.Image.Jpeg);
//picture.ContentId = "attachment1";
//view.LinkedResources.Add(picture);
//LinkedResource script = new LinkedResource(@"a.js", MediaTypeNames.Text.Plain);
//script.ContentId = "attachment2";
//view.LinkedResources.Add(script);
MailMessage mail = new MailMessage();
mail.AlternateViews.Add(view);
mail.From = new MailAddress("test@microshaoft.com", "<script>alert('mail from xss')</script>");
mail.To.Add(new MailAddress("microshaoft@gmail.com", "<script>alert('mail to xss')</script>"));
mail.To.Add(new MailAddress("microshaoft@qq.com", "<script>alert('mail to xss')</script>"));
mail.Subject = "<script>alert('mail subject xss')</script>" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
byte[] buffer = mail.GetBytes();
File.WriteAllBytes(@"d:\temp.eml", buffer);
Console.WriteLine("====================================================================");
Console.ReadLine();
Console.WriteLine("计算表达式");
string formula = "(({0}-{1})/{2}+{3})*{4}";
string result = JScriptEvaluator.ComputeFormula<double>
(
formula
, 1f
, 2.1
, 3.1
, 4.0
, 5.0
);
Console.WriteLine(result);
double x;
x = DataTableColumnExpression.ComputeFormula<double, double>
(
formula
, 1f
, 2.1
, 3.1
, 4.0
, 5.0
);
Console.WriteLine(x);
//=================================================================================================
formula = "IIF(1=2, F1, F2) + ((--F1) * F2) + F3";
var tuples = new Tuple<string, double>[]
{
Tuple.Create<string,double>("F1", 1.0)
, Tuple.Create<string,double>("F2", 2.0)
, Tuple.Create<string,double>("F3", 3.0)
, Tuple.Create<string,double>("F4", 4.0)
, Tuple.Create<string,double>("F3", 2.0)
};
x = DataTableColumnExpression.ComputeFormula<double, double>(formula, tuples);
Console.WriteLine(x);
Console.ReadLine();
}
}
}
namespace Microshaoft
{
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
public class DataTableColumnExpression
{
private static MethodInfo _mi = typeof(string).GetMethods().First
(
m => m.Name.Equals("Format")
&& m.GetParameters().Length == 2
&& m.IsStatic
&& m.GetParameters()[1].Name == "args"
);
private class ObjectEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> _onEqualsProcessFunc;
private Func<T, int> _onGetHashCodeProcessFunc;
public ObjectEqualityComparer
(
Func<T, T, bool> onEqualsProcessFunc
, Func<T, int> onGetHashCodeProcessFunc
)
{
_onEqualsProcessFunc = onEqualsProcessFunc;
_onGetHashCodeProcessFunc = onGetHashCodeProcessFunc;
}
public bool Equals(T x, T y)
{
if (Object.ReferenceEquals(x, y))
{
return true;
}
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
{
return false;
}
return _onEqualsProcessFunc(x, y);
}
public int GetHashCode(T x)
{
if (Object.ReferenceEquals(x, null))
{
return 0;
}
return _onGetHashCodeProcessFunc(x);
}
}
public static TResult ComputeFormula<TResult, TParameter>
(
string formula
, params TParameter[] parameters
)
{
var dt = new DataTable();
var list = parameters.ToList();
var parametersNames = new List<string>(); ;
int i = 0;
Array.ForEach
(
parameters
, (x) =>
{
string f = string.Format("F{0}", i++);
parametersNames.Add(f);
var dc = new DataColumn(f, typeof(TParameter));
dt.Columns.Add(dc);
}
);
string expression = string.Format(formula, parametersNames.ToArray());
dt.Columns.Add(new DataColumn("Microshaoft", typeof(TResult), expression));
var dr = dt.NewRow();
i = 0;
Array.ForEach
(
parameters
, (x) =>
{
dr[i++] = x;
}
);
dt.Rows.Add(dr);
return (TResult)dr["Microshaoft"];
}
public static TResult ComputeFormula<TResult, TParameter>
(
string formula
, params Tuple<string, TParameter>[] parameters
)
{
var dt = new DataTable();
var comparer = new ObjectEqualityComparer<Tuple<string, TParameter>>
(
(x, y) =>
{
return x.Item1 == y.Item1;
}
, (x) =>
{
return x.Item1.GetHashCode();
}
);
var list = parameters.Distinct
(
comparer
)
.ToList();
list.ForEach
(
(x) =>
{
var dc = new DataColumn
(
x.Item1
, x.Item2.GetType()
);
dt.Columns.Add(dc);
}
);
dt.Columns.Add(new DataColumn("Microshaoft", typeof(TResult), formula));
var dr = dt.NewRow();
list.ForEach
(
(x) =>
{
dr[x.Item1] = x.Item2;
}
);
dt.Rows.Add(dr);
return (TResult)dr["Microshaoft"];
}
}
public class JScriptEvaluator
{
private static MethodInfo _mi = typeof(string).GetMethods().First
(
m => m.Name.Equals("Format")
&& m.GetParameters().Length == 2
&& m.IsStatic
&& m.GetParameters()[1].Name == "args"
);
private static Func<string, object[], object> _func = null;
public static string ComputeFormula<TParameter>(string formula, params TParameter[] parameters)
{
object[] objects = new object[parameters.Length];
Array.Copy(parameters, objects, objects.Length);
string expression1 = string.Format(formula, objects);
return (string)JScriptEvaluator.Eval(expression1);
//=====================================================================
object[] ps = new object[parameters.Length];
Array.Copy(parameters, 0, ps, 0, ps.Length);
if (_func == null)
{
_func = DynamicCallMethodExpressionTreeInvokerHelper.CreateMethodCallInvokerFunc<string, string>
(
typeof(string)
, () =>
{
var methodsInfos = typeof(string).GetMethods();
var methodInfo = methodsInfos.First
(
(x) =>
{
var parametersInfos = x.GetParameters();
//Debug.Assert(x.Name.ToLower() == "Format".ToLower());
return
x.Name.ToLower() == "Format".ToLower()
&& x.IsStatic
&& parametersInfos[0].ParameterType == typeof(string)
&& parametersInfos[1].ParameterType == typeof(object[])
&& Attribute.IsDefined
(
parametersInfos[1]
, typeof(ParamArrayAttribute)
);
}
);
return methodInfo;
}
);
}
string expression = (string)_mi.Invoke
(
null
, new object[]
{
formula
, ps
}
);
expression = (string) _func
(
formula
, new object[]
{
formula
, ps
}
);
return (string) JScriptEvaluator.Eval(expression);
}
public static object Eval(string statement)
{
return _evaluatorType.InvokeMember
(
"Eval"
, BindingFlags.InvokeMethod
, null
, _evaluator
, new object[]
{
statement
}
);
}
static JScriptEvaluator()
{
CodeDomProvider provider = CodeDomProvider.CreateProvider("JScript");
CompilerParameters parameters;
parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
CompilerResults results;
results = provider.CompileAssemblyFromSource(parameters, _JScript);
Assembly assembly = results.CompiledAssembly;
_evaluatorType = assembly.GetType("Microshaoft.JScriptEvaluator");
var constructorInfo = _evaluatorType.GetConstructors().First();
var func = DynamicCallMethodExpressionTreeInvokerHelper.CreateNewInstanceConstructorInvokerFunc
(
_evaluatorType
, constructorInfo
);
_evaluator = func(null);
//_evaluator = Activator.CreateInstance(_evaluatorType);
}
private static object _evaluator = null;
private static Type _evaluatorType = null;
/// <summary>
/// JScript代码
/// </summary>
private static readonly string _JScript =
@"
package Microshaoft
{
class JScriptEvaluator
{
public function Eval(statement : String) : String
{
return eval(statement);
}
}
}
";
}
}
namespace Microshaoft
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
public static class DynamicCallMethodExpressionTreeInvokerHelper
{
public static Func<object[], object> CreateNewInstanceConstructorInvokerFunc
(
Type type
, Func<ConstructorInfo> getConstructorInfoFunc
)
{
var constructorInfo = getConstructorInfoFunc();
return CreateNewInstanceConstructorInvokerFunc<object>
(
type
, constructorInfo
);
}
public static Func<object[], T> CreateNewInstanceConstructorInvokerFunc<T>
(
Type type
, Func<ConstructorInfo> getConstructorInfoFunc
)
{
var constructorInfo = getConstructorInfoFunc();
return CreateNewInstanceConstructorInvokerFunc<T>
(
type
, constructorInfo
);
}
public static Func<object[], object> CreateNewInstanceConstructorInvokerFunc
(
Type type
, ConstructorInfo constructorInfo
)
{
return CreateNewInstanceConstructorInvokerFunc<object>(type, constructorInfo);
}
public static Func<object[], T> CreateNewInstanceConstructorInvokerFunc<T>
(
Type type
, ConstructorInfo constructorInfo
)
{
var parametersInfos = constructorInfo.GetParameters();
var constructorParametersExpressions = new List<ParameterExpression>();
int i = 0;
Array.ForEach
(
parametersInfos
, (x) =>
{
var parameterExpression = Expression.Parameter
(
x.ParameterType
, "p" + i.ToString()
);
constructorParametersExpressions.Add(parameterExpression);
i++;
}
);
var newExpression = Expression.New(constructorInfo, constructorParametersExpressions);
var inner = Expression.Lambda(newExpression, constructorParametersExpressions);
var args = Expression.Parameter(typeof(object[]), "args");
var body = Expression.Invoke
(
inner
, constructorParametersExpressions.Select
(
(p, ii) =>
{
return Expression.Convert
(
Expression.ArrayIndex
(
args
, Expression.Constant(ii)
)
, p.Type
);
}
).ToArray()
);
var outer = Expression.Lambda<Func<object[], T>>(body, args);
var func = outer.Compile();
return func;
}
public static Action<T, object[]> CreateMethodCallInvokerAction<T>
(
Type type
, Func<MethodInfo> getMethodInfoFunc
)
{
var methodInfo = getMethodInfoFunc();
return CreateMethodCallInvokerAction<T>
(
type
, methodInfo
);
}
public static Action<T, object[]> CreateMethodCallInvokerAction<T>
(
Type type
, MethodInfo methodInfo
)
{
ParameterExpression instanceParameterExpression;
MethodCallExpression methodCallExpression;
ParameterExpression argumentsParameterExpression = GetMethodArgumentsParameterExpression
(
type
, methodInfo
, out instanceParameterExpression
, out methodCallExpression
);
var lambda = Expression.Lambda<Action<T, object[]>>(methodCallExpression, instanceParameterExpression, argumentsParameterExpression);
var action = lambda.Compile();
return action;
}
public static Func<T, object[], TResult> CreateMethodCallInvokerFunc<T, TResult>
(
Type type
, Func<MethodInfo> getMethodInfoFunc
)
{
var methodInfo = getMethodInfoFunc();
return
CreateMethodCallInvokerFunc<T, TResult>
(
type
, methodInfo
);
}
public static Func<T, object[], TResult> CreateMethodCallInvokerFunc<T, TResult>
(
Type type
, MethodInfo methodInfo
)
{
ParameterExpression instanceParameterExpression;
MethodCallExpression methodCallExpression;
ParameterExpression argumentsParameterExpression = GetMethodArgumentsParameterExpression
(
type
, methodInfo
, out instanceParameterExpression
, out methodCallExpression
);
var lambda = Expression.Lambda<Func<T, object[], TResult>>(methodCallExpression, instanceParameterExpression, argumentsParameterExpression);
var func = lambda.Compile();
return func;
}
private static ParameterExpression GetMethodArgumentsParameterExpression
(
Type type
, MethodInfo methodInfo
, out ParameterExpression instanceParameterExpression
, out MethodCallExpression methodCallExpression
)
{
var argumentsParameterExpression = Expression.Parameter(typeof(object[]), "args");
instanceParameterExpression = Expression.Parameter(type);
UnaryExpression instanceConvertUnaryExpression = null;
if (!methodInfo.IsStatic)
{
instanceConvertUnaryExpression = Expression.Convert(instanceParameterExpression, type);
}
var parametersParameterExpressionList = new List<Expression>();
int i = 0;
var parametersInfos = methodInfo.GetParameters();
Array.ForEach
(
parametersInfos
, (x) =>
{
BinaryExpression valueObject = Expression.ArrayIndex
(
argumentsParameterExpression
, Expression.Constant(i)
);
UnaryExpression valueCast = Expression.Convert
(
valueObject
, x.ParameterType
);
parametersParameterExpressionList.Add(valueCast);
i++;
}
);
methodCallExpression = Expression.Call(instanceConvertUnaryExpression, methodInfo, parametersParameterExpressionList);
return argumentsParameterExpression;
}
}
}
namespace Microshaoft
{
using System;
using System.IO;
using System.Net.Mail;
using System.Reflection;
public static partial class ExtensionMethodsManager
{
public static byte[] GetBytes(this MailMessage mailMessage)
{
Assembly assembly = typeof(SmtpClient).Assembly;
Type type = assembly.GetType("System.Net.Mail.MailWriter");
var parametersTypes = new[]
{
typeof(Stream)
};
object x = null;
using (Stream stream = new MemoryStream())
{
var constructorInfo = type.GetConstructor
(
BindingFlags.Instance | BindingFlags.NonPublic
, null
, parametersTypes
, null
);
var func = DynamicCallMethodExpressionTreeInvokerHelper.CreateNewInstanceConstructorInvokerFunc<object>
(
type
, constructorInfo
);
x = func(new[] { stream });
var action = DynamicCallMethodExpressionTreeInvokerHelper.CreateMethodCallInvokerAction<MailMessage>
(
typeof(MailMessage)
, () =>
{
var methodInfo = typeof(MailMessage).GetMethod
(
"Send"
, BindingFlags.NonPublic | BindingFlags.Instance
, null
, new[] { type, typeof(bool) }
, null
);
return methodInfo;
}
);
action
(
mailMessage
, new[]
{
x
, true
}
);
byte[] buffer = StreamDataHelper.ReadDataToBytes(stream);
return buffer;
}
}
}
}
namespace Microshaoft
{
using System.IO;
public static class StreamDataHelper
{
public static byte[] ReadDataToBytes(Stream stream)
{
byte[] buffer = new byte[64 * 1024];
MemoryStream ms = new MemoryStream();
int r = 0;
int l = 0;
long position = -1;
if (stream.CanSeek)
{
position = stream.Position;
stream.Position = 0;
}
while (true)
{
r = stream.Read(buffer, 0, buffer.Length);
if (r > 0)
{
l += r;
ms.Write(buffer, 0, r);
}
else
{
break;
}
}
byte[] bytes = new byte[l];
ms.Position = 0;
ms.Read(bytes, 0, (int)l);
ms.Close();
ms.Dispose();
ms = null;
if (position >= 0)
{
stream.Position = position;
}
return bytes;
}
}
}
|