CSharpCodeProvider说是支持.net core 经过实验是不支持的,所以动态编译选择roslyn。
首先,我们需要建立一个项目 .net core ,nuget 安装Microsoft.CodeAnalysis.CSharp和 Microsoft.CodeAnalysis.CSharp.Workspaces.
哪我就直接上代码 就不多说 说一些遇到问题点
public static bool BuildAssembly(string TenancyFID, string codeStr, string assemblyName, string AppBasePath = null, string[] AssemblyName=null)
{
if (string.IsNullOrWhiteSpace(TenancyFID) || string.IsNullOrWhiteSpace(codeStr) || string.IsNullOrWhiteSpace(assemblyName))
{
return false;
}
if(AppBasePath==null)
{
AppBasePath = SystemParas.AppBasePath;
}
String path = AppBasePath + "/wwwroot/Tenancy/" + TenancyFID + "/DLL/";
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(codeStr);
try
{
string fileFullName = path + assemblyName + ".cs";// "生成cs文件的保存位置";
string dllFullName = path + assemblyName + ".dll";
if (Directory.Exists(path) == false)//如果不存
{
Directory.CreateDirectory(path);
}
if (File.Exists(fileFullName))
{
File.Delete(fileFullName);
}
File.WriteAllText(fileFullName, codeStr);
string[] refPaths=null;
if (AssemblyName != null && AssemblyName.Length > 0)
{
}
else
{
string basePath = Environment.CurrentDirectory + "\\refs";
if (Directory.Exists(basePath))//如果不存
{
DirectoryInfo root = new DirectoryInfo(basePath);
FileInfo[] files = root.GetFiles("*.dll");
refPaths = files.Select(x => x.FullName).ToArray();
}
else
{
refPaths = new string[0];
}
}
//相关的依赖dll加载,由于网上几个依赖的会缺少,我将所有的放到一个文件夹下面,再加载,当其他项目引用的时候就不会报错误。
MetadataReference[] references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray();
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: GetCompilationOption());
//EmitResult result = compilation.Emit(dllFullName);
using (MemoryStream dllStream = new MemoryStream())
using (MemoryStream pdbStream = new MemoryStream())
//通过这个win32的资源流来给动态编译的dll产生版本相关的文件信息【问题点,寻找很久才找到】
using (Stream win32resStream = compilation.CreateDefaultWin32Resources(
versionResource: true, // Important!
noManifest: false,
manifestContents: null,
iconInIcoFormat: null))
{
var result = compilation.Emit(
peStream: dllStream,
pdbStream: pdbStream,
win32Resources: win32resStream);
String outputMessage = "";
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
{
outputMessage += string.Format("\t{0}: {1}", diagnostic.Id, diagnostic.GetMessage()) + Environment.NewLine;//调试的最终输出信息
Logger.log.Warn("MrCompilation.AssemblyManager.BuildAssembly error:" + Environment.NewLine + outputMessage);
}
return false;
}
else
{
//ms.Seek(0, SeekOrigin.Begin);
File.WriteAllBytes(dllFullName, dllStream.ToArray());
}
}
}
catch (Exception ex)
{
Logger.log.Error("MrCompilation.AssemblyManager.BuildAssembly", ex);
return false;
}
return true;
}
依赖的dll 可以在vs 编译生产的 查看其应用的dll 再自己从目录复制出来如图所示
总结 一下 动态编译 出现问题,
1、编译成功,但是在引用的时候报缺少 一个dll,发现编译的默认继承 system.object类,而我们正常建的cs和编译出来的dll 是没有显示继承的。由于直接显示继承 就缺少哪个 dll。后来经过监控vs编译的过程 发现vs编译会从
2、问题生产的dll 没有版本号和相关信息
cs文件头部加入版本信息之后,在通过这样编译产生的文件就会有版本信息
using (Stream win32resStream = compilation.CreateDefaultWin32Resources(
versionResource: true, // Important!
noManifest: false,
manifestContents: null,
iconInIcoFormat: null))
{
var result = compilation.Emit(
peStream: dllStream,
pdbStream: pdbStream,
win32Resources: win32resStream);
3、考虑到多个cs文件,最好还是用一个工程来管理和编译
public static bool CreateProjectBuildAssembly(string TenancyFID,Dictionary<string,string> dicSourceContent,string projectName, out string ErrorMessage, string AppBasePath = null, string[] AssemblyName = null)
{
bool buildResult = true;
ErrorMessage = null;
List<string> refPaths=null;
if (AppBasePath == null || string.IsNullOrWhiteSpace(AppBasePath))
{
string refPath = SystemParas.AppBasePath + "\\refs";
if (Directory.Exists(refPath))//如果不存
{
DirectoryInfo root = new DirectoryInfo(refPath);
FileInfo[] files = root.GetFiles("*.dll");
refPaths = files.Select(x => x.FullName).ToList();
}
}
else
{
if (Directory.Exists(AppBasePath))//如果不存
{
DirectoryInfo root = new DirectoryInfo(AppBasePath);
FileInfo[] files = root.GetFiles("*.dll");
if (AssemblyName != null && AssemblyName.Length > 0)
{
refPaths = files.Where(m => AssemblyName.Contains(m.FullName)).Select(x => x.FullName).ToList();
}
else
{
refPaths = files.Select(x => x.FullName).ToList();
}
}
}
if(refPaths==null|| refPaths.Count<1)
{
return false;
}
string mrEntityDllPath = Assembly.GetExecutingAssembly().Location.Replace("MrCompilation.dll", "MrEntity.dll");
if (!refPaths.Contains(mrEntityDllPath))
{
refPaths.Add(mrEntityDllPath);
}
if(dicSourceContent.Keys.Count()<1)
{
return false;
}
MetadataReference[] references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray();
var adhoc = new AdhocWorkspace();
var solutionInfo = SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Default);
adhoc.AddSolution(solutionInfo);
var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Default, projectName, projectName, "C#")
.WithMetadataReferences(references)
.WithCompilationOptions(GetCompilationOption());
adhoc.AddProject(projectInfo);
var basePathCS = SystemParas.AppBasePath + "/wwwroot/Tenancy/" + TenancyFID + "/CS/";
foreach (var className in dicSourceContent.Keys)
{
var filePath = basePathCS + className + ".cs";
if (Directory.Exists(basePathCS) == false)//如果不存
{
Directory.CreateDirectory(basePathCS);
}
System.IO.File.WriteAllText(filePath, dicSourceContent[className]);
//SourceText sourceText = SourceText.From(sigleSource);
adhoc.AddDocument(projectInfo.Id, className+".cs", SourceText.From(dicSourceContent[className]));
}
var version1 = DateTime.UtcNow.Date.Subtract(DateTime.Parse("2000-01-01")).TotalDays.ToString("f0");
var version2 = DateTime.UtcNow.TimeOfDay.TotalSeconds.ToString("f0");
var versionStr = string.Format("1.0.{0}.{1}", version1, version2);
var versionInfo = AddVersionInfo(projectName, versionStr, versionStr, projectName, versionStr, "MR@Copyright");
adhoc.AddDocument(projectInfo.Id, "AssemblyInfo.cs", SourceText.From(versionInfo));
var project = adhoc.CurrentSolution.GetProject(projectInfo.Id);
var compilation = project.GetCompilationAsync().Result;
using (MemoryStream dllStream = new MemoryStream())
using (Stream win32resStream = compilation.CreateDefaultWin32Resources(
versionResource: true, // Important!
noManifest: false,
manifestContents: null,
iconInIcoFormat: null))
{
EmitResult result = compilation.Emit(dllStream, win32Resources: win32resStream);
if (!result.Success)
{
buildResult = false;
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
StringBuilder sboutputMessage = new StringBuilder();
foreach (Diagnostic diagnostic in failures)
{
sboutputMessage.AppendFormat("\t{0} {1}: {2}", diagnostic.Location.ToString(), diagnostic.Id, diagnostic.GetMessage()+ Environment.NewLine) ;//调试的最终输出信息
}
ErrorMessage = sboutputMessage.ToString();
Logger.log.Warn("MrCompilation.AssemblyManager.CreateProjectBuildAssembly error:" + Environment.NewLine + ErrorMessage);
}
else
{
var basePath = SystemParas.AppBasePath + "/wwwroot/Tenancy/" +TenancyFID+"/DLL/";
var filePath= basePath+ projectName + ".dll";
if (Directory.Exists(basePath) == false)//如果不存
{
Directory.CreateDirectory(basePath);
}
System.IO.File.WriteAllBytes(filePath, dllStream.ToArray());
}
}
return buildResult;
}