Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ResolvePackageFileConflicts performance enhancements #1805

Merged
merged 6 commits into from
Dec 14, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 31 additions & 2 deletions src/Tasks/Common/ConflictResolution/ConflictItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ internal interface IConflictItem
Version FileVersion { get; }
string PackageId { get; }
string DisplayName { get; }

// NOTE: Technically this should be NuGetVersion because System.Version doesn't work with symver.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: s/symver/semver/

// However, the only scenarios we need to support this property for in conflict resolution is stable versions
// of System packages. PackageVersion will be null if System.Version can't parse the version (i.e. if is pre-release)
Version PackageVersion { get; }
}

// Wraps an ITask item and adds lazy evaluated properties used by Conflict resolution.
Expand Down Expand Up @@ -103,7 +108,7 @@ public string FileName
{
if (_fileName == null)
{
_fileName = OriginalItem == null ? String.Empty : OriginalItem.GetMetadata(MetadataNames.FileName) + OriginalItem.GetMetadata(MetadataNames.Extension);
_fileName = OriginalItem == null ? String.Empty : Path.GetFileName(OriginalItem.ItemSpec);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI - this change is unrelated to the package override work, but I saw roughly a 200ms gain in OrchardCore by making this change.

}
return _fileName;
}
Expand Down Expand Up @@ -165,7 +170,31 @@ public string PackageId
}
private set { _packageId = value; }
}


private bool _hasPackageVersion;
private Version _packageVersion;
public Version PackageVersion
{
get
{
if (!_hasPackageVersion)
{
_packageVersion = null;

var packageVersionString = OriginalItem?.GetMetadata(nameof(MetadataNames.NuGetPackageVersion)) ?? String.Empty;

if (packageVersionString.Length != 0)
{
Version.TryParse(packageVersionString, out _packageVersion);
}

// PackageVersion may be null but don't try to recalculate it
_hasPackageVersion = true;
}

return _packageVersion;
}
}

private string _sourcePath;
public string SourcePath
Expand Down
10 changes: 9 additions & 1 deletion src/Tasks/Common/ConflictResolution/ConflictResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ internal class ConflictResolver<TConflictItem> where TConflictItem : class, ICon
private Dictionary<string, TConflictItem> winningItemsByKey = new Dictionary<string, TConflictItem>();
private ILog log;
private PackageRank packageRank;
private PackageOverrideResolver<TConflictItem> packageOverrideResolver;

public ConflictResolver(PackageRank packageRank, ILog log)
public ConflictResolver(PackageRank packageRank, PackageOverrideResolver<TConflictItem> packageOverrideResolver, ILog log)
{
this.log = log;
this.packageRank = packageRank;
this.packageOverrideResolver = packageOverrideResolver;
}

