.net 在实施microsoft.build.utilities.task时,如何访问构建的各种环境变量?
在实施microsoft.build.utilities.task时,如何访问构建的各种环境变量 例如“TargetPath” 我知道我可以将它作为任务XML的一部分传入.net 在实施microsoft.build.utilities.task时,如何访问构建的各种环境变量?,.net,msbuild,msbuild-task,.net,Msbuild,Msbuild Task,在实施microsoft.build.utilities.task时,如何访问构建的各种环境变量 例如“TargetPath” 我知道我可以将它作为任务XML的一部分传入 <MyTask TargetPath="$(TargetPath)" /> 但是如果我可以访问代码中的变量,我不想强迫任务的使用者必须这样做 你不可能轻易做到这一点,你不应该这么做。任务不应该知道它的执行上下文,而应该使用它的输入参数 免责声明:不要这样做! 如果你真的想这样做,你需要用类似的东西重新分析项目
<MyTask TargetPath="$(TargetPath)" />
但是如果我可以访问代码中的变量,我不想强迫任务的使用者必须这样做
你不可能轻易做到这一点,你不应该这么做。任务不应该知道它的执行上下文,而应该使用它的输入参数 免责声明:不要这样做! 如果你真的想这样做,你需要用类似的东西重新分析项目文件
public override bool Execute()
{
string projectFile = BuildEngine.ProjectFileOfTaskNode;
Engine buildEngine = new Engine(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory());
Project project = new Project(buildEngine);
project.Load(projectFile);
foreach(var o in project.EvaluatedProperties)
{
// Use properties
}
// Do what you want
return true;
}
我想出了办法
public static class BuildEngineExtensions
{
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public;
public static IEnumerable GetEnvironmentVariable(this IBuildEngine buildEngine, string key,bool throwIfNotFound)
{
var projectInstance = GetProjectInstance(buildEngine);
var items = projectInstance.Items
.Where(x => string.Equals(x.ItemType, key, StringComparison.InvariantCultureIgnoreCase)).ToList();
if (items.Count > 0)
{
return items.Select(x => x.EvaluatedInclude);
}
var properties = projectInstance.Properties
.Where(x => string.Equals(x.Name, key, StringComparison.InvariantCultureIgnoreCase)).ToList();
if (properties.Count > 0)
{
return properties.Select(x => x.EvaluatedValue);
}
if (throwIfNotFound)
{
throw new Exception(string.Format("Could not extract from '{0}' environmental variables.", key));
}
return Enumerable.Empty();
}
static ProjectInstance GetProjectInstance(IBuildEngine buildEngine)
{
var buildEngineType = buildEngine.GetType();
var targetBuilderCallbackField = buildEngineType.GetField("targetBuilderCallback", bindingFlags);
if (targetBuilderCallbackField == null)
{
throw new Exception("Could not extract targetBuilderCallback from " + buildEngineType.FullName);
}
var targetBuilderCallback = targetBuilderCallbackField.GetValue(buildEngine);
var targetCallbackType = targetBuilderCallback.GetType();
var projectInstanceField = targetCallbackType.GetField("projectInstance", bindingFlags);
if (projectInstanceField == null)
{
throw new Exception("Could not extract projectInstance from " + targetCallbackType.FullName);
}
return (ProjectInstance)projectInstanceField.GetValue(targetBuilderCallback);
}
}
它可以这样使用
string targetPath = buildEngine.GetEnvironmentVariable("TargetPath", true).First();
string intermediateAssembly = buildEngine.GetEnvironmentVariable("IntermediateAssembly", true).First();
IEnumerable<string> referencePaths = buildEngine.GetEnvironmentVariable("ReferencePath", true);
string targetPath=buildEngine.GetEnvironmentVariable(“targetPath”,true).First();
字符串intermediateAssembly=buildEngine.GetEnvironmentVariable(“intermediateAssembly”,true).First();
IEnumerable ReferencePath=buildEngine.GetEnvironmentVariable(“ReferencePath”,true);
是的,这是一个丑陋的黑魔法,但它是有效的。我的情况是,当从msbuild调用SQLCMD脚本时,我需要为它构建一个参数列表;我们不希望每次SQL脚本作者需要传入新属性时都必须重新编写MsBuild任务。这很好地解决了这个问题。