栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

.net Core 3.1下的Roslyn 动态编译

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

.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 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 dicSourceContent,string projectName, out string ErrorMessage, string AppBasePath = null,  string[] AssemblyName = null)
        {
            bool buildResult = true;
            ErrorMessage = null;
            List 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 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;
        }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/910212.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号