Skip to content

Commit 9e9b2a1

Browse files
Merge pull request #661 from johelvisguzman/GH-660
(GH-660) Allow to configure json serializer, and added default settings when options not provided
2 parents b52c7a4 + d6fb03d commit 9e9b2a1

File tree

5 files changed

+111
-16
lines changed

5 files changed

+111
-16
lines changed

src/DotNetToolkit.Repository.AzureStorageBlob/DotNetToolkit.Repository.AzureStorageBlob.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<ItemGroup>
1313
<PackageReference Include="Azure.Storage.Blobs" Version="12.9.1" />
14+
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
1415
<PackageReference Include="System.Linq.Async" Version="5.0.0" />
1516
</ItemGroup>
1617

src/DotNetToolkit.Repository.AzureStorageBlob/Internal/AzureStorageBlobRepositoryContext.cs

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44
using Azure.Storage.Blobs;
55
using Configuration;
66
using Extensions;
7+
using Newtonsoft.Json;
78
using Properties;
89
using Query;
910
using Query.Strategies;
1011
using System;
1112
using System.Collections.Generic;
1213
using System.Data;
14+
using System.IO;
1315
using System.Linq;
1416
using System.Linq.Expressions;
17+
using System.Text;
1518
using System.Threading;
1619
using System.Threading.Tasks;
1720
using Utility;
@@ -22,17 +25,19 @@ internal class AzureStorageBlobRepositoryContext : LinqEnumerableRepositoryConte
2225

2326
private readonly IAzureStorageBlobContainerNameBuilder _containerNameBuilder;
2427
private readonly bool _createContainerIfNotExists;
28+
private readonly JsonSerializerSettings _serializerSettings;
2529

2630
#endregion
2731

2832
#region Constructors
2933

