Cannot Access static field c# Error - c#

I have the following c# code within a 2012 SSIS package Script Task using 4.5 Framework:
[Microsoft.sqlServer.Dts.Tasks.ScripTask.SSISScriptTaskEntryPointAttribute]
Public partial class ScriptMain
{
static ScriptMain()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomai_AssemblyResolveForDLL);
}
Static System.Reflection.Assembly CurrentDomain_AssemblyResolveForDLL(object sender, ResolveEventArgs args)
{
If (args.Name.Contains("NameofMydll"))
{
string path = #"c:\Temp\";
return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "NameofMydll.dll"));
}
}
return null;
}
The purpose of this code is to load a .dll file used in a SSIS Script task during run time. The way the code works is just like what is described here. With the path hard coded, it works fine.
The problem I have is I need to dynamically set the value of the path so I can promote the code from server to server with no hard coded values. Since the function is static, I didn't know how to do it.
The line of code here:
MyVariable = (string)Dts.Variables.["MyVariable"].value;
...receives the value with MyVariable declared as a global public string variable (this works fine as long as its not within the code above). But using "MyVariable" in place of the #"c:\Temp\" is where I get the Cannot access non static field...error.
Changing the declaration to public static string allows it to compile, but throws an error at run time.
Exception has been thrown by the target of invocation.
The value is assigned through a function just before the line of code below is called:
AppDomain.CurentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolveForDLL)
The call to the function is the first line of code in Main(), the line of code above is the 2nd.
All I need to do is assign the value of the path from a variable. Any assistance will be greatly appreciated.

Change to MyVariable = (string)Dts.Variables.["MyVariable"].value;
or access via it's positionMyVariable = (string)Dts.Variables.[0].value;

Related

AppDomain in Azure Function

I have tried to create an AppDomain within Azure Functions to run untrusted code. Creating the domain seems to work fine, but when I try to load in assemblies, it seems like they get loaded in incorrectly.
First I tried a simple AppDomain:
public class Sandboxer
{
public void Run()
{
AppDomain newDomain = AppDomain.CreateDomain("name");
var obj = newDomain.CreateInstance(typeof(OtherProgram).Assembly.FullName, typeof(OtherProgram).FullName).Unwrap();
}
}
public class OtherProgram : MarshalByRefObject
{
public void Main(string[] args)
{
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
foreach (var item in args)
Console.WriteLine(item);
}
}
I got an error
"System.IO.FileNotFoundException : Could not load file or assembly 'Sandboxer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2cd9cb1d6fdb50b4' or one of its dependencies. The system cannot find the file specified."
I then tried to set the appliactionBase to the folder with my dll in it.
public class Sandboxer
{
public void Run()
{
var location = typeof(OtherProgram).Assembly.Location;
AppDomainSetup ads = new AppDomainSetup();
ads.ApplicationBase = Path.GetDirectoryName(location);
AppDomain newDomain = AppDomain.CreateDomain("name", null, ads);
var obj = newDomain.CreateInstance(typeof(OtherProgram).Assembly.FullName, typeof(OtherProgram).FullName).Unwrap();
var other = obj as OtherProgram;
var other2 = obj as MarshalByRefObject;
}
}
public class OtherProgram : MarshalByRefObject
{
public void Main(string[] args)
{
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName);
foreach (var item in args)
Console.WriteLine(item);
}
}
In this case, "other" is null at the end of the Run() method, but "other2" is a __TransparentProxy. It seems like it is finding and loading the dll, but doesn't understand the type.
How can I fix this problem? Thanks!
Cross posted here: https://social.msdn.microsoft.com/Forums/azure/en-US/59b119d8-1e51-4460-bf86-01b96ed55b12/how-can-i-create-an-appdomain-in-azure-functions?forum=AzureFunctions&prof=required
In this case, "other" is null at the end of the Run() method, but "other2" is a __TransparentProxy. It seems like it is finding and loading the dll, but doesn't understand the type.
According to your description, I could encounter the similar issue, I tried to create a Console application to check this issue and found that the code could work as expected under a Console application.
For Azure Function, obj as OtherProgram always returns null. Then I tried to instantiate OtherProgram under the current domain as follows:
var obj=AppDomain.CurrentDomain.CreateInstanceFromAndUnwrap(typeof(OtherProgram).Assembly.Location, typeof(OtherProgram).FullName);
OtherProgram op = obj as OtherProgram;
if (op != null)
op.PrintDomain(log);
The above code could work as expected, but I did not found why the object under a new AppDomain always returns null. You may try to add a issue under Azure/Azure-Functions.
This is how I would do it in a conventional .NET application, should work in Azure Functions:
Register to the AppDomain.AssemblyResolve event on the newly created AppDomain
In the event handler, resolve the assembly path using the Function Directory / Function App Directory in order to point to the bin folder
AppDomains are not usable with Azure Functions. In order to properly sandbox code in Azure Functions, you would have to create a new Azure Functions App and run the code there.
If you are allowing users to write scripts, you can use another language like Lua that allows easy sandboxing.

