以编程方式调用EntityDeploy构建任务
我正在使用Roslyn编译,发出和运行C#源代码。 但是,当遇到使用EntityFramework的项目时,我遇到了限制。
似乎只是简单地发出编译是不够的,因为有一个EntityDeploy
构建任务在它们被发出后操纵它们。 (我相信它在发布后会在DLL中嵌入元数据工件)。
在我正在处理的.csproj
文件中,我看到以下实体部署任务:
EntityModelCodeGenerator Northwind.Designer.cs
是否可以直接调用此构建任务并操纵我发出的DLL?
注意:我不想简单地调用msbuild.exe
或在.csproj
文件中的所有内容上运行MSBuild
。 我正在构建的项目存在于内存中,但不存在于磁盘上,因此在我的情况下不起作用。
我尝试过的:
我正在尝试学习如何使用Microsoft.Build.Evaluation
东西。 我可以找到EntityDeploy任务,但我不知道如何调用它(以及我应该提供的参数)。
var project = new Project(@"C:\Users\JoshVarty\Documents\Visual Studio 2015\Projects\WebApplication1\WebApplication1\WebApplication1.csproj"); //Get the entity deploy target? I'm not sure if this is a task or target. var entityDeploy = project.Targets.Where(n => n.Key == "EntityDeploy").Single(); var projectTargetInstance = entityDeploy.Value;
我也尝试查看磁盘上存在的EntityDeploy
构建任务。
var entityDeployTask = new Microsoft.Data.Entity.Build.Tasks.EntityDeploy(); entityDeployTask.Sources = //I'm not sure where I can get the ITaskItem[] I need entityDeployTask.EntityDataModelEmbeddedResources = //I'm not sure where I can get the ITaskItem[] entityDeployTask.Execute();
我同时是MSBuild
, EntityFramework
和EntityDeploy
,所以如果我误用了条款或完全以错误的方式来解决这个问题,请纠正我。
我不熟悉EntityDeploy
,但我会提供一些我可能会帮助你的信息。
如果查看目标文件 ,可以看到EntityDeploy
目标依赖于EntityDeploy
, EntityDeploySplit
, EntityDeploySetLogicalNames
和EntityClean
任务 。
使用.edmx
文件列表调用EntityDeploy
目标时,会发生以下情况:
- 调用EntityDeploySplit ,它读取
.edmx
文件并确定处理每个文件的结果是应嵌入目标程序集中还是放在一起。 - 从1开始在NonEmbeddingItems上调用
NonEmbeddingItems
,它会拆分.edmx
文件并将结果放在OutputPath
- 从1开始在
EmbeddingItems
上调用EntityDeploy ,它会拆分.edmx
文件并将结果放在EntityDeployIntermediateResourcePath
- 在
EntityDeployIntermediateResourcePath
的文件上EntityDeployIntermediateResourcePath
,将每个文件上的元数据LogicalName
设置为用于嵌入的逻辑名称(它只是EntityDeployIntermediateResourcePath
文件的相对路径,斜点替换为点) - 调用EntityClean以删除中间文件
我没有试过这个,但应该可以按顺序调用这些来获得使用Engine类的预期行为:
// Instantiate a new Engine object Engine engine = new Engine(); // Point to the path that contains the .NET Framework 2.0 CLR and tools engine.BinPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.System) + @"\..\Microsoft.NET\Framework\v2.0.50727"; var entityDeploySplitTask = new EntityDeploySplit(); entityDeploySplitTask.Sources = new ITaskItem[] { new TaskItem("Model.edmx")// path to .edmx file from .csproj }; entityDeploySplitTask.BuildEngine = engine; entityDeploySplitTask.Execute(); var entityDeployTask = new EntityDeploy(); entityDeployTask.Sources = entityDeploySplitTask.NonEmbeddingItems entityDeployTask.OutputPath = "."; // path to the assembly output folder entityDeployTask.BuildEngine = engine; entityDeployTask.Execute(); var entityDeployTask2 = new EntityDeploy(); entityDeployTask2.Sources = entityDeploySplitTask.EmbeddingItems entityDeployTask2.OutputPath = "C:\Temp"; // path to an intermediate folder entityDeployTask2.BuildEngine = engine; entityDeployTask2.Execute(); var entityDeploySetLogicalTask = new EntityDeploySetLogicalNames(); entityDeploySetLogicalTask.Sources = Directory.EnumerateFiles("C:\Temp", "*.*", SearchOption.AllDirectories) .Select(f => new TaskItem(f)).ToArray(); entityDeploySetLogicalTask.ResourceOutputPath = "C:\Temp"; // path to the intermediate folder entityDeploySetLogicalTask.BuildEngine = engine; entityDeploySetLogicalTask.Execute(); foreach(var resourceFile in entityDeploySetLogicalTask.ResourcesToEmbed) { var fileName = resourceFile.GetMetadata("Identity"); var logicalName = resourceFile.GetMetadata("LogicalName"); //TODO: Embed filename using logicalName in the output assembly //You can embed them as normal resources by passing /resource to csc.exe //eg. /resource:obj\Debug\edmxResourcesToEmbed\Models\SampleEF.csdl,Models.SampleEF.csdl } //TODO: call EntityClean or just remove all files from the intermediate directory
请尝试以下方法:
var mockObject = new Mock(); IBuildEngine engine = mockObject.Object; var entityDeployTask = new EntityDeploy(); entityDeployTask.Sources = new ITaskItem[] { new TaskItem(@"path to edmx\Model1.edmx") }; entityDeployTask.OutputPath = @"C:\"; entityDeployTask.BuildEngine = engine; entityDeployTask.Execute();
输出路径似乎没有被拾取,但如果它是空的,则记录错误。 如果您实现自己的IBuildEngine
并记录错误,您可以看到这一点。 该过程的结果将是edmx旁边的三个文件:“Model1.ssdl”,“Model1.csdl”,“Model1.msdl”。 这些文件需要作为嵌入资源传递给CSC,至少原始目标文件似乎是这样做的。
希望它有所帮助,至少可以让你开始。