Actually i want to run class file dynamically without restarting server
and i tried with the following code.
the below code works fine on localhost, but it does not works when published on server
CompilerParameters CompilerParams = new CompilerParameters();
string outputDirectory = Directory.GetCurrentDirectory();
CompilerParams.GenerateInMemory = true;
CompilerParams.TreatWarningsAsErrors = false;
CompilerParams.GenerateExecutable = false;
CompilerParams.CompilerOptions = "/optimize";
string[] references = { "System.dll", "System.Linq.dll", AppSession.Analytics.ServerMapPath + "/BITool.dll", "System.ComponentModel.DataAnnotations.dll", AppSession.Analytics.ServerMapPath + "/RDotNet.dll", AppSession.Analytics.ServerMapPath + "/DynamicInterop.dll", "System.Core.dll", AppSession.Analytics.ServerMapPath + "/System.Dynamic.dll" };
CompilerParams.ReferencedAssemblies.AddRange(references);
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerResults compile = provider.CompileAssemblyFromSource(CompilerParams, code);
if (compile.Errors.HasErrors)
{
string text = "Compile error: ";
foreach (CompilerError ce in compile.Errors)
{
text += "rn" + ce.ToString();
}
throw new Exception(text);
}
//ExpoloreAssembly(compile.CompiledAssembly);
Module module = compile.CompiledAssembly.GetModules()[0];
Type mt = null;
MethodInfo methInfo = null;
if (module != null)
{
mt = module.GetType("BITool.Concrete.RIntegration");
}
if (mt != null)
{
methInfo = mt.GetMethod("RConnectFn");
}
if (methInfo != null)
{
methInfo.Invoke(null, new object[] { });
}
Can anyone suggest me a method to achieve this??
Related
How do I generate a C# class from XSD at runtime?
Additionally, how do it list the properties that are contained by the type?
It definitely is possible.. and not too complicated. You just have to add some differen techniques.
You can use the "Description Importer" to import Service descriptions in runtime. Link
What I did was basically creating following steps:
1) Get the WSDL file with a reader (locally or remote, different approaches)
XmlTextReader myXmlReader;
myWebService = new WebServiceImporterCompiler(WSDLPath, soapVersion);
if (useLocalWSDL)
{
FileWebRequest wr = (FileWebRequest)FileWebRequest.Create(WSDLPath);
FileWebResponse wres = (FileWebResponse)wr.GetResponse();
myXmlReader = new XmlTextReader(wres.GetResponseStream());
}
else
{
Uri uri = new Uri(WSDLPath); //WEBSERVICE URI
HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create(uri.OriginalString + "?wsdl");
wr.Credentials = wr.Credentials = new NetworkCredential(userName, password ?? "");
HttpWebResponse wres = (HttpWebResponse)wr.GetResponse();
myXmlReader = new XmlTextReader(wres.GetResponseStream());
}
2) Build an assembly from the definition / myXmlReader
Check if the xml is readable
if (!System.Web.Services.Description.ServiceDescription.CanRead(myXmlReader))
{
throw new IOException("WSDL not readable");
}
Load importer with some basic options (you might add / change something here)
I create an assembly (dll) but with the switch parameters.GenerateInMemory you will be able to generate an in memory class.
ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
ServiceDescription serviceDescription = ServiceDescription.Read(myXmlReader);
descriptionImporter.ProtocolName = soapVersion.ToString(); // EITHER SOAP OR SOAP12
descriptionImporter.AddServiceDescription(serviceDescription, null, null);
descriptionImporter.Style = ServiceDescriptionImportStyle.Client;
descriptionImporter.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;
Compile assembly with CodeDomProvider
CodeCompileUnit codeUnit = new CodeCompileUnit();
CodeNamespace codeNamespace = new CodeNamespace();
codeUnit.Namespaces.Add(codeNamespace); // Add additional Namespaces
ServiceDescriptionImportWarnings importWarnings = descriptionImporter.Import(codeNamespace, codeUnit);
if (importWarnings == 0)
{
using (CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp"))
{
string[] references = { "System.dll", "System.Web.Services.dll", "System.Xml.dll" };
CompilerParameters parameters = new CompilerParameters(references);
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = false;
parameters.IncludeDebugInformation = false;
parameters.CompilerOptions = "/optimize";
parameters.TempFiles = new TempFileCollection(System.IO.Path.GetTempPath() + "xxx", false);
parameters.ReferencedAssemblies.Add("System.dll");
results = compiler.CompileAssemblyFromSource(parameters, CSharpCode);
foreach (CompilerError cError in results.Errors)
{
// log errors
}
if (results.Errors.Count > 0 || results.CompiledAssembly == null) throw new Exception("Kompilierfehler bei Assemblyerstellung");
}
}
3) Use the generated asssembly object to invoke methods for example for calling the service
public T InvokeMethod <T>(Assembly assembly, string serviceNameToCall, MethodInfo methodToCall)
{
SoapHttpClientProtocol mySoapProtocoll;
try
{
object serviceInstance = myAssembly.CreateInstance(serviceNameToCall);
mySoapProtocoll = (SoapHttpClientProtocol)serviceInstance;
mySoapProtocoll.Credentials = CredentialCache.DefaultCredentials; // or use your own
object myObject = (T)ServiceType.InvokeMember(methodToCall, BindingFlags.InvokeMethod, null, mySoapProtocoll, args);
}
}
To get the methodInfo object / available methods use reflections to iterate over the assembly / classes.
A complete guide on reflections can be found here
I want to compile a C# console application inside my application and get the returned result somehow. I want this to happen silently(i don't want the console to actually show etc.) Lets say i have this code
private Assembly BuildAssembly(string code)
{
Microsoft.CSharp.CSharpCodeProvider provider =
new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters compilerparams = new CompilerParameters();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
CompilerResults results =
compiler.CompileAssemblyFromSource(compilerparams, code);
if (results.Errors.HasErrors)
{
StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in results.Errors )
{
errors.AppendFormat("Line {0},{1}\t: {2}\n",
error.Line, error.Column, error.ErrorText);
}
throw new Exception(errors.ToString());
}
else
{
return results.CompiledAssembly;
}
}
How would i execute the assembly and get the results?
Here's something I found -
public object ExecuteCode(string code, string namespacename, string classname, string functionname, bool isstatic, params object[] args)
{
var asm = BuildAssembly(code);
object instance = null;
Type type;
if(isstatic)
{
type = asm.GetType(namespacename + "." + classname);
}
else
{
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
return type.GetMethod(functionname).Invoke(instance, args);
}
This method simply extends your BuildAssembly function.
Source
Here's what I'm doing:
Selector selector = new Selector();
selector.fields = new string[] {"CampaignId", "AdGroupId", "Id", "CriteriaType", "Criteria", "CriteriaDestinationUrl", "Clicks", "Impressions", "Cost"};
Predicate predicate = new Predicate();
predicate.field = "Status";
predicate.#operator = PredicateOperator.IN;
predicate.values = new string[] { "ACTIVE", "PAUSED" };
selector.predicates = new Predicate[] { predicate };
ReportDefinition definition = new ReportDefinition();
definition.reportName = "criteria report";
definition.reportType = ReportDefinitionReportType.CRITERIA_PERFORMANCE_REPORT;
definition.downloadFormat = DownloadFormat.XML;
definition.dateRangeType = ReportDefinitionDateRangeType.YESTERDAY;
definition.selector = selector;
definition.includeZeroImpressions = true;
_handler.RunReport(new AdWordsUser(), definition);
And here's my handler method:
public void RunReport(AdWordsUser user, ReportDefinition definition)
{
if (definition != null)
{
string reportContents = string.Empty;
try
{
ReportUtilities utilities = new ReportUtilities(user);
utilities.ReportVersion = "v201206";
ClientReport report = utilities.GetClientReport(definition);
reportContents = report.Contents.ToString();
}
catch (Exception ex)
{
_errorHandler.AddError(ex);
}
}
}
Where I step through I get this error:
Report contents are invalid. - !!!2|||-1|||[ReportDefinitionError.CUSTOMER_SERVING_TYPE_REPORT_MISMATCH # selector]???
Been searching for hours trying to find a solution. Any hints?
It appears that the issue is indeed needing to pass in the customerClientID.
This document helped me picture what was going on.
I ended up modifying my code like this:
var configOptions = new Dictionary<string,string>();
configOptions.Add("clientCustomerID", customerID.ToString());
_handler.RunReport(new AdWordsUser(configOptions), definition);
So I was thinking of writing online c# compiler and execution environment. And of course problem #1 is security. I ended up creating a little-privileged appdomain for user code and starting it in a new process which is tightly monitored for cpu and memory consumption. Standard console application namespaces are available. So my question is this: can you think of ways of breaking something in some way? You can try your ideas on the spot rundotnet.
Edit2 If anyone cares about the code, there is now open source fork of this project: rextester at github
Edit1 As a response to one of the comments here are some code samples.
So basically you create a console application. I'll just post a big chunk of it:
class Sandboxer : MarshalByRefObject
{
private static object[] parameters = { new string[] { "parameter for the curious" } };
static void Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
string pathToUntrusted = args[0].Replace("|_|", " ");
string untrustedAssembly = args[1];
string entryPointString = args[2];
string[] parts = entryPointString.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
string name_space = parts[0];
string class_name = parts[1];
string method_name = parts[2];
//Setting the AppDomainSetup. It is very important to set the ApplicationBase to a folder
//other than the one in which the sandboxer resides.
AppDomainSetup adSetup = new AppDomainSetup();
adSetup.ApplicationBase = Path.GetFullPath(pathToUntrusted);
//Setting the permissions for the AppDomain. We give the permission to execute and to
//read/discover the location where the untrusted code is loaded.
PermissionSet permSet = new PermissionSet(PermissionState.None);
permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
//Now we have everything we need to create the AppDomain, so let's create it.
AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, null);
//Use CreateInstanceFrom to load an instance of the Sandboxer class into the
//new AppDomain.
ObjectHandle handle = Activator.CreateInstanceFrom(
newDomain, typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,
typeof(Sandboxer).FullName
);
//Unwrap the new domain instance into a reference in this domain and use it to execute the
//untrusted code.
Sandboxer newDomainInstance = (Sandboxer)handle.Unwrap();
Job job = new Job(newDomainInstance, untrustedAssembly, name_space, class_name, method_name, parameters);
Thread thread = new Thread(new ThreadStart(job.DoJob));
thread.Start();
thread.Join(10000);
if (thread.ThreadState != ThreadState.Stopped)
{
thread.Abort();
Console.Error.WriteLine("Job taking too long. Aborted.");
}
AppDomain.Unload(newDomain);
}
public void ExecuteUntrustedCode(string assemblyName, string name_space, string class_name, string method_name, object[] parameters)
{
MethodInfo target = null;
try
{
target = Assembly.Load(assemblyName).GetType(name_space+"."+class_name).GetMethod(method_name);
if (target == null)
throw new Exception();
}
catch (Exception)
{
Console.Error.WriteLine("Entry method '{0}' in class '{1}' in namespace '{2}' not found.", method_name, class_name, name_space);
return;
}
...
//Now invoke the method.
try
{
target.Invoke(null, parameters);
}
catch (Exception e)
{
...
}
}
}
class Job
{
Sandboxer sandboxer = null;
string assemblyName;
string name_space;
string class_name;
string method_name;
object[] parameters;
public Job(Sandboxer sandboxer, string assemblyName, string name_space, string class_name, string method_name, object[] parameters)
{
this.sandboxer = sandboxer;
this.assemblyName = assemblyName;
this.name_space = name_space;
this.class_name = class_name;
this.method_name = method_name;
this.parameters = parameters;
}
public void DoJob()
{
try
{
sandboxer.ExecuteUntrustedCode(assemblyName, name_space, class_name, method_name, parameters);
}
catch (Exception e)
{
Console.Error.WriteLine(e.Message);
}
}
}
You compile the above and have executable which you start and monitor in a new process:
using (Process process = new Process())
{
try
{
double TotalMemoryInBytes = 0;
double TotalThreadCount = 0;
int samplesCount = 0;
process.StartInfo.FileName = /*path to sandboxer*/;
process.StartInfo.Arguments = folder.Replace(" ", "|_|") + " " + assemblyName + " Rextester|Program|Main"; //assemblyName - assembly that contains compiled user code
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
DateTime start = DateTime.Now;
process.Start();
OutputReader output = new OutputReader(process.StandardOutput);
Thread outputReader = new Thread(new ThreadStart(output.ReadOutput));
outputReader.Start();
OutputReader error = new OutputReader(process.StandardError);
Thread errorReader = new Thread(new ThreadStart(error.ReadOutput));
errorReader.Start();
do
{
// Refresh the current process property values.
process.Refresh();
if (!process.HasExited)
{
try
{
var proc = process.TotalProcessorTime;
// Update the values for the overall peak memory statistics.
var mem1 = process.PagedMemorySize64;
var mem2 = process.PrivateMemorySize64;
//update stats
TotalMemoryInBytes += (mem1 + mem2);
TotalThreadCount += (process.Threads.Count);
samplesCount++;
if (proc.TotalSeconds > 5 || mem1 + mem2 > 100000000 || process.Threads.Count > 100 || start + TimeSpan.FromSeconds(10) < DateTime.Now)
{
var time = proc.TotalSeconds;
var mem = mem1 + mem2;
process.Kill();
...
}
}
catch (InvalidOperationException)
{
break;
}
}
}
while (!process.WaitForExit(10)); //check process every 10 milliseconds
process.WaitForExit();
...
}
...
class OutputReader
{
StreamReader reader;
public string Output
{
get;
set;
}
StringBuilder sb = new StringBuilder();
public StringBuilder Builder
{
get
{
return sb;
}
}
public OutputReader(StreamReader reader)
{
this.reader = reader;
}
public void ReadOutput()
{
try
{
int bufferSize = 40000;
byte[] buffer = new byte[bufferSize];
int outputLimit = 200000;
int count;
bool addMore = true;
while (true)
{
Thread.Sleep(10);
count = reader.BaseStream.Read(buffer, 0, bufferSize);
if (count != 0)
{
if (addMore)
{
sb.Append(Encoding.UTF8.GetString(buffer, 0, count));
if (sb.Length > outputLimit)
{
sb.Append("\n\n...");
addMore = false;
}
}
}
else
break;
}
Output = sb.ToString();
}
catch (Exception e)
{
...
}
}
}
Assemblies that user code can use are added at compile time:
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.OutputAssembly = ...
cp.GenerateInMemory = false;
cp.TreatWarningsAsErrors = false;
cp.WarningLevel = 4;
cp.IncludeDebugInformation = false;
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
cp.ReferencedAssemblies.Add("System.Data.dll");
cp.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
cp.ReferencedAssemblies.Add("System.Xml.dll");
cp.ReferencedAssemblies.Add("System.Xml.Linq.dll");
using (CodeDomProvider provider = CodeDomProvider.CreateProvider(/*language*/))
{
cr = provider.CompileAssemblyFromSource(cp, new string[] { data.Program });
}
Have you looked at Mono's Compiler as a service? I think that is pretty cool what they are doing, perhaps something there could be useful to you for this project.
For a good example of something similar to this already in existence, there is a place at http://www.topcoder.com, which has an "Algorithm Arena", where code is submitted and automatically scored. There are restrictions against using certain types of classes, such as Exception, but it may be a good idea to examine their application for a proof of concept.
Thanks for the messages about my first post about this problem. I will do a repost and try to be more clear this time. I guess this may be a trivial problem but I'm really stuck and need some help. This is my first time posting here.
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using Microsoft.CSharp;
namespace DynamicCode
{
public class DynaCore
{
string WorkingCode =
"using System;"+
"using System.Collections.Generic;"+
"namespace DynaCore"+
"{"+
" public class DynaCore"+
" {"+
" static public string DynamicResult()"+
" {"+
" return \"I'm compiled\";"+
" }"+
" }"+
"}";
string PredicateTemplCode =
"using System;"+
"using System.Linq;"+
"using System.Collections.Generic;"+
"namespace DynaCore"+
"{"+
" public class DynaCore"+
" {"+
" static public Func<{1}, bool> DynamicResult()"+
" {"+
" return new Func<{1}, bool>({2});"+
" }"+
" }"+
"}";
public DynaCore()
{
string compiledString = WorkingCompilation(WorkingCode);
Func<bool, bool> compiladePredicate = NotWorkingCompilation<bool>(PredicateTemplCode, "(o)=> true");
}
string WorkingCompilation(string code)
{
var cParams = new CompilerParameters();
cParams.GenerateInMemory = true;
cParams.TreatWarningsAsErrors = false;
cParams.GenerateExecutable = false;
cParams.CompilerOptions = "/optimize /target:library";
var curAss = Assembly.GetExecutingAssembly();
cParams.ReferencedAssemblies.Add("System.dll");
cParams.ReferencedAssemblies.Add("mscorlib.dll");
cParams.ReferencedAssemblies.Add("System.dll");
cParams.ReferencedAssemblies.Add("System.Data.dll");
cParams.ReferencedAssemblies.Add(curAss.Location);
var provider = new CSharpCodeProvider();
var compalerResult = provider.CompileAssemblyFromSource(cParams, code);
if (compalerResult.Errors.HasErrors)
{
var complieError = "";
foreach (CompilerError ce in compalerResult.Errors)
complieError += ce + " ";
throw new Exception(complieError.Trim());
}
Module module = compalerResult.CompiledAssembly.GetModules()[0];
Type mt = null;
MethodInfo methInfo = null;
return (string)module.GetType("DynaCore.DynaCore").GetMethod("DynamicResult").Invoke(null, null);
}
Func<T, bool> NotWorkingCompilation<T>(string code, string predicateString)
{
var cParams = new CompilerParameters();
cParams.GenerateInMemory = true;
cParams.TreatWarningsAsErrors = false;
cParams.GenerateExecutable = false;
cParams.CompilerOptions = "/optimize /target:library";
var curAss = Assembly.GetExecutingAssembly();
cParams.ReferencedAssemblies.Add("System.dll");
cParams.ReferencedAssemblies.Add("mscorlib.dll");
cParams.ReferencedAssemblies.Add("System.dll");
cParams.ReferencedAssemblies.Add("System.Data.dll");
cParams.ReferencedAssemblies.Add("System.Core.dll");
cParams.ReferencedAssemblies.Add(curAss.Location);
var provider = new CSharpCodeProvider();
var codeToRun = code.Replace("{1}", typeof(T).Name).Replace("{2}", predicateString);
var compalerResult = provider.CompileAssemblyFromSource(cParams, codeToRun);
if (compalerResult.Errors.HasErrors)
{
var complieError = "";
foreach (CompilerError ce in compalerResult.Errors)
complieError += ce + " ";
throw new Exception(complieError.Trim());
}
Module module = compalerResult.CompiledAssembly.GetModules()[0];
Type mt = null;
MethodInfo methInfo = null;
return (Func<T, bool>)module.GetType("DynaCore.DynaCore").GetMethod("DynamicResult").Invoke(null, null);
}
}
}
The problem is that when I reference System.Core.dll in ReferencedAssemblies.Add("System.Core.dll"), it gives me a compiler error:
error CS0006: Metadata file 'System.Core.dll' could not be found
I'm using v3.5 and VS 2008.
Thanks for all the answers!
It turns out that CSharpCodeProvider defaults to version 2.0 that have no support for generics or linq. The following fixed the problem:
var provider = new CSharpCodeProvider(
new Dictionary<String, String>{{ "CompilerVersion","v3.5" }});
I thought I'd update this thread since it was never properly answered. I just came across the same issue (CS0006), having to include a WPF library that was in the WPF directory, and wound up fixing it with the following:
string ver = string.Format("{0}.{1}.{2}", Environment.Version.Major, Environment.Version.MajorRevision, Environment.Version.Build);
string exWpfDir = string.Format(#"C:\WINDOWS\Microsoft.NET\Framework\v{0}\WPF", ver);
string exDir = string.Format(#"C:\WINDOWS\Microsoft.NET\Framework\v{0}", ver);
CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters compilerparams = new CompilerParameters();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
compilerparams.IncludeDebugInformation = false;
compilerparams.TreatWarningsAsErrors = false;
compilerparams.CompilerOptions = string.Format("/lib:{0}", exWpfDir);
compilerparams.CompilerOptions = string.Format("/lib:{0}", exDir);
Another issue may be that System.Core.dll is actually in a different location than the other dlls mentioned.
On my machine, System.Core.dll is located in %ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll, whereas the other dlls are in the GAC.
Sometimes you need to add the referenced assembly to the CSharpCodeProvider parameters.
parameters.ReferencedAssemblies.Add("System.dll");
Hope this helps.
The resulting code
using System;
using System.Linq;
using System.Collections.Generic;
namespace DynaCore
{
public class DynaCore
{
static public Func<Boolean, bool> Main()
{
Func<Boolean, bool> retur = (o) => true;
}
}
}
does not compile itself when pasted into a new file. First compilation error is
'DynaCore.DynaCore.Main()': not all code paths return a value
First you need to generate code thats compiling when pasted into a empty .cs file.
The first obvious thing is to fix the func-statement into something like
return new Func<Boolean, bool>(o => true);
Edit:
And don't call the method Main.