.net Core 3.1下的Roslyn 动态编译

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;
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值