以编程方式调用EntityDeploy构建任务 [英] Invoke EntityDeploy build task programatically

查看:142
本文介绍了以编程方式调用EntityDeploy构建任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Roslyn编译,发出和运行C#源代码。然而,当面对使用EntityFramework的项目时,我遇到了一个限制。



似乎简单地发出编译是不够的,因为有一个code> EntityDeploy 构建任务,它们在发布后操作DLL。 (我相信它们在发布后将DLL中的元数据工件嵌入)。



.csproj 文件我正在处理,我看到以下实体部署任务:

 < EntityDeploy Include =Models\Northwind.edmx > 
< Generator> EntityModelCodeGenerator< / Generator>
< LastGenOutput> Northwind.Designer.cs< / LastGenOutput>
< / EntityDeploy>

是否可以直接调用此构建任务并操作我发出的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); 
//获取实体部署目标?我不知道这是一个任务还是目标。
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 = //我不知道我可以在哪里得到ITaskItem []我需要
entityDeployTask.EntityDataModelEmbeddedResources = //我不知道我可以在哪里得到ITaskItem []
entityDeployTask.Execute();

我同时崭新的 MSBuild EntityFramework EntityDeploy ,所以请纠正我,如果我滥用条款或完全错误的方式。

解决方案

我不熟悉 EntityDeploy ,但我会给我一些可能会帮助你的信息。



如果你看看目标文件,您可以看到有一个 EntityDeploy 目标依赖于 EntityDeploy EntityDeploySplit EntityDeploySetLogicalNames EntityClean 任务



EntityDeploy 目标被调用,列表为 .edmx 文件发生以下情况:


  1. EntityDeploySplit 被调用,它读取 .edmx 文件,并确定处理每个文件的结果是否应嵌入到目标程序集中或放在旁边。

  2. EntityDeploy 在1. $ NonEmbeddingItems 之间调用,它将 .edmx 文件,并将结果放在 OutputPath

  3. EntityDeploy EmbeddingItems 从1.,它分割 .edmx 文件,并将结果放在 EntityDeployIntermediateResourcePath

  4. EntityDeploySetLogicalNames EntityDeployIntermediateResourcePath 将每个文件上的元数据 LogicalName 设置为要用于嵌入的逻辑名称(这只是文件的相对路径,来自 EntityDeployIntermediateResourcePath 以斜线替换为点)

  5. EntityClean 被删除中间文件

我没有尝试这样做,但应该可以按顺序调用这些,以使用引擎类

  //实例化一个新的引擎对象
引擎engine = new Engine();

//指向包含.NET Framework 2.0 CLR和工具的路径
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)// .csproj
}中的.edmx文件的路径;
entityDeploySplitTask.BuildEngine = engine;
entityDeploySplitTask.Execute();

var entityDeployTask = new EntityDeploy();
entityDeployTask.Sources = entityDeploySplitTask.NonEmbeddingItems
entityDeployTask.OutputPath =。; //程序集输出文件夹的路径
entityDeployTask.BuildEngine = engine;
entityDeployTask.Execute();

var entityDeployTask2 = new EntityDeploy();
entityDeployTask2.Sources = entityDeploySplitTask.EmbeddingItems
entityDeployTask2.OutputPath =C:\Temp; //中间文件夹的路径
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; //中间文件夹的路径
entityDeploySetLogicalTask​​.BuildEngine = engine;
entityDeploySetLogicalTask​​.Execute();

foreach(entityDeploySetLogicalTask​​.ResourcesToEmbed中的var resourceFile)
{
var fileName = resourceFile.GetMetadata(Identity);
var logicalName = resourceFile.GetMetadata(LogicalName);
// TODO:在输出程序集中嵌入使用logicalName的文件名
//您可以将它们作为普通资源嵌入到csc.exe
// eg中。 /resource:obj\Debug\edmxResourcesToEmbed\Models\SampleEF.csdl,Models.SampleEF.csdl
}

// TODO:调用EntityClean,或者只是删除所有文件中间目录


I'm using Roslyn to compile, emit and run C# source code. However, I've run into a limitation when faced with projects that use EntityFramework.

It seems that simply emitting the compilation isn't enough, as there is an EntityDeploy build task that manipulates the DLLs after they've been emitted. (I believe it is embedding Metadata Artifacts in the DLLs after they're emitted).

In the .csproj file I'm processing, I see the following entity deploy task:

<EntityDeploy Include="Models\Northwind.edmx">
  <Generator>EntityModelCodeGenerator</Generator>
  <LastGenOutput>Northwind.Designer.cs</LastGenOutput>
</EntityDeploy>

Is it possible to invoke this build task this directly and manipulate the DLLs I've emitted?

Note: I don't want to simply call msbuild.exe or run MSBuild on everything in the .csproj file. The projects I'm building exist in memory, but not on disk, so that won't work in my case.

What I've tried:

I'm trying to learn how to use the Microsoft.Build.Evaluation stuff. I can find the EntityDeploy task, but I'm at a loss for how to invoke it (and for what parameters I should be providing).

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;

I've also tried looking at the EntityDeploy build task as it exists on disk.

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();

I'm simultaneously brand new to MSBuild, EntityFramework and EntityDeploy, so please correct me if I've misused terms or come at this the wrong way altogether.

解决方案

I'm not familiar with EntityDeploy, but I'll give some information that I've gathered that might help you.

If you look at the targets file you can see that there's an EntityDeploy target which relies on EntityDeploy, EntityDeploySplit, EntityDeploySetLogicalNames and EntityClean tasks.

When the EntityDeploy target is called with list of .edmx files the following happens:

  1. EntityDeploySplit is invoked, it reads the .edmx files and determines whether the results from processing each one should be embedded in the target assembly or placed alongside.
  2. EntityDeploy is called on NonEmbeddingItems from 1., it splits the .edmx files and places the result in OutputPath
  3. EntityDeploy is called on EmbeddingItems from 1., it splits the .edmx files and places the result in EntityDeployIntermediateResourcePath
  4. EntityDeploySetLogicalNames is called on the files in EntityDeployIntermediateResourcePath to set the metadata LogicalName on each file to the logical name to be used for embedding (It's just the relative path to the file from EntityDeployIntermediateResourcePath with slashes replaced by dots)
  5. EntityClean is called to remove the intermediate files

I haven't tried this, but it should be possible to call these in sequence to get the expected behavior using the Engine class:

 // 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

这篇关于以编程方式调用EntityDeploy构建任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