public void ResolveConflicts(IEnumerable<TConflictItem> conflictItems, Func<TConflictItem, string> getItemKey,
Expand Down Expand Up @@ -87,6 +89,12 @@ public ConflictResolver(PackageRank packageRank, ILog log)

private TConflictItem ResolveConflict(TConflictItem item1, TConflictItem item2)
{
var winner = packageOverrideResolver.Resolve(item1, item2);
if (winner != null)
{
return winner;
}

string conflictMessage = string.Format(CultureInfo.CurrentCulture, Strings.EncounteredConflict,
item1.DisplayName,
item2.DisplayName);
Expand Down
1 change: 1 addition & 0 deletions src/Tasks/Common/ConflictResolution/MetadataNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ static class MetadataNames
public const string FileName = "FileName";
public const string HintPath = "HintPath";
public const string NuGetPackageId = "NuGetPackageId";
public const string NuGetPackageVersion = "NuGetPackageVersion";
public const string Path = "Path";
public const string Private = "Private";
public const string TargetPath = "TargetPath";
Expand Down
18 changes: 15 additions & 3 deletions src/Tasks/Common/ConflictResolution/ResolvePackageFileConflicts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ public class ResolvePackageFileConflicts : TaskBase
/// </summary>
public string[] PreferredPackages { get; set; }

/// <summary>
/// A collection of items that contain information of which packages get overriden
/// by which packages before doing any other conflict resolution.
/// </summary>
/// <remarks>
/// This is an optimizaiton so AssemblyVersions, FileVersions, etc. don't need to be read
/// in the default cases where platform packages (Microsoft.NETCore.App) should override specific packages
/// (System.Console v4.3.0).
/// </remarks>
public ITaskItem[] PackageOverrides { get; set; }

[Output]
public ITaskItem[] ReferencesWithoutConflicts { get; set; }

Expand All @@ -44,6 +55,7 @@ protected override void ExecuteCore()
{
var log = new MSBuildLog(Log);
var packageRanks = new PackageRank(PreferredPackages);
var packageOverrides = new PackageOverrideResolver<ConflictItem>(PackageOverrides);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much perf did you give back by creating this every time the task runs? I thought the version with a hard coded structure created every time was significantly slower than a static list.

The parsing logic looks very heavy on allocations: split, trim, tuple, yield.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My original mistake was doing the data creation in the ConflictResolver constructor, which is called 3x per invocation of the task. So that's why it came up when I profiled at that time (it was 3x what it needed to be).

I did some profiling of my current approach, and this creation takes <10% of the time of the new task. The real time left in the task (according to PerfView) is getting Item Metadata multiple times for every ConflictItem. This accounts for ~60% of the time of the new task according to the profiles I've looked at.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW - I've updated the original post with the perf numbers I'm seeing on my machine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'm satisfied. We can tune the rest if it ever it shows up and this is clearly a nice win already.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You made my realize that I should be lazy-loading this data for the case where there are no conflicts. No reason to build the dictionary up, until we need it. I've pushed a change for that.


// Treat assemblies from FrameworkList.xml as platform assemblies that also get considered at compile time
IEnumerable<ConflictItem> compilePlatformItems = null;
Expand All @@ -60,7 +72,7 @@ protected override void ExecuteCore()
// resolve conflicts at compile time
var referenceItems = GetConflictTaskItems(References, ConflictItemType.Reference).ToArray();

var compileConflictScope = new ConflictResolver<ConflictItem>(packageRanks, log);
var compileConflictScope = new ConflictResolver<ConflictItem>(packageRanks, packageOverrides, log);

compileConflictScope.ResolveConflicts(referenceItems,
ci => ItemUtilities.GetReferenceFileName(ci.OriginalItem),
Expand All @@ -74,7 +86,7 @@ protected override void ExecuteCore()
}

// resolve conflicts that class in output
var runtimeConflictScope = new ConflictResolver<ConflictItem>(packageRanks, log);
var runtimeConflictScope = new ConflictResolver<ConflictItem>(packageRanks, packageOverrides, log);

runtimeConflictScope.ResolveConflicts(referenceItems,
ci => ItemUtilities.GetReferenceTargetPath(ci.OriginalItem),
Expand All @@ -95,7 +107,7 @@ protected override void ExecuteCore()

// resolve conflicts with platform (eg: shared framework) items
// we only commit the platform items since its not a conflict if other items share the same filename.
var platformConflictScope = new ConflictResolver<ConflictItem>(packageRanks, log);
var platformConflictScope = new ConflictResolver<ConflictItem>(packageRanks, packageOverrides, log);
var platformItems = PlatformManifests?.SelectMany(pm => PlatformManifestReader.LoadConflictItems(pm.ItemSpec, log)) ?? Enumerable.Empty<ConflictItem>();

if (compilePlatformItems != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
<!--
***********************************************************************************************
Microsoft.NET.DefaultPackageConflictOverrides.targets

WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.

Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>

<ItemGroup Condition="'$(DisableDefaultPackageConflictOverrides)' != 'true'">
<PackageConflictOverrides Include="Microsoft.NETCore.App">
<OverridenPackages>
Microsoft.CSharp|4.4.0;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@weshaggard - is there a list I can compare these packages to for both NETCore.App and NETStandard? The tricky thing is which OOB packages need versions > 4.3.0.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do what just the latest versions? It would seem to make this a useful cache you would need all versions.

As for the list of them I think the best you can do is to provide the latest version of everything that lives in Microsoft.NETCore.App and lookup their latest version on nuget.org.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using a <= check. So if Microsoft.CSharp 4.1.0 package is encountered, it still loses to Microsoft.NETCore.App.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to be a little careful about that type of logic in servicing type of scenarios. During servicing we will have a 4.x.x that we might actually need to override what is in Microsoft.NETCore.App.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concretely, you mean we might ship a 4.3.1 Microsoft.CSharp that should override the 4.4.0 version inside Microsoft.NETCore.App 2.0.0?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess thinking about it a little more I think it is pretty unlikely to ship something that overrides the inbox Microsoft.NETCore.App from anything other then the release/2.0.0 branch (i.e. 4.4.x). So we need to at least ensure that these versions are somehow tied to a version of Microsoft.NETCore.App as well. As in we may very well want the 4.4.1 (if and when it ships) version of Microsoft.Csharp to win a conflict over the 2.0.0 Microsoft.NETCore.App but not for the 2.0.x and greater version that contains it.

I'm not sure how this affects, if at all, Microsoft.NETCore.App < 2.0.0, but we need to be sure that this doesn't start to throw out packages there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking is that these versions in the SDK won't change going forward. They are the "baseline".

We can do the following going forward in future versions of Microsoft.NETCore.App and/or NETStandard.Library:

  1. Provide higher version numbers to the existing packages, and add new packages. see MergePackageOverrides
  2. Set DisableDefaultPackageConflictOverrides=true and provide a whole new list of these packages and versions. Or set that boolean to turn this functionality off all together.
  3. Choose to not update these packages/versions in Microsoft.NETCore.App or NETStandard.Library. This won't cause any correctness issues, since this new check is only a performance optimization. If a higher Microsoft.CSharp package (say 4.4.1) conflicts with a future version of Microsoft.NETCore.App, then the existing AssemblyVersion and FileVersion checks will kick in and do the right thing. They will just happen to be a bit slower than these NuGet version checks.

I'm choosing to go with the last option for now, until we have data that proves we need to add those future versions to Microsoft.NETCore.App and/or NETStandard.Library. >90% of the conflicts are caused by packages that we aren't shipping new versions for (System.Runtime/Console/Collections/IO/etc). So even if we don't keep the OOB packages up-to-date, we still get a big perf win here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense to me.

I'm wondering if there can/should be a test to validate that all of these overrides behave the same as the fallback assemblyversion/fileversion checks. I'm imagining a test that generates a set of package references from the overrides and then we build with and it without DisableDefaultPackageConflictOverrides and check that we get the same @(Reference) and @(ReferenceCopyLocalPaths) both ways. You can get the overrides and the reference lists with GetValuesCommand.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how this affects, if at all, Microsoft.NETCore.App < 2.0.

I would think that none of the assets out of these packages would ever conflict with Microsoft.NETCore.App or NETStandard.Library < 2.0.0 and so there would be no impact there. Right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since < 2.0 were packages references nuget should unify the packages and so there shouldn't be a conflict but I not sure if there is any logic to always compare to what is part of Microsoft.NETCore.App so thought I would ask the question just to be sure others think about it as well.

Microsoft.Win32.Primitives|4.3.0;
Microsoft.Win32.Registry|4.4.0;
runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0;
runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0;
runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0;
runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0;
runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0;
runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple|4.3.0;
runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0;
runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0;
runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0;
runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0;
runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl|4.3.0;
System.AppContext|4.3.0;
System.Collections|4.3.0;
System.Collections.Concurrent|4.3.0;
System.Collections.Immutable|1.4.0;
System.Collections.NonGeneric|4.3.0;
System.Collections.Specialized|4.3.0;
System.ComponentModel|4.3.0;
System.ComponentModel.EventBasedAsync|4.3.0;
System.ComponentModel.Primitives|4.3.0;
System.ComponentModel.TypeConverter|4.3.0;
System.Console|4.3.0;
System.Data.Common|4.3.0;
System.Diagnostics.Contracts|4.3.0;
System.Diagnostics.Debug|4.3.0;
System.Diagnostics.FileVersionInfo|4.3.0;
System.Diagnostics.Process|4.3.0;
System.Diagnostics.StackTrace|4.3.0;
System.Diagnostics.TextWriterTraceListener|4.3.0;
System.Diagnostics.Tools|4.3.0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't a better place for this list be in Microsoft.NETCore.App itself? In fact we already provide the assembly list we should just be able to provide extra metadata for the version.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should ship any updates to this that way, but we need this to work on already shipped versions of these packages.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is definitely a better place, but we have already shipped Microsoft.NETCore.App 2.0.0 and NETStandard.Library 2.0.0. Thus we can't add this data to those packages.

This change allows data to come from those packages in the future, and that new data will either augment this (see MergePackageOverrides), or the future packages can turn the default data off all together by setting DisableDefaultPackageConflictOverrides and just provide its own data.

System.Diagnostics.TraceSource|4.3.0;
System.Diagnostics.Tracing|4.3.0;
System.Dynamic.Runtime|4.3.0;
System.Globalization|4.3.0;
System.Globalization.Extensions|4.3.0;
System.IO|4.3.0;
System.IO.Compression|4.3.0;
System.IO.Compression.ZipFile|4.3.0;
System.IO.FileSystem|4.3.0;
System.IO.FileSystem.AccessControl|4.4.0;
System.IO.FileSystem.DriveInfo|4.3.0;
System.IO.FileSystem.Primitives|4.3.0;
System.IO.FileSystem.Watcher|4.3.0;
System.IO.IsolatedStorage|4.3.0;
System.IO.MemoryMappedFiles|4.3.0;
System.IO.Pipes|4.3.0;
System.IO.UnmanagedMemoryStream|4.3.0;
System.Linq|4.3.0;
System.Linq.Expressions|4.3.0;
System.Linq.Queryable|4.3.0;
System.Net.Http|4.3.0;
System.Net.NameResolution|4.3.0;
System.Net.Primitives|4.3.0;
System.Net.Requests|4.3.0;
System.Net.Security|4.3.0;
System.Net.Sockets|4.3.0;
System.Net.WebHeaderCollection|4.3.0;
System.ObjectModel|4.3.0;
System.Private.DataContractSerialization|4.3.0;
System.Reflection|4.3.0;
System.Reflection.Emit|4.3.0;
System.Reflection.Emit.ILGeneration|4.3.0;
System.Reflection.Emit.Lightweight|4.3.0;
System.Reflection.Extensions|4.3.0;
System.Reflection.Metadata|1.5.0;
System.Reflection.Primitives|4.3.0;
System.Reflection.TypeExtensions|4.3.0;
System.Resources.ResourceManager|4.3.0;
System.Runtime|4.3.0;
System.Runtime.Extensions|4.3.0;
System.Runtime.Handles|4.3.0;
System.Runtime.InteropServices|4.3.0;
System.Runtime.InteropServices.RuntimeInformation|4.3.0;
System.Runtime.Loader|4.3.0;
System.Runtime.Numerics|4.3.0;
System.Runtime.Serialization.Formatters|4.3.0;
System.Runtime.Serialization.Json|4.3.0;
System.Runtime.Serialization.Primitives|4.3.0;
System.Security.AccessControl|4.4.0;
System.Security.Claims|4.3.0;
System.Security.Cryptography.Algorithms|4.3.0;
System.Security.Cryptography.Cng|4.4.0;
System.Security.Cryptography.Csp|4.3.0;
System.Security.Cryptography.Encoding|4.3.0;
System.Security.Cryptography.OpenSsl|4.4.0;
System.Security.Cryptography.Primitives|4.3.0;
System.Security.Cryptography.X509Certificates|4.3.0;
System.Security.Cryptography.Xml|4.4.0;
System.Security.Principal|4.3.0;
System.Security.Principal.Windows|4.4.0;
System.Text.Encoding|4.3.0;
System.Text.Encoding.Extensions|4.3.0;
System.Text.RegularExpressions|4.3.0;
System.Threading|4.3.0;
System.Threading.Overlapped|4.3.0;
System.Threading.Tasks|4.3.0;
System.Threading.Tasks.Extensions|4.3.0;
System.Threading.Tasks.Parallel|4.3.0;
System.Threading.Thread|4.3.0;
System.Threading.ThreadPool|4.3.0;
System.Threading.Timer|4.3.0;
System.ValueTuple|4.3.0;
System.Xml.ReaderWriter|4.3.0;
System.Xml.XDocument|4.3.0;
System.Xml.XmlDocument|4.3.0;
System.Xml.XmlSerializer|4.3.0;
System.Xml.XPath|4.3.0;
System.Xml.XPath.XDocument|4.3.0;
</OverridenPackages>
</PackageConflictOverrides>
<PackageConflictOverrides Include="NETStandard.Library">
<OverridenPackages>
Microsoft.Win32.Primitives|4.3.0;
System.AppContext|4.3.0;
System.Collections|4.3.0;
System.Collections.Concurrent|4.3.0;
System.Collections.Immutable|1.4.0;
System.Collections.NonGeneric|4.3.0;
System.Collections.Specialized|4.3.0;
System.ComponentModel|4.3.0;
System.ComponentModel.EventBasedAsync|4.3.0;
System.ComponentModel.Primitives|4.3.0;
System.ComponentModel.TypeConverter|4.3.0;
System.Console|4.3.0;
System.Data.Common|4.3.0;
System.Diagnostics.Contracts|4.3.0;
System.Diagnostics.Debug|4.3.0;
System.Diagnostics.FileVersionInfo|4.3.0;
System.Diagnostics.Process|4.3.0;
System.Diagnostics.StackTrace|4.3.0;
System.Diagnostics.TextWriterTraceListener|4.3.0;
System.Diagnostics.Tools|4.3.0;
System.Diagnostics.TraceSource|4.3.0;
System.Diagnostics.Tracing|4.3.0;
System.Dynamic.Runtime|4.3.0;
System.Globalization|4.3.0;
System.Globalization.Extensions|4.3.0;
System.IO|4.3.0;
System.IO.Compression|4.3.0;
System.IO.Compression.ZipFile|4.3.0;
System.IO.FileSystem|4.3.0;
System.IO.FileSystem.DriveInfo|4.3.0;
System.IO.FileSystem.Primitives|4.3.0;
System.IO.FileSystem.Watcher|4.3.0;
System.IO.IsolatedStorage|4.3.0;
System.IO.MemoryMappedFiles|4.3.0;
System.IO.Pipes|4.3.0;
System.IO.UnmanagedMemoryStream|4.3.0;
System.Linq|4.3.0;
System.Linq.Expressions|4.3.0;
System.Linq.Queryable|4.3.0;
System.Net.Http|4.3.0;
System.Net.NameResolution|4.3.0;
System.Net.Primitives|4.3.0;
System.Net.Requests|4.3.0;
System.Net.Security|4.3.0;
System.Net.Sockets|4.3.0;
System.Net.WebHeaderCollection|4.3.0;
System.ObjectModel|4.3.0;
System.Private.DataContractSerialization|4.3.0;
System.Reflection|4.3.0;
System.Reflection.Emit|4.3.0;
System.Reflection.Emit.ILGeneration|4.3.0;
System.Reflection.Emit.Lightweight|4.3.0;
System.Reflection.Extensions|4.3.0;
System.Reflection.Primitives|4.3.0;
System.Reflection.TypeExtensions|4.3.0;
System.Resources.ResourceManager|4.3.0;
System.Runtime|4.3.0;
System.Runtime.Extensions|4.3.0;
System.Runtime.Handles|4.3.0;
System.Runtime.InteropServices|4.3.0;
System.Runtime.InteropServices.RuntimeInformation|4.3.0;
System.Runtime.Loader|4.3.0;
System.Runtime.Numerics|4.3.0;
System.Runtime.Serialization.Formatters|4.3.0;
System.Runtime.Serialization.Json|4.3.0;
System.Runtime.Serialization.Primitives|4.3.0;
System.Security.AccessControl|4.4.0;
System.Security.Claims|4.3.0;
System.Security.Cryptography.Algorithms|4.3.0;
System.Security.Cryptography.Csp|4.3.0;
System.Security.Cryptography.Encoding|4.3.0;
System.Security.Cryptography.Primitives|4.3.0;
System.Security.Cryptography.X509Certificates|4.3.0;
System.Security.Cryptography.Xml|4.4.0;
System.Security.Principal|4.3.0;
System.Security.Principal.Windows|4.4.0;
System.Text.Encoding|4.3.0;
System.Text.Encoding.Extensions|4.3.0;
System.Text.RegularExpressions|4.3.0;
System.Threading|4.3.0;
System.Threading.Overlapped|4.3.0;
System.Threading.Tasks|4.3.0;
System.Threading.Tasks.Extensions|4.3.0;
System.Threading.Tasks.Parallel|4.3.0;
System.Threading.Thread|4.3.0;
System.Threading.ThreadPool|4.3.0;
System.Threading.Timer|4.3.0;
System.ValueTuple|4.3.0;
System.Xml.ReaderWriter|4.3.0;
System.Xml.XDocument|4.3.0;
System.Xml.XmlDocument|4.3.0;
System.Xml.XmlSerializer|4.3.0;
System.Xml.XPath|4.3.0;
System.Xml.XPath.XDocument|4.3.0;
</OverridenPackages>
</PackageConflictOverrides>
</ItemGroup>
</Project>
Loading