aspnetcore/Microsoft.AspNet.CoreServices/Compilation/CscBasedCompilationService.cs

114 lines
3.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Owin.FileSystems;
namespace Microsoft.AspNet.CoreServices
{
public class CscBasedCompilationService : ICompilationService
{
private static readonly string _tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
private readonly string _path;
public CscBasedCompilationService()
{
_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows),
@"Microsoft.NET\Framework\v4.0.30319\csc.exe");
}
public async Task<CompilationResult> Compile(IFileInfo fileInfo)
{
Directory.CreateDirectory(_tempDir);
string outFile = Path.Combine(_tempDir, Path.GetRandomFileName() + ".dll");
StringBuilder args = new StringBuilder("/target:library ");
args.AppendFormat("/out:\"{0}\" ", outFile);
foreach (var file in Directory.EnumerateFiles(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "*.dll"))
{
args.AppendFormat("/R:\"{0}\" ", file);
}
args.AppendFormat("\"{0}\"", fileInfo.PhysicalPath);
var outputStream = new MemoryStream();
// common execute
var process = CreateProcess(args.ToString());
int exitCode = await Start(process, outputStream);
string output = GetString(outputStream);
if (exitCode != 0)
{
IEnumerable<CompilationMessage> messages = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
.Skip(3)
.Select(e => new CompilationMessage(e));
return CompilationResult.Failed(String.Empty, messages);
}
var type = Assembly.LoadFrom(outFile)
.GetExportedTypes()
.First();
return CompilationResult.Successful(String.Empty, type);
}
private string GetString(MemoryStream stream)
{
if (stream.Length > 0)
{
return Encoding.UTF8.GetString(stream.GetBuffer(), 0, (int)stream.Length);
}
return String.Empty;
}
private static async Task<int> Start(Process process, Stream output)
{
var tcs = new TaskCompletionSource<int>();
process.EnableRaisingEvents = true;
process.Exited += (sender, eventArgs) =>
{
tcs.SetResult(process.ExitCode);
};
process.Start();
var copyTask = process.StandardOutput.BaseStream.CopyToAsync(output);
await Task.WhenAll(tcs.Task, copyTask);
return process.ExitCode;
}
internal Process CreateProcess(string arguments)
{
var psi = new ProcessStartInfo
{
FileName = _path,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
ErrorDialog = false,
Arguments = arguments
};
psi.StandardOutputEncoding = Encoding.UTF8;
psi.StandardErrorEncoding = Encoding.UTF8;
var process = new Process()
{
StartInfo = psi
};
return process;
}
}
}