Roslyn scripting - using aliases - c#

I'm just getting started with Roslyn scripting, and I'm having a little bit of trouble understanding how the Imports property on the ScriptOptions class works. I'm fine with the concept of importing an entire namespace, but if I add individual class names to the imports list, I can't use them in my script without fully qualifying them. For example:
Error: "CS0103: The name 'DateTime' does not exist in the current context"
var scriptOptions = ScriptOptions.Default
.WithReferences(typeof(DateTime).Assembly)
.WithImports(typeof(DateTime).FullName);
var script = CSharpScript.Create<DateTime>("DateTime.UtcNow",
scriptOptions);
var now = script.RunAsync(null, CancellationToken.None).Result;
Success: Use Fully-Qualified Type Name
var scriptOptions = ScriptOptions.Default
.WithReferences(typeof(DateTime).Assembly)
.WithImports(typeof(DateTime).FullName);
var script = CSharpScript.Create<DateTime>("System.DateTime.UtcNow",
scriptOptions);
var now = script.RunAsync(null, CancellationToken.None).Result;
Success: Import System Namespace
var scriptOptions = ScriptOptions.Default
.WithReferences(typeof(DateTime).Assembly)
.WithImports("System");
var script = CSharpScript.Create<DateTime>("DateTime.UtcNow",
scriptOptions);
var now = script.RunAsync(null, CancellationToken.None).Result;
What I'd like to do is restrict the script so that it only has access to a few types within a namespace (i.e. I don't want to make the whole of the System namespace available, but allow access to System.DateTime, System.Math, etc), but not require the script to fully-qualify these type names when they're used. I appreciate that it is also possible to add using statements to the script itself, but I'd ideally like to have the script engine take care of this for me.
I've attempted declaring aliases in the WithImports method (e.g. ScriptOptions.Default.WithImports("DateTime = System.DateTime")), but this just gives me a compilation error (CS0246: The type or namespace name 'DateTime = System' could not be found (are you missing a using directive or an assembly reference?)).
The documentation seems to be pretty thin on the ground, but the source for the ScriptImports class seems to suggest that namespaces, static classes, and aliases can all be imported. Am I doing something stupid or missing anything obvious here?
UPDATE
Thanks to Enfyve's helpful comments, I can now access static properties and methods, but I still have to use a fully-qualified name when calling constructors:
var scriptOptions = ScriptOptions.Default
.WithReferences(typeof(System.DateTime).FullName)
.WithImports("System.DateTime");
var script = CSharpScript.Create<object>("new DateTime()", scriptOptions);
// Still throws CS0246 compiler error...
var result = script.RunAsync(null, CancellationToken.None).Result.Dump();

You can access static properties and methods of a type by importing it as if it was an alias. eg: with .WithImports("System.DateTime") and then "UtcNow"
However, this isn't a true type-alias-directive (see: Issue #7451)
and so you cannot create objects in this manner.

Related

Reference to type 'CancellationToken' claims it is defined in 'System.Runtime'

I'm trying to generate some class by using Roslyn api however I can't compile generated code successfully becouse of that error. It sounds:
error CS7069: Reference to type 'CancellationToken' claims it is defined in 'System.Runtime', but it could not be found
what I'm trying to do is:
var objLocation = typeof(object).GetTypeInfo().Assembly.Location;
var path = new FileInfo(objLocation);
var directory = path.Directory;
Compilation = Compilation.AddReferences(MetadataReference.CreateFromFile(objLocation));
Compilation = Compilation.AddReferences(MetadataReference.CreateFromFile(Path.Combine(directory.FullName, "System.dll")));
Compilation = Compilation.AddReferences(MetadataReference.CreateFromFile(Path.Combine(directory.FullName, "System.Runtime.dll")));
As far as I see, the System.Runtime.dll is only placeholder that references different libraries so I don't understand why the message appear and why the compiler is looking for that type here.
Could some point me something?
Sounds like you are compiling for .net core.
CancellationToken resides in mscorlib.dll, so you need to reference that as well.

Expose global singletons to CSharpScripts

I want to use the Roslyn Scripting Engine to provide a scripting engine for
our Software. Our software exposes some of it's api as singletons. However i cannot access those statics in the executed code.
For example i want to do something like this in script:
IOManager.Instance.DoWork(...);
When i do this:
var scriptContent = "IOManager.Instance.DoWork(...);
var options = ScriptOptions.Default;
options.AddReference(this.GetType().Assembly);
var script = CSharpScript.Create(scriptContent, options);
await script.RunAsync();
I get this error:
The name 'IOManager' does not exist in the current context
I thought maybe adding a reference to the current assembly might fix this problem. But it doesn't. I also know, that it is possible to set a global object to the script context. But i want to expose all statics/singletons accessible where i execute the script, to the script itself.
Thank you for your help.
You need to add the import for IOManager in your script:
var script = CSharpScript.Create( "IOManager.Instance.DoWork(...)" , ScriptOptions.Default.AddImports( "Namespace for IOManager" ) );

Object in ProjectReference not accessible when using 'Import'

