Skip to content

Commit 325a39c

Browse files
committed
Switch from int to long, use invariant culture, use singleton codec
1 parent e9435cf commit 325a39c

File tree

6 files changed

+34
-34
lines changed

6 files changed

+34
-34
lines changed

test/JsonApiDotNetCoreTests/IntegrationTests/IdObfuscation/BankAccountsController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
66

77
public sealed class BankAccountsController(
8-
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<BankAccount, int> resourceService)
8+
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<BankAccount, long> resourceService)
99
: ObfuscatedIdentifiableController<BankAccount>(options, resourceGraph, loggerFactory, resourceService);

test/JsonApiDotNetCoreTests/IntegrationTests/IdObfuscation/DebitCardsController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
66

77
public sealed class DebitCardsController(
8-
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<DebitCard, int> resourceService)
8+
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<DebitCard, long> resourceService)
99
: ObfuscatedIdentifiableController<DebitCard>(options, resourceGraph, loggerFactory, resourceService);

test/JsonApiDotNetCoreTests/IntegrationTests/IdObfuscation/HexadecimalCodec.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ internal sealed class HexadecimalCodec
1010
{
1111
// This implementation is deliberately simple for demonstration purposes.
1212
// Consider using something more robust, such as https://github.com/sqids/sqids-dotnet.
13+
public static HexadecimalCodec Instance { get; } = new();
1314

14-
public int Decode(string? value)
15+
private HexadecimalCodec()
16+
{
17+
}
18+
19+
public long Decode(string? value)
1520
{
1621
if (value == null)
1722
{
@@ -28,7 +33,7 @@ public int Decode(string? value)
2833
}
2934

3035
string stringValue = FromHexString(value[1..]);
31-
return int.Parse(stringValue);
36+
return long.Parse(stringValue, CultureInfo.InvariantCulture);
3237
}
3338

3439
private static string FromHexString(string hexString)
@@ -38,22 +43,22 @@ private static string FromHexString(string hexString)
3843
for (int index = 0; index < hexString.Length; index += 2)
3944
{
4045
string hexChar = hexString.Substring(index, 2);
41-
byte bt = byte.Parse(hexChar, NumberStyles.HexNumber);
46+
byte bt = byte.Parse(hexChar, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
4247
bytes.Add(bt);
4348
}
4449

4550
char[] chars = Encoding.ASCII.GetChars([.. bytes]);
4651
return new string(chars);
4752
}
4853

49-
public string? Encode(int value)
54+
public string? Encode(long value)
5055
{
5156
if (value == 0)
5257
{
5358
return null;
5459
}
5560

56-
string stringValue = value.ToString();
61+
string stringValue = value.ToString(CultureInfo.InvariantCulture);
5762
return $"x{ToHexString(stringValue)}";
5863
}
5964

@@ -63,7 +68,7 @@ private static string ToHexString(string value)
6368

6469
foreach (byte bt in Encoding.ASCII.GetBytes(value))
6570
{
66-
builder.Append(bt.ToString("X2"));
71+
builder.Append(bt.ToString("X2", CultureInfo.InvariantCulture));
6772
}
6873

6974
return builder.ToString();

test/JsonApiDotNetCoreTests/IntegrationTests/IdObfuscation/IdObfuscationTests.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ public sealed class IdObfuscationTests : IClassFixture<IntegrationTestContext<Te
1313
{
1414
private readonly IntegrationTestContext<TestableStartup<ObfuscationDbContext>, ObfuscationDbContext> _testContext;
1515
private readonly ObfuscationFakers _fakers = new();
16-
private readonly HexadecimalCodec _codec = new();
1716

1817
public IdObfuscationTests(IntegrationTestContext<TestableStartup<ObfuscationDbContext>, ObfuscationDbContext> testContext)
1918
{
@@ -34,7 +33,7 @@ public void Encodes_resource_ID()
3433
account.Id = 123;
3534

3635
// Act
37-
string? stringId = _codec.Encode(account.Id);
36+
string? stringId = HexadecimalCodec.Instance.Encode(account.Id);
3837

3938
// Assert
4039
stringId.Should().Be(account.StringId);
@@ -48,7 +47,7 @@ public void Decodes_resource_ID()
4847
account.Id = 123;
4948

5049
// Act
51-
int id = _codec.Decode(account.StringId);
50+
long id = HexadecimalCodec.Instance.Decode(account.StringId);
5251

5352
// Assert
5453
id.Should().Be(account.Id);
@@ -123,7 +122,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
123122
await dbContext.SaveChangesAsync();
124123
});
125124

126-
string route = $"/bankAccounts?filter=any(id,'{accounts[1].StringId}','{_codec.Encode(Unknown.TypedId.Int32)}')";
125+
string route = $"/bankAccounts?filter=any(id,'{accounts[1].StringId}','{HexadecimalCodec.Instance.Encode(Unknown.TypedId.Int64)}')";
127126

128127
// Act
129128
(HttpResponseMessage httpResponse, Document responseDocument) = await _testContext.ExecuteGetAsync<Document>(route);
@@ -362,7 +361,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
362361
value.Links.Related.Should().Be($"/debitCards/{newCardStringId}/account");
363362
});
364363

