Skip to content

Commit b9bff7d

Browse files
authored
Multi target type reuse (#5300)
* Support referenced assembly type reuse for multi-target project * Resolve reabse conflict. * rebase and fix test issue. * Apply workaround for reusing WindowsAppSDK pkg types in maui 7.0-xxx project * Rebase and resolve conflicts.
1 parent 8cfa29e commit b9bff7d

File tree

14 files changed

+448
-47
lines changed

14 files changed

+448
-47
lines changed

src/dotnet-svcutil/lib/src/Bootstrapper/SvcutilBootstrapper.cs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -123,22 +123,17 @@ internal async Task GenerateProjectAsync(bool keepBootstrapperDir, ILogger logge
123123
this.MSBuildProj = await MSBuildProj.DotNetNewAsync(projectFullPath, logger, cancellationToken).ConfigureAwait(false);
124124
this.MSBuildProj.AddDependency(svcutilPkgRef, true);
125125

126-
// Comment out code below for reasons: 1. it never used for .net core later than V2.1 since when the approach is always use TF from the generated project.
127-
// 2. with below code applied when target framework is netstandard2.0 client machine require netcoreapp2.0 (obsolete) for bootstrapper to work
128-
// 3. keep it here for future reference in case when we need definite bootstrapper TF version
129-
130-
// NOTE: If post v2.0 NetStandard ships a different version from NetCore the table below needs to be updated!
131-
//var targetFramework = frameworkInfo.FullName;
132-
//if (isSupportedTFM && frameworkInfo.IsKnownDnx)
133-
//{
134-
// if (frameworkInfo.Name == FrameworkInfo.Netstandard)
135-
// {
136-
// targetFramework = FrameworkInfo.Netcoreapp + TargetFrameworkHelper.NetStandardToNetCoreVersionMap[frameworkInfo.Version];
137-
// }
138-
// this.MSBuildProj.TargetFramework = targetFramework;
139-
//}
126+
var targetFramework = frameworkInfo.FullName;
127+
if (isSupportedTFM && frameworkInfo.Name != FrameworkInfo.Netstandard && frameworkInfo.Version.CompareTo(new Version(6, 0)) >= 0)
128+
{
129+
this.MSBuildProj.TargetFramework = targetFramework;
130+
if(targetFramework.ToLowerInvariant().Contains("net7.0-windows10"))
131+
{
132+
this.MSBuildProj.SetEnableMsixTooling();
133+
}
134+
}
140135
// else
141-
// The TFM is unknown: either, it was not provided or it is a version not yet known to the tool,
136+
// The TFM is Netstandard or version lower than 6.0 or unknown: either, it was not provided or it is a version not yet known to the tool,
142137
// we will use the default TF from the generated project.
143138
}
144139

src/dotnet-svcutil/lib/src/CodeDomFixup/WcfCodeGenerationExtension.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public void WsdlImported(WsdlImporter importer, Collection<ServiceEndpoint> endp
6262

6363
foreach (var binding in bindings)
6464
{
65-
if (binding is NetNamedPipeBinding && _options.Project != null && !_options.Project.TargetFrameworks.FirstOrDefault().ToLower().Contains("windows"))
65+
if (binding is NetNamedPipeBinding && _options.Project != null && !_options.Project.TargetFrameworks.Any(t => t.ToLower().Contains("windows")))
6666
{
6767
MetadataConversionError error = new MetadataConversionError(SR.WrnTargetFrameworkNotSupported_NetNamedPipe, isWarning: true);
6868
if (!importer.Errors.Contains(error))

src/dotnet-svcutil/lib/src/Shared/FrameworkInfo.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public static FrameworkInfo Parse(string fullFrameworkName)
4040
// framework spec form: 'net5.0'
4141
// framework spec form: '.NETCoreApp,Version=v6.0'
4242
// framework spec form: '.NETFramework,Version=v4.8'
43+
// framework spec form: 'net7.0-windows10.0.19041.0', 'net7.0-windows'
4344
for (int i = 0; i < fullFrameworkName.Length; i++)
4445
{
4546
char c = fullFrameworkName[i];
@@ -49,17 +50,25 @@ public static FrameworkInfo Parse(string fullFrameworkName)
4950

5051
// Version ctr requires at least Major and Minor parts
5152
string versionString = fullFrameworkName.Substring(i);
52-
if ((name == Netfx) && !versionString.Contains("."))
53+
if ((name == Netfx))
5354
{
5455
// net452
55-
StringBuilder sb = new StringBuilder(versionString);
56-
for (int j = 1; j < sb.Length; j += 2)
56+
if(!versionString.Contains("."))
5757
{
58-
sb.Insert(j, '.');
58+
StringBuilder sb = new StringBuilder(versionString);
59+
for (int j = 1; j < sb.Length; j += 2)
60+
{
61+
sb.Insert(j, '.');
62+
}
63+
versionString = sb.ToString();
5964
}
60-
versionString = sb.ToString();
65+
// net7.0-windows10.0.19041.0
66+
if (versionString.Contains("-"))
67+
{
68+
versionString = versionString.Substring(0, versionString.IndexOf("-"));
69+
}
6170
}
62-
71+
6372
version = new Version(versionString);
6473
break;
6574
}

src/dotnet-svcutil/lib/src/Shared/MSBuildProj.cs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -221,14 +221,9 @@ public static async Task<MSBuildProj> ParseAsync(string projectText, string proj
221221
if (targetFrameworksElements.Count() > 0)
222222
{
223223
var targetFrameworks = targetFrameworksElements.Last().Value;
224-
if (targetFrameworks.ToString().StartsWith("$"))
225-
{
226-
targetFrameworks = GetValueFromDirBuildProps(targetFrameworks, msbuildProj.DirectoryPath);
227-
}
228-
229224
foreach (var targetFx in targetFrameworks.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()))
230225
{
231-
if (!string.IsNullOrWhiteSpace(targetFx))
226+
if (!string.IsNullOrEmpty(targetFx) && !targetFx.ToString().StartsWith("$"))
232227
{
233228
msbuildProj._targetFrameworks.Add(targetFx);
234229
}
@@ -591,6 +586,14 @@ public bool AddDependency(ProjectDependency dependency, bool copyInternalAssets
591586
return addDependency;
592587
}
593588

589+
public void SetEnableMsixTooling()
590+
{
591+
// workaround for https://github.com/microsoft/WindowsAppSDK/issues/3548: dotnet build fails when WindowsAppSDK is referenced in console application.
592+
// affects MAUI project targeting net7.0-windows10.0xxx, not reproduce in net8.0-window10.0xxx
593+
// ref: https://github.com/dotnet/maui/issues/5886
594+
SetPropertyValue("EnableMsixTooling", "true");
595+
}
596+
594597
// Sets the property value in a PropertyGroup. Returns true if the value was changed, and false if it was already set to that value.
595598
private bool SetPropertyValue(string propertyName, string value)
596599
{
@@ -759,7 +762,7 @@ public async Task<IEnumerable<ProjectDependency>> ResolveProjectReferencesAsync(
759762

760763
using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Resolving project references ...").ConfigureAwait(false))
761764
{
762-
if (_targetFrameworks.Count == 1 && TargetFrameworkHelper.IsSupportedFramework(this.TargetFramework, out var frameworkInfo) && frameworkInfo.IsDnx)
765+
if (_targetFrameworks.Count >= 1 && TargetFrameworkHelper.IsSupportedFramework(this.TargetFramework, out var frameworkInfo) && frameworkInfo.IsDnx)
763766
{
764767
await this.RestoreAsync(logger, cancellationToken).ConfigureAwait(false);
765768

@@ -794,15 +797,17 @@ await AsyncHelper.RunAsync(async () =>
794797
try
795798
{
796799
var assetsFile = new FileInfo(Path.Combine(this.DirectoryPath, "obj", "project.assets.json")).FullName;
797-
if (File.Exists(assetsFile))
800+
if (File.Exists(assetsFile) && !(this.TargetFramework.Contains("-") && !this.TargetFramework.ToLower().Contains("windows")))
798801
{
799802
LockFile lockFile = LockFileUtilities.GetLockFile(assetsFile, logger as NuGet.Common.ILogger);
800-
801803
if (lockFile != null)
802804
{
803-
if (lockFile.Targets.Count == 1)
805+
LockFileTarget target = lockFile.Targets.Count == 1 ? lockFile.Targets[0] : lockFile.Targets.FirstOrDefault(t =>
806+
t.Name.StartsWith(this.TargetFramework, StringComparison.InvariantCultureIgnoreCase) //this.TargetFramework:net7.0-windows, targets:net7.0-windows7.0
807+
|| this.TargetFramework.StartsWith(t.Name, StringComparison.InvariantCultureIgnoreCase));//this.TargetFramework:net7.0-windows10.0.19041.0, targets:net7.0-windows10.0.19041
808+
if (target != null)
804809
{
805-
foreach (var lib in lockFile.Targets[0].Libraries)
810+
foreach (var lib in target.Libraries)
806811
{
807812
bool isPackage = StringComparer.OrdinalIgnoreCase.Compare(lib.Type, "package") == 0;
808813

@@ -970,7 +975,7 @@ public async Task<IEnumerable<KeyValuePair<string, string>>> ResolveProperyValue
970975

971976
if (propertyTable.Count() != propertyNames.Count())
972977
{
973-
propertyTable = await _propertyResolver.EvaluateProjectPropertiesAsync(this.FullPath, this.TargetFrameworks.FirstOrDefault(), propertyNames, this.GlobalProperties, logger, cancellationToken).ConfigureAwait(false);
978+
propertyTable = await _propertyResolver.EvaluateProjectPropertiesAsync(this.FullPath, this.TargetFramework, propertyNames, this.GlobalProperties, logger, cancellationToken).ConfigureAwait(false);
974979

975980
foreach (var entry in propertyTable)
976981
{
@@ -1000,7 +1005,7 @@ private async Task<string> ResolveDepsFilePathFromBuildConfigAsync(string output
10001005
{
10011006
var depsFiles = Directory.GetFiles(binFolder, "*", SearchOption.AllDirectories)
10021007
.Where(d => Path.GetFileName(d).Equals(fileName, RuntimeEnvironmentHelper.FileStringComparison))
1003-
.Where(f => PathHelper.GetFolderName(Path.GetDirectoryName(f)) == this.TargetFrameworks.FirstOrDefault())
1008+
.Where(f => PathHelper.GetFolderName(Path.GetDirectoryName(f)) == this.TargetFramework || Directory.GetParent(Directory.GetParent(f).FullName).Name == this.TargetFramework)
10041009
.Select(f => new FileInfo(f))
10051010
.OrderByDescending(f => f.CreationTimeUtc);
10061011

src/dotnet-svcutil/lib/src/Shared/TargetFrameworkHelper.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,6 @@ public static string GetBestFitTargetFramework(IEnumerable<string> targetFramewo
160160
}
161161
}
162162

163-
if (fxInfo != null)
164-
{
165-
return fxInfo.FullName;
166-
}
167-
168163
return targetFramework;
169164
}
170165

@@ -222,12 +217,6 @@ public static bool IsSupportedFramework(string fullFrameworkName, out FrameworkI
222217
{
223218
bool isSupported = false;
224219

225-
var tfx = fullFrameworkName.Split('-');
226-
if (tfx.Length > 1)
227-
{
228-
fullFrameworkName = tfx[0];
229-
}
230-
231220
if (FrameworkInfo.TryParse(fullFrameworkName, out frameworkInfo))
232221
{
233222
isSupported = (frameworkInfo.Name == FrameworkInfo.Netstandard && frameworkInfo.Version >= MinSupportedNetStandardVersion) ||
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by a tool.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
namespace ServiceReference
11+
{
12+
using System.Runtime.Serialization;
13+
14+
15+
[System.Diagnostics.DebuggerStepThroughAttribute()]
16+
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "99.99.99")]
17+
[System.Runtime.Serialization.DataContractAttribute(Name="TypeReuseCompositeType", Namespace="http://schemas.datacontract.org/2004/07/TypesLib")]
18+
public partial class TypeReuseCompositeType : object
19+
{
20+
21+
private bool BoolValueField;
22+
23+
private string StringValueField;
24+
25+
[System.Runtime.Serialization.DataMemberAttribute()]
26+
public bool BoolValue
27+
{
28+
get
29+
{
30+
return this.BoolValueField;
31+
}
32+
set
33+
{
34+
this.BoolValueField = value;
35+
}
36+
}
37+
38+
[System.Runtime.Serialization.DataMemberAttribute()]
39+
public string StringValue
40+
{
41+
get
42+
{
43+
return this.StringValueField;
44+
}
45+
set
46+
{
47+
this.StringValueField = value;
48+
}
49+
}
50+
}
51+
52+
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "99.99.99")]
53+
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference.ITypeReuseSvc")]
54+
public interface ITypeReuseSvc
55+
{
56+
57+
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ITypeReuseSvc/GetData", ReplyAction="http://tempuri.org/ITypeReuseSvc/GetDataResponse")]
58+
System.Threading.Tasks.Task<BinLib.BinLibrary> GetDataAsync(int value);
59+
60+
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ITypeReuseSvc/GetDataUsingDataContract", ReplyAction="http://tempuri.org/ITypeReuseSvc/GetDataUsingDataContractResponse")]
61+
System.Threading.Tasks.Task<ServiceReference.TypeReuseCompositeType> GetDataUsingDataContractAsync(ServiceReference.TypeReuseCompositeType composite);
62+
}
63+
64+
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "99.99.99")]
65+
public interface ITypeReuseSvcChannel : ServiceReference.ITypeReuseSvc, System.ServiceModel.IClientChannel
66+
{
67+
}
68+
69+
[System.Diagnostics.DebuggerStepThroughAttribute()]
70+
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "99.99.99")]
71+
public partial class TypeReuseSvcClient : System.ServiceModel.ClientBase<ServiceReference.ITypeReuseSvc>, ServiceReference.ITypeReuseSvc
72+
{
73+
74+
/// <summary>
75+
/// Implement this partial method to configure the service endpoint.
76+
/// </summary>
77+
/// <param name="serviceEndpoint">The endpoint to configure</param>
78+
/// <param name="clientCredentials">The client credentials</param>
79+
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);
80+
81+
public TypeReuseSvcClient() :
82+
base(TypeReuseSvcClient.GetDefaultBinding(), TypeReuseSvcClient.GetDefaultEndpointAddress())
83+
{
84+
this.Endpoint.Name = EndpointConfiguration.BasicHttpBinding_ITypeReuseSvc.ToString();
85+
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
86+
}
87+
88+
public TypeReuseSvcClient(EndpointConfiguration endpointConfiguration) :
89+
base(TypeReuseSvcClient.GetBindingForEndpoint(endpointConfiguration), TypeReuseSvcClient.GetEndpointAddress(endpointConfiguration))
90+
{
91+
this.Endpoint.Name = endpointConfiguration.ToString();
92+
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
93+
}
94+
95+
public TypeReuseSvcClient(EndpointConfiguration endpointConfiguration, string remoteAddress) :
96+
base(TypeReuseSvcClient.GetBindingForEndpoint(endpointConfiguration), new System.ServiceModel.EndpointAddress(remoteAddress))
97+
{
98+
this.Endpoint.Name = endpointConfiguration.ToString();
99+
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
100+
}
101+
102+
public TypeReuseSvcClient(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress) :
103+
base(TypeReuseSvcClient.GetBindingForEndpoint(endpointConfiguration), remoteAddress)
104+
{
105+
this.Endpoint.Name = endpointConfiguration.ToString();
106+
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
107+
}
108+
109+
public TypeReuseSvcClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
110+
base(binding, remoteAddress)
111+
{
112+
}
113+
114+
public System.Threading.Tasks.Task<BinLib.BinLibrary> GetDataAsync(int value)
115+
{
116+
return base.Channel.GetDataAsync(value);
117+
}
118+
119+
public System.Threading.Tasks.Task<ServiceReference.TypeReuseCompositeType> GetDataUsingDataContractAsync(ServiceReference.TypeReuseCompositeType composite)
120+
{
121+
return base.Channel.GetDataUsingDataContractAsync(composite);
122+
}
123+
124+
public virtual System.Threading.Tasks.Task OpenAsync()
125+
{
126+
return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(null, null), new System.Action<System.IAsyncResult>(((System.ServiceModel.ICommunicationObject)(this)).EndOpen));
127+
}
128+
129+
private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration)
130+
{
131+
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_ITypeReuseSvc))
132+
{
133+
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
134+
result.MaxBufferSize = int.MaxValue;
135+
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
136+
result.MaxReceivedMessageSize = int.MaxValue;
137+
result.AllowCookies = true;
138+
return result;
139+
}
140+
throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
141+
}
142+
143+
private static System.ServiceModel.EndpointAddress GetEndpointAddress(EndpointConfiguration endpointConfiguration)
144+
{
145+
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_ITypeReuseSvc))
146+
{
147+
return new System.ServiceModel.EndpointAddress("http://localhost:51074/TypeReuseSvc.svc");
148+
}
149+
throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
150+
}
151+
152+
private static System.ServiceModel.Channels.Binding GetDefaultBinding()
153+
{
154+
return TypeReuseSvcClient.GetBindingForEndpoint(EndpointConfiguration.BasicHttpBinding_ITypeReuseSvc);
155+
}
156+
157+
private static System.ServiceModel.EndpointAddress GetDefaultEndpointAddress()
158+
{
159+
return TypeReuseSvcClient.GetEndpointAddress(EndpointConfiguration.BasicHttpBinding_ITypeReuseSvc);
160+
}
161+
162+
public enum EndpointConfiguration
163+
{
164+
165+
BasicHttpBinding_ITypeReuseSvc,
166+
}
167+
}
168+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"providerId": "Microsoft.Tools.ServiceModel.Svcutil",
3+
"version": "99.99.99",
4+
"options": {
5+
"inputs": [
6+
"$testCasesPath$/wsdl/TypeReuseSvc.wsdl"
7+
],
8+
"namespaceMappings": [
9+
"*, ServiceReference"
10+
],
11+
"outputFile": "Reference.cs",
12+
"references": [
13+
"$TEMP$MultiTargetTypeReuse//TypeReuseClient//bin//Debug//net6.0//BinLib.dll"
14+
],
15+
"targetFramework": "N.N",
16+
"typeReuseMode": "All"
17+
}
18+
}

0 commit comments

Comments
 (0)