我正在并行运行一些单元测试。每个单元测试都会调用一些触发SSDT数据库项目的MSBuild部署的代码:
void Deploy(string projectPath, string publishProfilePath, ILogger logger)
{
var project = ProjectCollection.GlobalProjectCollection.LoadProject("projectPath);
Projects.SetGlobalProperty("Configuration", "Debug");
Projects.SetGlobalProperty("SqlPublishProfilePath", publishProfilePath);
var targets = new[] { "Build", "Publish" };
project.Build(targets, new[] { logger });
}
此方法的最后一行抛出InvalidOperationException
,并显示以下消息:
此集合是只读的。
这是调用堆栈跟踪的相关部分:
at Microsoft.Build.Shared.ErrorUtilities.ThrowInvalidOperation(String resourceName, Object[] args)
at Microsoft.Build.Collections.RetrievableEntryHashSet`1.AddEvenIfPresent(T value)
at Microsoft.Build.Evaluation.Project.Data.AddTarget(ProjectTargetInstance target)
at Microsoft.Build.Evaluation.Evaluator`4.ReadTargetElement(ProjectTargetElement targetElement, LinkedList`1 activeTargetsByEvaluationOrder, Dictionary`2 activeTargets)
at Microsoft.Build.Evaluation.Evaluator`4.Evaluate()
at Microsoft.Build.Evaluation.Evaluator`4.Evaluate(IEvaluatorData`4 data, ProjectRootElement root, ProjectLoadSettings loadSettings, Int32 maxNodeCount, PropertyDictionary`1 environmentProperties, ILoggingService loggingService, IItemFactory`2 itemFactory, IToolsetProvider toolsetProvider, ProjectRootElementCache projectRootElementCache, BuildEventContext buildEventContext, ProjectInstance projectInstanceIfAnyForDebuggerOnly)
at Microsoft.Build.Evaluation.Project.ReevaluateIfNecessary(ILoggingService loggingServiceForEvaluation)
at Microsoft.Build.Evaluation.Project.CreateProjectInstance(ILoggingService loggingServiceForEvaluation, ProjectInstanceSettings settings)
at Microsoft.Build.Evaluation.Project.Build(String[] targets, IEnumerable`1 loggers, IEnumerable`1 remoteLoggers)
at Microsoft.Build.Evaluation.Project.Build(String[] targets, IEnumerable`1 loggers)
Build
方法的文档似乎没有提到这一点。这段代码以前有用过。
答案 0 :(得分:0)
我怀疑MSBuild以这种方式不是线程安全的。
当我使用lock
阻止多次同时调用代码时,我的代码线程安全时不再出现问题:
void Deploy(string projectPath, string publishProfilePath, ILogger logger)
{
lock (deployLock)
{
//Implementation
}
}
object deployLock = new object();