30-
public AzureStorageBlobRepositoryContext(string connectionString, IAzureStorageBlobContainerNameBuilder containerNameBuilder = null, bool createIfNotExists = false)
34+
public AzureStorageBlobRepositoryContext(string connectionString, IAzureStorageBlobContainerNameBuilder containerNameBuilder = null, bool createIfNotExists = false, JsonSerializerSettings serializerSettings = null)
3135
{
3236
Guard.NotEmpty(connectionString, nameof(connectionString));
3337

3438
_containerNameBuilder = containerNameBuilder ?? new DefaultContainerNameBuilder();
3539
_createContainerIfNotExists = createIfNotExists;
40+
_serializerSettings = serializerSettings;
3641

3742
Client = new BlobServiceClient(connectionString);
3843
}
@@ -41,6 +46,46 @@ public AzureStorageBlobRepositoryContext(string connectionString, IAzureStorageB
4146

4247
#region Private Methods
4348

49+
private JsonSerializer GetJsonSerializer()
50+
{
51+
var settings = _serializerSettings ?? new JsonSerializerSettings
52+
{
53+
Formatting = Formatting.Indented,
54+
ContractResolver = new DefaultJsonSerializeContractResolver(),
55+
PreserveReferencesHandling = PreserveReferencesHandling.None
56+
};
57+
58+
return JsonSerializer.Create(settings);
59+
}
60+
61+
private Stream Serialize<TEntity>(TEntity entity)
62+
{
63+
var serializer = GetJsonSerializer();
64+
var stream = new MemoryStream();
65+
66+
using (var sw = new StreamWriter(stream: stream, encoding: Encoding.UTF8, bufferSize: 4096, leaveOpen: true))
67+
using (var jsonTextWriter = new JsonTextWriter(sw))
68+
{
69+
serializer.Serialize(jsonTextWriter, entity);
70+
71+
sw.Flush();
72+
stream.Seek(0, SeekOrigin.Begin);
73+
74+
return stream;
75+
}
76+
}
77+
78+
private TEntity Deserialize<TEntity>(Stream stream)
79+
{
80+
var serializer = GetJsonSerializer();
81+
82+
using (var sr = new StreamReader(stream))
83+
using (var jsonTextReader = new JsonTextReader(sr))
84+
{
85+
return serializer.Deserialize<TEntity>(jsonTextReader);
86+
}
87+
}
88+
4489
private BlobContainerClient GetBlobContainer<TEntity>()
4590
{
4691
var container = _containerNameBuilder.Build<TEntity>();
@@ -72,7 +117,8 @@ private TEntity DownloadEntity<TEntity>(BlobContainerClient blobContainer, strin
72117
{
73118
var blob = blobContainer.GetBlobClient(blobName);
74119
var contentResult = blob.DownloadContent();
75-
var result = contentResult.Value.Content.ToObjectFromJson<TEntity>();
120+
var contentStream = contentResult.Value.Content.ToStream();
121+
var result = Deserialize<TEntity>(contentStream);
76122

77123
return result;
78124
}
@@ -117,7 +163,8 @@ private async Task<TEntity> DownloadEntityAsync<TEntity>(BlobContainerClient blo
117163
{
118164
var blob = blobContainer.GetBlobClient(blobName);
119165
var contentResult = await blob.DownloadContentAsync(cancellationToken);
120-
var result = contentResult.Value.Content.ToObjectFromJson<TEntity>();
166+
var contentStream = contentResult.Value.Content.ToStream();
167+
var result = Deserialize<TEntity>(contentStream);
121168

122169
return result;
123170
}
@@ -139,17 +186,23 @@ private async IAsyncEnumerable<TEntity> DownloadEntitiesAsync<TEntity>() where T
139186
private void UploadEntity<TEntity>(TEntity entity) where TEntity : class
140187
{
141188
var blob = GetBlobClient(entity);
142-
var binaryData = BinaryData.FromObjectAsJson<TEntity>(entity);
189+
using (var stream = Serialize<TEntity>(entity))
190+
{
191+
var binaryData = BinaryData.FromStream(stream);
143192

144-
blob.Upload(binaryData, overwrite: true);
193+
blob.Upload(binaryData, overwrite: true);
194+
}
145195
}
146196

147197
private async Task UploadEntityAsync<TEntity>(TEntity entity, CancellationToken cancellationToken = new CancellationToken()) where TEntity : class
148198
{
149199
var blob = await GetBlobClientAsync(entity);
150-
var binaryData = BinaryData.FromObjectAsJson<TEntity>(entity);
200+
using (var stream = Serialize<TEntity>(entity))
201+
{
202+
var binaryData = await BinaryData.FromStreamAsync(stream, cancellationToken);
151203

152-
await blob.UploadAsync(binaryData, overwrite: true, cancellationToken);
204+
await blob.UploadAsync(binaryData, overwrite: true, cancellationToken);
205+
}
153206
}
154207

155208
#endregion

src/DotNetToolkit.Repository.AzureStorageBlob/Internal/AzureStorageBlobRepositoryContextFactory.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace DotNetToolkit.Repository.AzureStorageBlob.Internal
22
{
33
using Configuration;
4+
using Newtonsoft.Json;
45
using Utility;
56

67
/// <summary>
@@ -14,6 +15,7 @@ internal class AzureStorageBlobRepositoryContextFactory : IRepositoryContextFact
1415
private readonly string _nameOrConnectionString;
1516
private readonly IAzureStorageBlobContainerNameBuilder _containerNameBuilder;
1617
private readonly bool _createIfNotExists;
18+
private readonly JsonSerializerSettings _serializerSettings;
1719

1820
#endregion
1921

@@ -25,42 +27,50 @@ internal class AzureStorageBlobRepositoryContextFactory : IRepositoryContextFact
2527
/// <param name="nameOrConnectionString">Either the database name or a connection string.</param>
2628
/// <param name="containerNameBuilder">The name of the container builder.</param>
2729
/// <param name="createIfNotExists">Creates the container if it does not exist.</param>
28-
public AzureStorageBlobRepositoryContextFactory(string nameOrConnectionString, IAzureStorageBlobContainerNameBuilder containerNameBuilder, bool createIfNotExists)
30+
/// <param name="serializerSettings">The serializer options to use when serializing to JSON.</param>
31+
public AzureStorageBlobRepositoryContextFactory(string nameOrConnectionString, IAzureStorageBlobContainerNameBuilder containerNameBuilder, bool createIfNotExists, JsonSerializerSettings serializerSettings = null)
2932
{
3033
_nameOrConnectionString = Guard.NotEmpty(nameOrConnectionString, nameof(nameOrConnectionString));
3134
_containerNameBuilder = Guard.NotNull(containerNameBuilder, nameof(containerNameBuilder));
3235
_createIfNotExists = createIfNotExists;
36+
_serializerSettings = serializerSettings;
3337
}
3438

3539
/// <summary>
3640
/// Initializes a new instance of the <see cref="AzureStorageBlobRepositoryContext" /> class.
3741
/// </summary>
3842
/// <param name="nameOrConnectionString">Either the database name or a connection string.</param>
3943
/// <param name="containerNameBuilder">The name of the container builder.</param>
40-
public AzureStorageBlobRepositoryContextFactory(string nameOrConnectionString, IAzureStorageBlobContainerNameBuilder containerNameBuilder)
44+
/// <param name="serializerSettings">The serializer options to use when serializing to JSON.</param>
45+
public AzureStorageBlobRepositoryContextFactory(string nameOrConnectionString, IAzureStorageBlobContainerNameBuilder containerNameBuilder, JsonSerializerSettings serializerSettings = null)
4146
{
4247
_nameOrConnectionString = Guard.NotEmpty(nameOrConnectionString, nameof(nameOrConnectionString));
4348
_containerNameBuilder = Guard.NotNull(containerNameBuilder, nameof(containerNameBuilder));
49+
_serializerSettings = serializerSettings;
4450
}
4551

4652
/// <summary>
4753
/// Initializes a new instance of the <see cref="AzureStorageBlobRepositoryContext" /> class.
4854
/// </summary>
4955
/// <param name="nameOrConnectionString">Either the database name or a connection string.</param>
5056
/// <param name="createIfNotExists">Creates the container if it does not exist.</param>
51-
public AzureStorageBlobRepositoryContextFactory(string nameOrConnectionString, bool createIfNotExists)
57+
/// <param name="serializerSettings">The serializer options to use when serializing to JSON.</param>
58+
public AzureStorageBlobRepositoryContextFactory(string nameOrConnectionString, bool createIfNotExists, JsonSerializerSettings serializerSettings = null)
5259
{
5360
_nameOrConnectionString = Guard.NotEmpty(nameOrConnectionString, nameof(nameOrConnectionString));
5461
_createIfNotExists = createIfNotExists;
62+
_serializerSettings = serializerSettings;
5563
}
5664

5765
/// <summary>
5866
/// Initializes a new instance of the <see cref="AzureStorageBlobRepositoryContext" /> class.
5967
/// </summary>
6068
/// <param name="nameOrConnectionString">Either the database name or a connection string.</param>
61-
public AzureStorageBlobRepositoryContextFactory(string nameOrConnectionString)
69+
/// <param name="serializerSettings">The serializer options to use when serializing to JSON.</param>
70+
public AzureStorageBlobRepositoryContextFactory(string nameOrConnectionString, JsonSerializerSettings serializerSettings = null)
6271
{
6372
_nameOrConnectionString = Guard.NotEmpty(nameOrConnectionString, nameof(nameOrConnectionString));
73+
_serializerSettings = serializerSettings;
6474
}
6575

6676
#endregion
@@ -73,7 +83,11 @@ public AzureStorageBlobRepositoryContextFactory(string nameOrConnectionString)
7383
/// <returns>The new repository context.</returns>
7484
public IRepositoryContext Create()
7585
{
76-
return new AzureStorageBlobRepositoryContext(_nameOrConnectionString, _containerNameBuilder, _createIfNotExists);
86+
return new AzureStorageBlobRepositoryContext(
87+
_nameOrConnectionString,
88+
_containerNameBuilder,
89+
_createIfNotExists,
90+
_serializerSettings);
7791
}
7892

7993
#endregion
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace DotNetToolkit.Repository.AzureStorageBlob.Internal
2+
{
3+
using Newtonsoft.Json;
4+
using Newtonsoft.Json.Serialization;
5+
using System.Reflection;
6+
7+
internal class DefaultJsonSerializeContractResolver : CamelCasePropertyNamesContractResolver
8+
{
9+
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
10+
{
11+
var property = base.CreateProperty(member, memberSerialization);
12+
13+
// Checks to see if this is a complex type
14+
if (((PropertyInfo)member).PropertyType.Namespace != "System")
15+
{
16+
property.Ignored = true;
17+
}
18+
19+
return property;
20+
}
21+
}
22+
}

src/DotNetToolkit.Repository.AzureStorageBlob/RepositoryOptionsBuilderExtensions.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Configuration.Options;
44
using Internal;
55
using JetBrains.Annotations;
6+
using Newtonsoft.Json;
67
using Utility;
78

89
/// <summary>
@@ -16,13 +17,15 @@ public static class RepositoryOptionsBuilderExtensions
1617
/// <param name="source">The repository options builder.</param>
1718
/// <param name="connectionString">The connection string.</param>
1819
/// <param name="createIfNotExists">Creates the container if it does not exist.</param>
20+
/// <param name="serializerSettings">The serializer options to use when serializing to JSON.</param>
1921
/// <returns>The same builder instance.</returns>
20-
public static RepositoryOptionsBuilder UseAzureStorageBlob([NotNull] this RepositoryOptionsBuilder source, [NotNull] string connectionString, bool createIfNotExists = false)
22+
public static RepositoryOptionsBuilder UseAzureStorageBlob([NotNull] this RepositoryOptionsBuilder source, [NotNull] string connectionString, bool createIfNotExists = false, JsonSerializerSettings serializerSettings = null)
2123
{
2224
Guard.NotNull(source, nameof(source));
2325
Guard.NotEmpty(connectionString, nameof(connectionString));
2426

25-
source.UseInternalContextFactory(new AzureStorageBlobRepositoryContextFactory(connectionString, createIfNotExists));
27+
source.UseInternalContextFactory(
28+
new AzureStorageBlobRepositoryContextFactory(connectionString, createIfNotExists, serializerSettings));
2629

2730
return source;
2831
}
@@ -34,14 +37,16 @@ public static RepositoryOptionsBuilder UseAzureStorageBlob([NotNull] this Reposi
3437
/// <param name="connectionString">The connection string.</param>
3538
/// <param name="containerNameBuilder">The name of the container builder.</param>
3639
/// <param name="createIfNotExists">Creates the container if it does not exist.</param>
40+
/// <param name="serializerSettings">The serializer options to use when serializing to JSON.</param>
3741
/// <returns>The same builder instance.</returns>
38-
public static RepositoryOptionsBuilder UseAzureStorageBlob([NotNull] this RepositoryOptionsBuilder source, [NotNull] string connectionString, IAzureStorageBlobContainerNameBuilder containerNameBuilder, bool createIfNotExists = false)
42+
public static RepositoryOptionsBuilder UseAzureStorageBlob([NotNull] this RepositoryOptionsBuilder source, [NotNull] string connectionString, IAzureStorageBlobContainerNameBuilder containerNameBuilder, bool createIfNotExists = false, JsonSerializerSettings serializerSettings = null)
3943
{
4044
Guard.NotNull(source, nameof(source));
4145
Guard.NotEmpty(connectionString, nameof(connectionString));
4246
Guard.NotNull(containerNameBuilder, nameof(containerNameBuilder));
4347

44-
source.UseInternalContextFactory(new AzureStorageBlobRepositoryContextFactory(connectionString, containerNameBuilder, createIfNotExists));
48+
source.UseInternalContextFactory(
49+
new AzureStorageBlobRepositoryContextFactory(connectionString, containerNameBuilder, createIfNotExists, serializerSettings));
4550

4651
return source;
4752
}

0 commit comments

Comments
 (0)