365-
int newCardId = _codec.Decode(responseDocument.Data.SingleValue.Id);
364+
long newCardId = HexadecimalCodec.Instance.Decode(responseDocument.Data.SingleValue.Id);
366365

367366
await _testContext.RunOnDatabaseAsync(async dbContext =>
368367
{
@@ -568,7 +567,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
568567
public async Task Cannot_delete_unknown_resource()
569568
{
570569
// Arrange
571-
string? stringId = _codec.Encode(Unknown.TypedId.Int32);
570+
string stringId = HexadecimalCodec.Instance.Encode(Unknown.TypedId.Int64)!;
572571

573572
string route = $"/bankAccounts/{stringId}";
574573

test/JsonApiDotNetCoreTests/IntegrationTests/IdObfuscation/ObfuscatedIdentifiable.cs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,15 @@
22

33
namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
44

5-
public abstract class ObfuscatedIdentifiable : Identifiable<int>
5+
public abstract class ObfuscatedIdentifiable : Identifiable<long>
66
{
7-
private static readonly HexadecimalCodec Codec = new();
8-
9-
protected override string? GetStringId(int value)
7+
protected override string? GetStringId(long value)
108
{
11-
return value == 0 ? null : Codec.Encode(value);
9+
return value == 0 ? null : HexadecimalCodec.Instance.Encode(value);
1210
}
1311

14-
protected override int GetTypedId(string? value)
12+
protected override long GetTypedId(string? value)
1513
{
16-
return value == null ? 0 : Codec.Decode(value);
14+
return value == null ? 0 : HexadecimalCodec.Instance.Decode(value);
1715
}
1816
}

test/JsonApiDotNetCoreTests/IntegrationTests/IdObfuscation/ObfuscatedIdentifiableController.cs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@
1111
namespace JsonApiDotNetCoreTests.IntegrationTests.IdObfuscation;
1212

1313
public abstract class ObfuscatedIdentifiableController<TResource>(
14-
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<TResource, int> resourceService)
15-
: BaseJsonApiController<TResource, int>(options, resourceGraph, loggerFactory, resourceService)
16-
where TResource : class, IIdentifiable<int>
14+
IJsonApiOptions options, IResourceGraph resourceGraph, ILoggerFactory loggerFactory, IResourceService<TResource, long> resourceService)
15+
: BaseJsonApiController<TResource, long>(options, resourceGraph, loggerFactory, resourceService)
16+
where TResource : class, IIdentifiable<long>
1717
{
18-
private readonly HexadecimalCodec _codec = new();
19-
2018
[HttpGet]
2119
[HttpHead]
2220
public override Task<IActionResult> GetAsync(CancellationToken cancellationToken)
@@ -28,7 +26,7 @@ public override Task<IActionResult> GetAsync(CancellationToken cancellationToken
2826
[HttpHead("{id}")]
2927
public Task<IActionResult> GetAsync([Required] string id, CancellationToken cancellationToken)
3028
{
31-
int idValue = _codec.Decode(id);
29+
long idValue = HexadecimalCodec.Instance.Decode(id);
3230
return base.GetAsync(idValue, cancellationToken);
3331
}
3432

@@ -37,7 +35,7 @@ public Task<IActionResult> GetAsync([Required] string id, CancellationToken canc
3735
public Task<IActionResult> GetSecondaryAsync([Required] string id, [Required] [PreserveEmptyString] string relationshipName,
3836
CancellationToken cancellationToken)
3937
{
40-
int idValue = _codec.Decode(id);
38+
long idValue = HexadecimalCodec.Instance.Decode(id);
4139
return base.GetSecondaryAsync(idValue, relationshipName, cancellationToken);
4240
}
4341

@@ -46,7 +44,7 @@ public Task<IActionResult> GetSecondaryAsync([Required] string id, [Required] [P
4644
public Task<IActionResult> GetRelationshipAsync([Required] string id, [Required] [PreserveEmptyString] string relationshipName,
4745
CancellationToken cancellationToken)
4846
{
49-
int idValue = _codec.Decode(id);
47+
long idValue = HexadecimalCodec.Instance.Decode(id);
5048
return base.GetRelationshipAsync(idValue, relationshipName, cancellationToken);
5149
}
5250

@@ -60,14 +58,14 @@ public override Task<IActionResult> PostAsync([FromBody] [Required] TResource re
6058
public Task<IActionResult> PostRelationshipAsync([Required] string id, [Required] [PreserveEmptyString] string relationshipName,
6159
[FromBody] [Required] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
6260
{
63-
int idValue = _codec.Decode(id);
61+
long idValue = HexadecimalCodec.Instance.Decode(id);
6462
return base.PostRelationshipAsync(idValue, relationshipName, rightResourceIds, cancellationToken);
6563
}
6664

6765
[HttpPatch("{id}")]
6866
public Task<IActionResult> PatchAsync([Required] string id, [FromBody] [Required] TResource resource, CancellationToken cancellationToken)
6967
{
70-
int idValue = _codec.Decode(id);
68+
long idValue = HexadecimalCodec.Instance.Decode(id);
7169
return base.PatchAsync(idValue, resource, cancellationToken);
7270
}
7371

@@ -76,22 +74,22 @@ public Task<IActionResult> PatchAsync([Required] string id, [FromBody] [Required
7674
public Task<IActionResult> PatchRelationshipAsync([Required] string id, [Required] [PreserveEmptyString] string relationshipName,
7775
[FromBody] [Required] object? rightValue, CancellationToken cancellationToken)
7876
{
79-
int idValue = _codec.Decode(id);
77+
long idValue = HexadecimalCodec.Instance.Decode(id);
8078
return base.PatchRelationshipAsync(idValue, relationshipName, rightValue, cancellationToken);
8179
}
8280

8381
[HttpDelete("{id}")]
8482
public Task<IActionResult> DeleteAsync([Required] string id, CancellationToken cancellationToken)
8583
{
86-
int idValue = _codec.Decode(id);
84+
long idValue = HexadecimalCodec.Instance.Decode(id);
8785
return base.DeleteAsync(idValue, cancellationToken);
8886
}
8987

9088
[HttpDelete("{id}/relationships/{relationshipName}")]
9189
public Task<IActionResult> DeleteRelationshipAsync([Required] string id, [Required] [PreserveEmptyString] string relationshipName,
9290
[FromBody] [Required] ISet<IIdentifiable> rightResourceIds, CancellationToken cancellationToken)
9391
{
94-
int idValue = _codec.Decode(id);
92+
long idValue = HexadecimalCodec.Instance.Decode(id);
9593
return base.DeleteRelationshipAsync(idValue, relationshipName, rightResourceIds, cancellationToken);
9694
}
9795
}

0 commit comments

Comments
 (0)