Skip to content

Commit cbbc258

Browse files
committed
Add project files.
1 parent 89f0305 commit cbbc258

15 files changed

Lines changed: 1513 additions & 0 deletions

.editorconfig

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# editorconfig.org
2+
root = true
3+
4+
# Don't use tabs for indentation.
5+
[*]
6+
indent_style = space
7+
trim_trailing_whitespace = false
8+
9+
# Code files
10+
[*.{cs,csx,vb,vbx}]
11+
indent_size = 4
12+
insert_final_newline = true
13+
charset = utf-8-bom
14+
trim_trailing_whitespace = true
15+
16+
[*.{css,less,html,js,ts,json}]
17+
charset = utf-8
18+
end_of_line = lf
19+
indent_size = 2
20+
insert_final_newline = true
21+
trim_trailing_whitespace = true
22+
23+
[*.md]
24+
trim_trailing_whitespace = false
25+
26+
[**.cshtml]
27+
indent_size = 4
28+
29+
# size matters when we render html emails
30+
[StackOverflow/Views/Email/**.Html.cshtml]
31+
indent_style = tab
32+
tab_width = 4
33+
trim_trailing_whitespace = true
34+
35+
# Xml project files
36+
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
37+
indent_size = 2
38+
39+
# Xml config files
40+
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
41+
indent_size = 2
42+
43+
# Dotnet code style settings:
44+
[*.{cs,vb}]
45+
# Sort using and Import directives with System.* appearing first
46+
dotnet_sort_system_directives_first = true
47+
48+
# Avoid "this." and "Me." if not necessary
49+
dotnet_style_qualification_for_field = false:suggestion
50+
dotnet_style_qualification_for_property = false:suggestion
51+
dotnet_style_qualification_for_method = false:suggestion
52+
dotnet_style_qualification_for_event = false:suggestion
53+
54+
# Use language keywords instead of framework type names for type references
55+
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
56+
dotnet_style_predefined_type_for_member_access = true:suggestion
57+
58+
# Suggest more modern language features when available
59+
dotnet_style_object_initializer = true:suggestion
60+
dotnet_style_collection_initializer = true:suggestion
61+
dotnet_style_coalesce_expression = true:suggestion
62+
dotnet_style_null_propagation = true:suggestion
63+
dotnet_style_explicit_tuple_names = true:suggestion
64+
65+
# CSharp code style settings:
66+
[*.cs]
67+
# Prefer "var" everywhere
68+
#csharp_style_var_for_built_in_types = true:suggestion
69+
csharp_style_var_when_type_is_apparent = true:suggestion
70+
csharp_style_var_elsewhere = true:suggestion
71+
72+
# Prefer method-like constructs to have a expression-body
73+
csharp_style_expression_bodied_methods = true:none
74+
csharp_style_expression_bodied_constructors = true:none
75+
csharp_style_expression_bodied_operators = true:none
76+
77+
# Prefer property-like constructs to have an expression-body
78+
csharp_style_expression_bodied_properties = true:none
79+
csharp_style_expression_bodied_indexers = true:none
80+
csharp_style_expression_bodied_accessors = true:none
81+
82+
# Suggest more modern language features when available
83+
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
84+
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
85+
csharp_style_inlined_variable_declaration = true:suggestion
86+
csharp_style_throw_expression = true:suggestion
87+
csharp_style_conditional_delegate_call = true:suggestion
88+
89+
# Newline settings
90+
csharp_new_line_before_open_brace = all
91+
csharp_new_line_before_else = true
92+
csharp_new_line_before_catch = true
93+
csharp_new_line_before_finally = true
94+
csharp_new_line_before_members_in_object_initializers = true
95+
csharp_new_line_before_members_in_anonymous_types = true
96+
97+
# Space settings
98+
csharp_space_after_keywords_in_control_flow_statements = true:suggestion

README.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Westwind CSharp Scripting
2+
### Dynamically compile and execute CSharp code at runtime
3+
4+
This small `CSharpScripting` class provides an easy way to compile and execute C# on the fly at runtime using the .NET compiler services. This is ideal to provide support for addin's and application automation tasks that are user configurable.
5+
6+
The library supports both the latest Roslyn compiler and classic CSharp compilation.
7+
8+
> #### Requires Roslyn Code Providers for your Project
9+
> If you want to use Roslyn compilation you have to make sure you add the `Microsoft.CodeDom.CompilerServices` NuGet Package to your project to provide the required compiler binaries for your application. This should be added to the application's start project.
10+
>
11+
> Note that this adds a sizable chunk of files to your application's output folder in the `roslyn` folder. If you don't want this you can use the classic compiler, at the cost of not having access to C# 6+ features.
12+
13+
## Usage
14+
Using the `CSharpScriptExecution` class is very easy. It works by letting you provide either a simple code snippet that can optionally `return` a value, or a complete method signature with a method header and return statement. You can also provide multiple method that can be called explicitly using the `InvokeMethod()` operation.
15+
16+
You can add **Assembly References** and **Namespaces** via the `AddReferece()` and `AddNamespace()` methods.
17+
18+
Script Execution is gated rather than throwing directly to provide
19+
20+
### Executing a Code Snippet
21+
A code snippet can be **any block of .NET code** that can be executed. You can pass any number of parameters to the snippets which are accessible via a `parameters` object array. You can optionally `return` a value by providing a `return` statement.
22+
23+
24+
```cs
25+
var script = new CSharpScriptExecution()
26+
{
27+
SaveGeneratedCode = true,
28+
CompilerMode = ScriptCompilerModes.Roslyn
29+
};
30+
script.AddDefaultReferencesAndNamespaces();
31+
32+
//script.AddAssembly("Westwind.Utilities.dll");
33+
//script.AddNamespace("Westwind.Utilities");
34+
35+
var code = $@"
36+
// Check some C# 6+ lang features
37+
var s = new {{ name = ""Rick""}}; // anonymous types
38+
Console.WriteLine(s?.name); // null propagation
39+
40+
int num1 = (int)parameters[0];
41+
int num2 = (int)parameters[1];
42+
43+
// string templates
44+
var result = $""{{num1}} + {{num2}} = {{(num1 + num2)}}"";
45+
Console.WriteLine(result);
46+
47+
return result;
48+
";
49+
50+
string result = script.ExecuteCode(code,10,20) as string;
51+
52+
Console.WriteLine($"Result: {result}");
53+
Console.WriteLine($"Error: {script.Error}");
54+
Console.WriteLine(script.ErrorMessage);
55+
Console.WriteLine(script.GeneratedClassCodeWithLineNumbers);
56+
57+
Assert.IsFalse(script.Error, script.ErrorMessage);
58+
Assert.IsTrue(result.Contains(" = 30"));
59+
```
60+
61+
### Executing a Method
62+
Another way to execute code is to provide a full method body which is a little more explicit and makes it easier to reference parameters passed in.
63+
64+
```csharp
65+
var script = new CSharpScriptExecution()
66+
{
67+
SaveGeneratedCode = true,
68+
CompilerMode = ScriptCompilerModes.Roslyn,
69+
GeneratedClassName = "HelloWorldTestClass"
70+
};
71+
script.AddDefaultReferencesAndNamespaces();
72+
73+
string code = $@"
74+
public string HelloWorld(string name)
75+
{{
76+
string result = $""Hello {{name}}. Time is: {{DateTime.Now}}."";
77+
return result;
78+
}}";
79+
80+
string result = script.ExecuteMethod(code,"HelloWorld","Rick") as string;
81+
82+
Console.WriteLine($"Result: {result}");
83+
Console.WriteLine($"Error: {script.Error}");
84+
Console.WriteLine(script.ErrorMessage);
85+
Console.WriteLine(script.GeneratedClassCode);
86+
87+
Assert.IsFalse(script.Error);
88+
Assert.IsTrue(result.Contains("Hello Rick"));
89+
```
90+
91+
### More than just a Single Method
92+
Note that you can provide more than a method in the code block - you can provide an entire **class body** including additional methods, properties/fields, events and so on. Effectively you can build out an entire class this way. After intial execution you can access the `ObjectInstance` member and use either Reflection or `dynamic` to access the functionality on that class.
93+
94+
```cs
95+
var script = new CSharpScriptExecution()
96+
{
97+
SaveGeneratedCode = true,
98+
CompilerMode = ScriptCompilerModes.Roslyn
99+
};
100+
script.AddDefaultReferencesAndNamespaces();
101+
102+
// Class body with multiple methods and properties
103+
string code = $@"
104+
public string HelloWorld(string name)
105+
{{
106+
string result = $""Hello {{name}}. Time is: {{DateTime.Now}}."";
107+
return result;
108+
}}
109+
110+
public string GoodbyeName {{ get; set; }}
111+
112+
public string GoodbyeWorld()
113+
{{
114+
string result = $""Goodbye {{GoodbyeName}}. Time is: {{DateTime.Now}}."";
115+
return result;
116+
}}
117+
";
118+
119+
string result = script.ExecuteMethod(code, "HelloWorld", "Rick") as string;
120+
121+
Console.WriteLine($"Result: {result}");
122+
Console.WriteLine($"Error: {script.Error}");
123+
Console.WriteLine(script.ErrorMessage);
124+
Console.WriteLine(script.GeneratedClassCode);
125+
126+
Assert.IsFalse(script.Error);
127+
Assert.IsTrue(result.Contains("Hello Rick"));
128+
129+
// You can pick up the ObjectInstance of the generated class
130+
// Make dynamic for easier access
131+
dynamic instance = script.ObjectInstance;
132+
133+
instance.GoodbyeName = "Markus";
134+
result = instance.GoodbyeWorld();
135+
136+
Console.WriteLine($"Result: {result}");
137+
Assert.IsTrue(result.Contains("Goodbye Markus"));
138+
```

README.md.saved.bak

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Westwind CSharp Scripting
2+
### Dynamically compile and execute CSharp code at runtime
3+
4+
This small `CSharpScripting` class provides an easy way to compile and execute C# on the fly at runtime using the .NET compiler services. This is ideal to provide support for addin's and application automation tasks that are user configurable.
5+
6+
The library supports both the latest Roslyn compiler and classic CSharp compilation.
7+
8+
> #### Requires Roslyn Code Providers for your Project
9+
> If you want to use Roslyn compilation you have to make sure you add the `Microsoft.CodeDom.CompilerServices` NuGet Package to your project to provide the required compiler binaries for your application. This should be added to the application's start project.
10+
>
11+
> Note that this adds a sizable chunk of files to your application's output folder in the `roslyn` folder. If you don't want this you can use the classic compiler, at the cost of not having access to C# 6+ features.
12+
13+
## Usage
14+
Using the `CSharpScriptExecution` class is very easy. It works by letting you provide either a simple code snippet that can optionally `return` a value, or a complete method signature with a method header and return statement. You can also provide multiple method that can be called explicitly using the `InvokeMethod()` operation.
15+
16+
You can add **Assembly References** and **Namespaces** via the `AddReferece()` and `AddNamespace()` methods.
17+
18+
Script Execution is gated rather than throwing directly to provide
19+
20+
### Executing a Code Snippet
21+
A code snippet can be **any block of .NET code** that can be executed. You can pass any number of parameters to the snippets which are accessible via a `parameters` object array. You can optionally `return` a value by providing a `return` statement.
22+
23+
24+
```cs
25+
var script = new CSharpScriptExecution()
26+
{
27+
SaveGeneratedCode = true,
28+
CompilerMode = ScriptCompilerModes.Roslyn
29+
};
30+
script.AddDefaultReferencesAndNamespaces();
31+
32+
//script.AddAssembly("Westwind.Utilities.dll");
33+
//script.AddNamespace("Westwind.Utilities");
34+
35+
var code = $@"
36+
// Check some C# 6+ lang features
37+
var s = new {{ name = ""Rick""}}; // anonymous types
38+
Console.WriteLine(s?.name); // null propagation
39+
40+
int num1 = (int)parameters[0];
41+
int num2 = (int)parameters[1];
42+
43+
// string templates
44+
var result = $""{{num1}} + {{num2}} = {{(num1 + num2)}}"";
45+
Console.WriteLine(result);
46+
47+
return result;
48+
";
49+
50+
string result = script.ExecuteCode(code,10,20) as string;
51+
52+
Console.WriteLine($"Result: {result}");
53+
Console.WriteLine($"Error: {script.Error}");
54+
Console.WriteLine(script.ErrorMessage);
55+
Console.WriteLine(script.GeneratedClassCodeWithLineNumbers);
56+
57+
Assert.IsFalse(script.Error, script.ErrorMessage);
58+
Assert.IsTrue(result.Contains(" = 30"));
59+
```
60+
61+
62+
### Executing a Method
63+
Another way to execute code is to provide a full method body which is a little more explicit and makes it easier to reference parameters passed in.
64+
65+
```csharp
66+
var script = new CSharpScriptExecution()
67+
{
68+
SaveGeneratedCode = true,
69+
CompilerMode = ScriptCompilerModes.Roslyn,
70+
GeneratedClassName = "HelloWorldTestClass"
71+
};
72+
script.AddDefaultReferencesAndNamespaces();
73+
74+
string code = $@"
75+
public string HelloWorld(string name)
76+
{{
77+
string result = $""Hello {{name}}. Time is: {{DateTime.Now}}."";
78+
return result;
79+
}}";
80+
81+
string result = script.ExecuteMethod(code,"HelloWorld","Rick") as string;
82+
83+
Console.WriteLine($"Result: {result}");
84+
Console.WriteLine($"Error: {script.Error}");
85+
Console.WriteLine(script.ErrorMessage);
86+
Console.WriteLine(script.GeneratedClassCode);
87+
88+
Assert.IsFalse(script.Error);
89+
Assert.IsTrue(result.Contains("Hello Rick"));
90+
```
91+
92+
### More than just a Single Method
93+
Note that you can provide more than a method in the code block - you can provide an entire **class body** including additional methods, properties/fields, events and so on. Effectively you can build out an entire class this way. After intial execution you can access the `ObjectInstance` member and use either Reflection or `dynamic` to access the functionality on that class.
94+
95+
```cs
96+
var script = new CSharpScriptExecution()
97+
{
98+
SaveGeneratedCode = true,
99+
CompilerMode = ScriptCompilerModes.Roslyn
100+
};
101+
script.AddDefaultReferencesAndNamespaces();
102+
103+
// Class body with multiple methods and properties
104+
string code = $@"
105+
public string HelloWorld(string name)
106+
{{
107+
string result = $""Hello {{name}}. Time is: {{DateTime.Now}}."";
108+
return result;
109+
}}
110+
111+
public string GoodbyeName {{ get; set; }}
112+
113+
public string GoodbyeWorld()
114+
{{
115+
string result = $""Goodbye {{GoodbyeName}}. Time is: {{DateTime.Now}}."";
116+
return result;
117+
}}
118+
";
119+
120+
string result = script.ExecuteMethod(code, "HelloWorld", "Rick") as string;
121+
122+
Console.WriteLine($"Result: {result}");
123+
Console.WriteLine($"Error: {script.Error}");
124+
Console.WriteLine(script.ErrorMessage);
125+
Console.WriteLine(script.GeneratedClassCode);
126+
127+
Assert.IsFalse(script.Error);
128+
Assert.IsTrue(result.Contains("Hello Rick"));
129+
130+
// You can pick up the ObjectInstance of the generated class
131+
// Make dynamic for easier access
132+
dynamic instance = script.ObjectInstance;
133+
134+
instance.GoodbyeName = "Markus";
135+
result = instance.GoodbyeWorld();
136+
137+
Console.WriteLine($"Result: {result}");
138+
Assert.IsTrue(result.Contains("Goodbye Markus"));
139+
```

Westwind.Scripting.Test/App.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<appSettings>
4+
<add key="aspnet:RoslynCompilerLocation" value="roslyn" />
5+
</appSettings>
6+
</configuration>

0 commit comments

Comments
 (0)