Skip to content

Commit 06cb290

Browse files
committed
Propagate BaseUrl property to generated http client
1 parent be6b98f commit 06cb290

11 files changed

Lines changed: 120 additions & 45 deletions

File tree

src/Dibix.Http.Client/Client/UriBuilder.cs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,52 +8,64 @@ namespace Dibix.Http.Client
88
{
99
public sealed class UriBuilder
1010
{
11-
private readonly string _url;
1211
private readonly UriKind _kind;
1312
private readonly IDictionary<string, ICollection<string>> _params;
13+
private string _url;
1414

1515
private UriBuilder(string url, UriKind kind)
1616
{
17-
this._url = url;
18-
this._kind = kind;
19-
this._params = new Dictionary<string, ICollection<string>>();
17+
_url = url;
18+
_kind = kind;
19+
_params = new Dictionary<string, ICollection<string>>();
2020
}
2121

2222
public static UriBuilder Create(string url, UriKind kind = UriKind.Absolute) => new UriBuilder(url, kind);
2323

24-
public UriBuilder AddQueryParam<T>(string name, T value) where T : struct => this.AddQueryParam(name, ToString(value));
24+
public UriBuilder AddPath(string path)
25+
{
26+
StringBuilder sb = new StringBuilder(_url);
27+
if (sb[^1] != '/')
28+
sb.Append('/');
29+
30+
sb.Append(path);
31+
32+
_url = sb.ToString();
33+
return this;
34+
}
35+
36+
public UriBuilder AddQueryParam<T>(string name, T value) where T : struct => AddQueryParam(name, ToString(value));
2537
public UriBuilder AddQueryParam<T>(string name, T value, T defaultValue) where T : struct => !Equals(value, defaultValue) ? AddQueryParam(name, ToString(value)) : this;
26-
public UriBuilder AddQueryParam<T>(string name, T? value) where T : struct => this.AddQueryParam(name, ToString(value));
38+
public UriBuilder AddQueryParam<T>(string name, T? value) where T : struct => AddQueryParam(name, ToString(value));
2739
public UriBuilder AddQueryParam<T>(string name, T? value, T? defaultValue) where T : struct => !Equals(value, defaultValue) ? AddQueryParam(name, ToString(value)) : this;
2840
public UriBuilder AddQueryParam(string name, string value, string defaultValue) => !Equals(value, defaultValue) ? AddQueryParam(name, ToString(value)) : this;
2941
public UriBuilder AddQueryParam(string name, string value)
3042
{
31-
if (!this._params.TryGetValue(name, out ICollection<string> values))
43+
if (!_params.TryGetValue(name, out ICollection<string> values))
3244
{
3345
values = new Collection<string>();
34-
this._params.Add(name, values);
46+
_params.Add(name, values);
3547
}
3648
values.Add(value);
3749
return this;
3850
}
3951
public UriBuilder AddQueryParam<T>(string name, IEnumerable<T> values)
4052
{
4153
foreach (T value in values)
42-
this.AddQueryParam(name, ToString(value));
54+
AddQueryParam(name, ToString(value));
4355

4456
return this;
4557
}
4658

4759
public Uri Build()
4860
{
49-
StringBuilder sb = new StringBuilder(this._url);
61+
StringBuilder sb = new StringBuilder(_url);
5062

51-
if (this._params.Any())
63+
if (_params.Any())
5264
{
5365
sb.Append('?');
5466

5567
bool firstParam = true;
56-
foreach (KeyValuePair<string, ICollection<string>> param in this._params)
68+
foreach (KeyValuePair<string, ICollection<string>> param in _params)
5769
{
5870
foreach (string value in param.Value)
5971
{
@@ -75,7 +87,7 @@ public Uri Build()
7587
}
7688

7789
string uri = sb.ToString();
78-
return new Uri(uri, this._kind);
90+
return new Uri(uri, _kind);
7991
}
8092

8193
private static string ToString<T>(T value)

src/Dibix.Sdk.Cli/Commands/Artifact/AbandonArtifactCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public AbandonArtifactCommand() : base("abandon", "Unlists NuGet package(s) from
2727
Arity = ArgumentArity.ZeroOrOne
2828
};
2929
_nuGetApiKeyOption = new EnvironmentVariableOption("--nuget-api-key", EnvironmentVariableName.NuGetPackageOfficialFeedApiKey, "The API key used to unlist the package(s) from the official feed.", "-n");
30-
_dockerHubUserNameOption = new EnvironmentVariableOption("--docker-hub-user", EnvironmentVariableName.DockerHubUserName, "The user name used to delete the docker image(s) from the Docker Hub.", "-u");
30+
_dockerHubUserNameOption = new EnvironmentVariableOption("--docker-hub-username", EnvironmentVariableName.DockerHubUserName, "The user name used to delete the docker image(s) from the Docker Hub.", "-u");
3131
_dockerHubPasswordOption = new EnvironmentVariableOption("--docker-hub-password", EnvironmentVariableName.DockerHubPassword, "The password used to delete the docker image(s) from the Docker Hub.", "-p");
3232
_dockerOrganizationOption = new Option<string>("--docker-organization", "-o")
3333
{

src/Dibix.Sdk.Cli/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"profiles": {
33
"Dibix.Sdk.Cli": {
44
"commandName": "Project",
5-
"commandLineArgs": "artifact abandon dibix-http-host"
5+
"commandLineArgs": "artifact deploy Dibix.Sdk"
66
}
77
}
88
}

src/Dibix.Sdk.Cli/Utilities/NuGetPackageExpander.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ public static void Expand(string packageName, string packageVersion, string nupk
3535
string targetPath = Path.GetFullPath(Path.Combine(targetDirectory, targetFileName));
3636
Directory.CreateDirectory(Path.GetDirectoryName(targetPath)!);
3737
entry.ExtractToFile(targetPath, overwrite: true);
38+
39+
// NuGet packs files using the source's UtcDateTime but stores it in the zip's DOS local-time slot (the ZIP format has no native UTC field).
40+
// ZipArchiveEntry.ExtractToFile reapplies the value as local time, which drifts the timestamp by the current UTC offset.
41+
// Re-tag the wall-clock face value as UTC and apply via SetLastWriteTimeUtc to round-trip the original instant, mirroring `nuget.exe add -Expand`.
42+
// See:
43+
// https://github.com/NuGet/Home/issues/7395
44+
// https://github.com/NuGet/Home/issues/5240
45+
File.SetLastWriteTimeUtc(targetPath, DateTime.SpecifyKind(entry.LastWriteTime.DateTime, DateTimeKind.Utc));
3846
}
3947

4048
string nupkgFileName = $"{idLower}.{packageVersion}.nupkg";

src/Dibix.Sdk.CodeGeneration/Output/ApiClientImplementationWriter.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,19 +131,22 @@ bool CollectParameter(ApiParameter parameter)
131131
writer.WriteLine($"using {nameof(HttpClient)} client = _httpClientFactory.CreateClient(_httpClientName);");
132132

133133
string uri = RouteBuilder.BuildRoute(context.Model.AreaName, controller.Name, action.ChildRoute);
134-
string uriConstant = $"\"{uri}\"";
135-
if (uriConstant.Contains('{'))
136-
uriConstant = $"${uriConstant}";
137-
138134
ICollection<ApiParameter> queryParameters = parameters.Where(x => x.ParameterLocation == ActionParameterLocation.Query)
139135
.ToArray();
140136

137+
string uriConstant;
141138
if (queryParameters.Any())
142139
{
143140
context.AddUsing("UriBuilder = Dibix.Http.Client.UriBuilder");
144141

145-
writer.WriteLine($"{nameof(Uri)} uri = UriBuilder.Create({uriConstant}, {nameof(UriKind)}.{nameof(UriKind.Relative)})")
146-
.SetTemporaryIndent(20);
142+
writer.WriteLine($"{nameof(Uri)} uri = UriBuilder.Create(HttpClientConstants.BaseUrl, {nameof(UriKind)}.{nameof(UriKind.Relative)})")
143+
.SetTemporaryIndent(20)
144+
.Write(".AddPath(");
145+
146+
if (uri.Contains('{'))
147+
writer.WriteRaw('$');
148+
149+
writer.WriteLineRaw($"\"{uri}\")");
147150

148151
foreach (ApiParameter parameter in queryParameters)
149152
{
@@ -166,6 +169,12 @@ bool CollectParameter(ApiParameter parameter)
166169

167170
uriConstant = "uri";
168171
}
172+
else
173+
{
174+
uriConstant = $$"""
175+
$"{HttpClientConstants.BaseUrl}/{{uri}}"
176+
""";
177+
}
169178

170179
writer.WriteLine($"{nameof(HttpRequestMessage)} requestMessage = new {nameof(HttpRequestMessage)}(new {nameof(HttpMethod)}(\"{action.Method.ToString().ToUpperInvariant()}\"), {uriConstant});");
171180

src/Dibix.Sdk.CodeGeneration/Output/ApiClientWriter.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,9 @@
88

99
namespace Dibix.Sdk.CodeGeneration
1010
{
11-
internal abstract class ApiClientWriter : ArtifactWriterBase
11+
internal abstract class ApiClientWriter : ClientWriter
1212
{
13-
#region Properties
14-
public override string LayerName => CodeGeneration.LayerName.Client;
15-
#endregion
16-
1713
#region Overrides
18-
public override bool HasContent(CodeGenerationModel model) => model.Controllers.Any();
19-
2014
public override void Write(CodeGenerationContext context)
2115
{
2216
context.AddUsing("Dibix.Http.Client");

src/Dibix.Sdk.CodeGeneration/Output/ClientCodeGenerator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ protected override IEnumerable<ArtifactWriterBase> SelectWriters(CodeGenerationM
1616
yield return new ClientContractClassWriter(model);
1717
yield return new ApiClientInterfaceWriter();
1818
yield return new ApiClientImplementationWriter();
19+
yield return new SharedApiConstantsWriter();
1920
}
2021

2122
protected override IEnumerable<CSharpGlobalAnnotation> CollectGlobalAnnotations(CodeGenerationModel model)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System.Linq;
2+
3+
namespace Dibix.Sdk.CodeGeneration
4+
{
5+
internal abstract class ClientWriter : ArtifactWriterBase
6+
{
7+
public override string LayerName => CodeGeneration.LayerName.Client;
8+
9+
public override bool HasContent(CodeGenerationModel model) => model.Controllers.Any();
10+
11+
}
12+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Dibix.Sdk.CodeGeneration.CSharp;
2+
3+
namespace Dibix.Sdk.CodeGeneration
4+
{
5+
internal sealed class SharedApiConstantsWriter : ClientWriter
6+
{
7+
#region Properties
8+
public override string RegionName => "Shared";
9+
#endregion
10+
11+
#region Overrides
12+
public override void Write(CodeGenerationContext context)
13+
{
14+
context.Namespace()
15+
.AddClass("HttpClientConstants", CSharpModifiers.Internal | CSharpModifiers.Static)
16+
.AddField("BaseUrl", "string", new CSharpValue($"\"{context.Model.BaseUrl}\""), CSharpModifiers.Public | CSharpModifiers.Const);
17+
}
18+
#endregion
19+
}
20+
}

tests/Dibix.Http.Client.Tests/UriBuilderTest.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ public sealed class UriBuilderTest
99
[TestMethod]
1010
public void CrossCheck()
1111
{
12-
Uri uri = UriBuilder.Create("some/kind/{of}/uri", UriKind.Relative)
12+
Uri uri = UriBuilder.Create("some", UriKind.Relative)
13+
.AddPath("kind/{of}/uri")
1314
.AddQueryParam("name", "luke")
1415
.AddQueryParam("id", (int?)null)
1516
.AddQueryParam("omitdefaultnullint", (int?)null, null)

0 commit comments

Comments
 (0)