ОС: Windows 10 |.Net Core - 2.2.300 |Редактор кода Visual Studio Исходный код: https://github.com/CoviloMilos/CodeChallenge/tree/master/CodeCompiler/CodeCompilerAPI
Идея этого API заключается в получении запроса post с телом, в котором в качестве строки указан код c #. После этого я передаю этот строковый код c # классу Services / CompileService.cs, который выдает CSharpCompilation. Кроме того, если EmitResult успешен, я выполняю переданный код (точнее переданный метод) с различными типами входных параметров для этого метода. Все работает нормально, но проблема в том, что файл dll, созданный для хранения переданного кода C # и для CSharpCompilation, не может быть удален, потому что этот файл все еще используется. Я получаю сообщение об ошибке: (UnauthorizedAccessException: доступ к пути запрещен) . Моя идея заключается в том, что после компиляции и проверки кода внутри DLL-файла его следует удалить. Кроме того, я хотел создать сценарий, который принудительно удалял бы этот файл, но не пытался это сделать, потому что принудительное удаление с помощью PowerShell и CMD не работает.
using System.Collections;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using CodeCompilerAPI.Interfaces;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
namespace CodeCompilerAPI.Services
{
public class CompileService : ICompileService
{
//example of request body
/*public bool checkNum(int n) { if (n%2==0) { return true; }else { return false; }}*/
public Models.Task CompileCode(string inputCode, Models.Task task)
{
string code = @" using System;
namespace CodeCompilerAPI
{
public class Compile
{";
code += inputCode + "}}";
//Produces a syntax tree by parsing the source text.
var tree = SyntaxFactory.ParseSyntaxTree(code);
//name of file which will be used to store code
string fileName = "Temp" + DateTime.Now.ToString("dddd-dd-MMMM-yyyy-HH-mm-ss") + ".dll";
string path = Path.Combine(Directory.GetCurrentDirectory(), fileName);
var systemRefLocation = typeof(object).GetTypeInfo().Assembly.Location;
var systemReference = MetadataReference.CreateFromFile(systemRefLocation);
var compilation = CSharpCompilation.Create(fileName)
.WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
.AddReferences(systemReference)
.AddSyntaxTrees(tree);
EmitResult compilationResult = compilation.Emit(path);
if(compilationResult.Success)
{
Assembly asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
foreach (var testCase in task.Cases)
{
try{
System.Object result = executeCode(asm, testCase.FirstInputParameter, testCase.SecondInputParameter, task.MethodName, task.ReturnDataType, task.FirstInputParameterDataType, task.SecondInputParameterDataType);
switch (task.ReturnDataType)
{
case "bool":
if (bool.Parse(testCase.ValidReturnValue) == (bool) result)
testCase.CaseResult = true;
else
testCase.CaseResult = false;
break;
case "array":
var tempValidReturnValue = testCase.ValidReturnValue.Split(",").Select(x => Int32.Parse(x)).ToArray();
if (tempValidReturnValue.SequenceEqual(((IEnumerable)result).Cast<int>()) == true)
testCase.CaseResult = true;
break;
case "string":
var caseResult = string.Compare(testCase.ValidReturnValue, result.ToString());
testCase.CaseResult = caseResult == 0 ? true : false;
break;
}
string info = $"Test case num: {testCase.CaseNum.ToString()} \nTest case valid result: {testCase.ValidReturnValue.ToString()} \nActual test case result: {result.ToString()}";
Console.WriteLine(info);
}catch( Exception e) {
var helpLinks = e.HelpLink;
string issue = $"Message: {e.GetBaseException().ToString()}, \nHelp link: {e.HelpLink}";
Console.WriteLine(issue);
}
}
DeleteFile(fileName);
return task;
}
else
{
foreach (Diagnostic codeIssue in compilationResult.Diagnostics)
{
string issue = $"ID: {codeIssue.Id}, Message: {codeIssue.GetMessage()}, Location: {codeIssue.Location.GetLineSpan()}, Severity: {codeIssue.Severity}";
Console.WriteLine(issue);
}
DeleteFile(fileName);
return null;
}
}
private void DeleteFile(string fileName) {
var dir = new DirectoryInfo(Directory.GetCurrentDirectory().ToString());
foreach (var file in dir.EnumerateFiles("Temp*.dll")) {
if (file.Name != fileName)
file.Delete();
}
}
private System.Object executeCode(Assembly asm, string firstInputPara, string secondInputPara, string methodname, string returnDataType, string firstInputParaDataType, string secondInputParaDataType)
{
if (secondInputPara == null)
return asm.GetType("CodeCompilerAPI.Compile").GetMethod(methodname).Invoke(null, new object[] { parseInputParameter(firstInputParaDataType, firstInputPara) });
else if (secondInputPara != null)
return asm.GetType("CodeCompilerAPI.Compile").GetMethod(methodname).Invoke(null, new object[] { parseInputParameter(firstInputParaDataType, firstInputPara), parseInputParameter(secondInputParaDataType, secondInputPara)});
return null;
}
private System.Object parseInputParameter(string dataType, string inputParameter)
{
Object tempObj = new Object();
switch (dataType)
{
case "int":
tempObj = Int32.Parse(inputParameter);
break;
case "array":
tempObj = new int[inputParameter.Split(",").Length];
tempObj = Array.ConvertAll(inputParameter.Split(","), int.Parse);
break;
case "bool":
tempObj = Boolean.Parse(inputParameter);
break;
case "string":
tempObj = (String) inputParameter;
break;
default:
tempObj = null;
break;
}
return tempObj;
}
}
} ```
Can someone help me how to solve this problem? Is there any way to abort CSharpCompilation or force delete