以编程方式调用EntityDeploy构建任务

9
我正在使用Roslyn来编译、发出和运行C#源代码。然而,当遇到使用EntityFramework的项目时,我遇到了一些限制。
似乎仅仅发出编译不够,因为有一个名为EntityDeploy构建任务会在发出后操作DLL文件。(我相信它是在发出后将元数据工件嵌入DLL中)。
在我处理的.csproj文件中,我看到以下实体部署任务:
<EntityDeploy Include="Models\Northwind.edmx">
  <Generator>EntityModelCodeGenerator</Generator>
  <LastGenOutput>Northwind.Designer.cs</LastGenOutput>
</EntityDeploy>

这个构建任务是否可以直接调用并操作我发出的DLL呢?
注意:我不想简单地调用 msbuild.exe 或者 运行 MSBuild 来处理 .csproj 文件中的所有内容。我正在内存中构建项目,而不是在磁盘上,所以这种方法在我的情况下不适用。
我尝试过使用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();

我同时对MSBuildEntityFrameworkEntityDeploy都是新手,如果我使用术语不当或者完全错误,请纠正我。

2个回答

4
我不熟悉“EntityDeploy”,但我会提供一些信息,希望能对您有所帮助。
如果您查看目标文件,您可以看到有一个“EntityDeploy”目标,它依赖于“EntityDeploy”、“EntityDeploySplit”、“EntityDeploySetLogicalNames”和“EntityClean”任务。
当调用“EntityDeploy”目标时,使用“.edmx”文件列表执行以下操作:
  1. EntityDeploySplit被调用,读取“.edmx”文件,并确定是否将每个文件的处理结果嵌入到目标程序集中或与其并排放置。
  2. EntityDeploy在步骤1中的“NonEmbeddingItems”上被调用,它分割“.edmx”文件,并将结果放置在“OutputPath”中。
  3. EntityDeploy在步骤1中的“EmbeddingItems”上被调用,它分割“.edmx”文件,并将结果放置在“EntityDeployIntermediateResourcePath”中。
  4. EntityDeploySetLogicalNames被调用以设置在“EntityDeployIntermediateResourcePath”中的每个文件上的元数据“LogicalName”,该名称是嵌入时使用的逻辑名称(仅是相对于从“EntityDeployIntermediateResourcePath”开始的文件路径,其中斜杠被替换为点)。
  5. 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

1
尝试以下操作:
var mockObject = new Mock<IBuildEngine>();
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,至少原始targets文件似乎是这样做的。
希望这有所帮助,并至少让您开始了解。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接