In a simple project i want to reference objects from a webreference added to another c# library.
The Webreference is called QServices The default namespace is set as below
What seems to work is the following code:
Taskworkflow.SI.QServices.Record[] querysResult = new Taskworkflow.SI.QServices.Record[0];
yet when i import the Taskworkflow.SI - namespace, i keep on getting errors:
using TaskWorkflow.SI;
....
QServices.Record[] querysResult = new QServices.Record[0];
This results in the error:
The type or namespace name 'QServices' could not be found (are you missing a using directive or an assembly reference?)
Could someone clarify this for me?
Thank you for your time.
Note: QServices do only exist inside TaskWorkflow.SI. They do not have any occurences in other projects nor do they have any classes/namespaces/objects that share the name.
I strongly suspect that for whatever reason, you're ending up with a namespace called QServices declared in the TaskWorkflow.SI namespace. So actually you want:
using TaskWorkflow.SI.QServices;
....
Record[] querysResult = new Record[0];
Or you could explicitly alias it:
using QServices = TaskWorkflow.SI.QServices;
....
QServices.Record[] querysResult = new QServices.Record[0];

Embedding boo in C#, does not recognise executing assembly

scripts/ai/Dream.boo
import CultLib
import LonelyHero
class Dream(Enemy):
pass
C#
var bc = new BooCompiler();
bc.Parameters.Input.Add(new FileInput("rsc/script/ai/" + "Dream" + ".boo"));
bc.Parameters.Pipeline = new CompileToMemory();
bc.Parameters.References.Add(Assembly.GetExecutingAssembly());
bc.Parameters.References.Add(Assembly.LoadFile(new DirectoryInfo("CultLib.dll").FullName));
bc.Parameters.References.Add(Assembly.LoadFile(new DirectoryInfo("sfmlnet-audio-2.dll").FullName));
bc.Parameters.References.Add(Assembly.LoadFile(new DirectoryInfo("sfmlnet-graphics-2.dll").FullName));
bc.Parameters.References.Add(Assembly.LoadFile(new DirectoryInfo("sfmlnet-window-2.dll").FullName));
var cc = bc.Run();
if(cc.GeneratedAssembly!=null)
{
cc.GeneratedAssembly.CreateInstance("Dream", true, BindingFlags.NonPublic, null,
new object[] {Parent, pos}, null, null);
}
else
{
foreach (var error in cc.Errors)
Console.WriteLine(error);
}
In the line bc.Parameters.References.Add(Assembly.GetExecutingAssembly()); I add the executing assembly, which contains the namespace "LonelyHero". However, the error
rsc/script/ai/Dream.boo(2, 8): BCE0021: Namespace LonelyHero not found. maybe you forgot to add an assembly reference?
appears.
LonelyHero should exist, why does this error occur and what can I do to resolve it?
Note:
Upon replacing Assembly.GetExecutingAssmebly() with Assembly.GetAssembly(typeof(Enemy)) , thus assuring it adds the assembly with a class under the LonelyHero namespace, the same error occurs. Also with Assembly.LoadFile(new DirectoryInfo("LonelyHero.exe").FullName)
Occurs in Boo 0.9.4.9 and booxw-1203
Imported namespaces in BOO need to contain at least one public type for the import to succeed; otherwise you will get the BCE0021 error, so you want to make sure the Enemy type is public (or another one).
I don't know Boo or C# but I found someone asking a similar question on the Boo Programming Google Group. The question they were asking:
"Namespace 'Pathfinding' not found, maybe you forgot to add an assembly reference?"
Specifically they were getting this error:
I am converting some existing code I had from C# into Boo. One of my
classes had a "using Pathfinding" which got converted to "import
Pathfinding" by the script converter.
I get this error when trying to compile:
Assets/Script/VehicleController.boo(4,8): BCE0021: Namespace
'Pathfinding' not found, maybe you forgot to add an assembly
reference?
The Pathfinding library I'm using is written in C#. Could this cause
problems? Is there anything additional I need to do to make this work?
This looked like your error message and the solution someone mentioned was that you needed to put your scripts into your compilation phase earlier to ensure that they're accessible from scripts written in other languages.
This URL was cited as a reference/source for more information on script compilation.

RazorEngine Razor.Parse(...) throws exception about ServiceStack and Markdown?

I ran this simple example from the website and I get the error below when it calls Razor.Parse. How can I fix this???
http://razorengine.codeplex.com/
string template = "Hello #Model.Name! Welcome to Razor!";
string result = Razor.Parse(template, new { Name = "World" });
error CS0234: The type or namespace name 'Markdown' does not exist in the namespace 'ServiceStack' (are you missing an assembly reference?)
Not sure why you've linked to http://razorengine.codeplex.com
The 'ServiceStack' error assumes you want to use the Markdown engine in ServiceStack in which case you should be referencing the RazorEngine.dll that comes with ServiceStack not the one in razorengine.codeplex.com if that's what is done here.
I would imagine one of two things has happened. Either in your configuration file, namespaces have been added within the <razorEngine> configuration section, or the AddNamespace method is being called somewhere to include namespace imports in the compiled template.
The net result, is that namespaces are added to the generated class file, but references are missing. RazorEngine will automatically reference any loaded assemblies in the AppDomain.

Categories