How can I export my c# code logic (if-else-loops) in to text files (e.g XML) and later import it back and run?

I have these requirements coming from client every week for some new logic or verification. For which I have to code new logic (basically some if-else and loops) and launch a new build for him. I want to avoid it by simply coding my logic in visual studio then writing a utility to export it to XML or something and send it to client via e-mail. He just have to place this file in some appropriate folder and the application will behave considering this logic.
Please suggest some solutions. My platform is C# Asp.Net.
Thanks
Using .NET 4.6 and the NuGetPackage Microsoft.CodeAnalysis.Scripting you could implement a scripting engine to run your c# code residing in a textfile without building an assembly.
Install NuGet Package:
Install-Package Microsoft.CodeAnalysis.Scripting.CSharp
Implement TestClass with some basic C#-Code-Content:
class Program
{
static void Main(string[] args)
{
TestScript();
}
private static async void TestScript()
{
// Code snippet: a class with one string-property.
string codeContent = #" using System;
public class ScriptedClass
{
public string HelloWorld { get; set; }
public ScriptedClass()
{
HelloWorld = ""Hello Roslyn!"";
}
}
new ScriptedClass().HelloWorld";
// Instanciate CSharpScriptEngine
var engine = new CSharpScriptEngine();
// Execute code and return string property (HelloWorld)
var scriptingState = await engine.ExecuteAsync(codeContent);
// Print return value from CSharpScript
Console.WriteLine("Returned from CSharpScript: {0}", scriptingState.ReturnValue);
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
}
}
Implement a ScriptingEngine:
internal sealed class CSharpScriptEngine
{
public async Task<ScriptState<object>> ExecuteAsync(string codeContent)
{
// Add references from calling assembly
ScriptOptions options = ScriptOptions.Default.AddReferences(Assembly.GetExecutingAssembly());
// Run codeContent with given options
return await CSharpScript.RunAsync(codeContent, options);
}
}
Read ScriptCode from textfile:
So basically you could read some csharpcode from a textfile of your choice and run them on the fly:
private static async void TestScript()
{
// Read in script file
string codeContent = File.ReadAllText(#"C:\Temp\CSharpScriptTest.cs");
var engine = new CSharpScriptEngine();
// Run script
var scriptingState = await engine.ExecuteAsync(codeContent);
Console.WriteLine("Returned from CSharpScript: {0}", scriptingState.ReturnValue);
Console.WriteLine("Press any key to continue.");
Console.ReadKey();
}
In case you are wondering how all of this works under the hood, Roslyn will create a so called submission from your script code. A submission is an in memory assembly containing the types generated around your script code, which can be identified among the assemblies in the current AppDomain by a ℛ prefix in the name.
The precise implementation details are not important here (though, for example, scriptcs heavily relies on understanding in detail how Roslyn works to provide its extra features), but it's important to know that submissions can be chained together. When they are chained, variables, methods or classes defined in an earlier submission are available to use in subsequent submissions, creating a feature of a C# REPL (read-evaluate-print loop).
C# and Visual Basic - Use Roslyn to Write a Live Code Analyzer for Your API
Hope it helps

Trying to get recognize a class instance in roslyn

I’m writing a Visual Studio Extension, and I want to get the Type of a variable by its name and location.
For instance:
There’s a C# code:
class Program
{
static void Main(string[] args)
{
var flagMick = true;
Console.WriteLine(""Hello, World!"");
}
}
I am able to communicate with the ExpressionEvaluator and the DTE, I am able to read data off the snapshot and understand its location. I have the specific location but:
I don't want to "relearn" c# parsing, that's what Roslyn is supposed to be for.
So I want my extension to recognize the type of “FlagMick” , given its name and location on the screen.
How can I do that with Roslyn?
Use the following code:
var doc = point.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
var model = doc.GetSemanticModelAsync().Result;
var symbol = SymbolFinder.FindSymbolAtPosition(model, point, doc.Project.Solution.Workspace);
You will need a reference to Microsoft.CodeAnalysis.EditorFeatures.Text.dll, which you can get by adding the appropriate NuGet package.

How to get error info from dynamic C# code compiling

I have a C# application which uses a C# script interface. That means that my application will compile C# code and run it.
I am using the System.CodeDom.Compiler class to do it with.
The problem is that if I run the code below it throws an InvalidCastException because it is trying to cast a string to an int in my dynamic code.
If I catch the exception I have no indication where in the 'dynamic code' that error occured. For instance 'InvalidCastException on line 8'.
I get a stack trace, but no line numbers.
Any ideas? I want to present to our users enough information to know where their error is.
public class NotDynamicClass
{
public object GetValue()
{
return "value";
}
}
class Program
{
public static void Main()
{
var provider = CSharpCodeProvider.CreateProvider("c#");
var options = new CompilerParameters();
options.ReferencedAssemblies.Add("DynamicCodingTest.exe");
var results = provider.CompileAssemblyFromSource(options, new[]
{
#"
using DynamicCodingTest;
public class DynamicClass
{
public static void Main()
{
NotDynamicClass #class = new NotDynamicClass();
int value = (int)#class.GetValue();
}
}"
});
var t = results.CompiledAssembly.GetType("DynamicClass");
t.GetMethod("Main").Invoke(null, null);
}
}
You need to set IncludDebugInformation to true on your CompilerParameters.
Update: At the bottom of the MSDN documentation there is a community remark:
For C#, if you set this property to true you need to also set GenerateInMemory to false and set the value of OutputAssembly to a valid file name. This will generate an assembly and a .pdb file on disk and give you file and line number information in any stacktraces thrown from your compiled code.

Mono Compiler as a Service (MCS)

I'd like to consume Mono's compiler as a service from my regular .NET 3.5 application.
I've downloaded the latest bits (2.6.7), created a simple console application in Visual Studio and referenced the Mono.CSharp dll.
Then, in my console app (straight out of a sample online):
Evaluator.Run("using System; using System.Linq;");
bool ress;
object res;
Evaluator.Evaluate(
"from x in System.IO.Directory.GetFiles (\"C:\\\") select x;",
out res, out ress);
foreach (var v in (IEnumerable)res)
{
Console.Write(v);
Console.Write(' ');
}
This throws an exception at Evaluator.Run (the first line):
Illegal enum value: 2049.
Parameter name: access
This is because the dll was compiled using Mono.exe, not csc.exe, I believe.
I've tried downloading the Mono.CSharp dll directly from http://tirania.org/blog/archive/2010/Apr-27.html in the demo-repl.zip file...and that does not throw an exception...However the out parameter (res) after calling Evaluator.Evaluate is null...so I'm not sure what's going wrong. No exception is thrown...
So, I'd like to figure out why the dll I downloaded from the demo-repl.zip returns null.
EDIT: I figured out why it returns null. It seems like for some reason the compiler isn't picking up the System.Linq namespace...though I can't tell why...If I just Evaluate "System.IO.Directory.GetFiles (\"C:\\")", it works fine.
UPDATE: It definitely seems like there's something wrong with the Mono compiler picking up referenced System assemblies. If I directly copy the sample of their csharp console tool:
csharp> var list = new int [] {1,2,3};
csharp> var b = from x in list
> where x > 1
> select x;
csharp> b;
I get the exception:
{interactive}(1,25): error CS1935: An implementation of `Select' query expressio
n pattern could not be found. Are you missing `System.Linq' using directive or `
System.Core.dll' assembly reference?
Also, in order for the MCS to actually be a feasible solution, I'll need to modify the compiler so that it emits to one single dynamic assembly, instead of emitting one assembly per evaluate call (otherwise it presents a major memory leak, which I've dealt with before in the form of the CSharpCodeProvider). Does anyone have an idea of how difficult this will be or can anyone point me in the right direction here?
Thanks.
Ok, I think I have some answers.
To resolve the assembly load problem, I can either place a call to Assembly.LoadWithPartialName inside Mono.CSharp.Driver.LoadAssembly, or do the following in my application
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
private static bool isResolving;
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (!isResolving)
{
isResolving = true;
var a = Assembly.LoadWithPartialName(args.Name);
isResolving = false;
return a;
}
return null;
}
To make Mono reuse the same dynamic assembly for each Evaluate/Compile call, all I had to change is the following (although there are probably complexities I'm missing here).....
Inside Mono.CSharp.Evaluator, I added the property:
/// <summary>
/// Gets or sets a value indicating whether to auto reset when evaluations are performed and create a new assembly.
/// </summary>
/// <value><c>true</c> if [auto reset]; otherwise, <c>false</c>.</value>
public static bool AutoReset { get; set; }
Then...make sure Reset is called at least once in Init:
static void Init ()
{
Init (new string [0]);
Reset();
}
And finally, in ParseString, simply don't reset unless AutoReset is true...
static CSharpParser ParseString (ParseMode mode, string input, out bool partial_input)
{
.
.
.
if (AutoReset) Reset ();
According to Miguel's blog page you linked, you have to add a reference to System.Core in order to use LINQ on .Net.
csharp> using System.Linq;
csharp> from x in "Foo" select x;

Categories

Resources