Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
TheByteStuff committed Aug 3, 2023
1 parent 8b089e2 commit d354119
Show file tree
Hide file tree
Showing 12 changed files with 656 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.gitignore.bak
README.md.bak
LICENSE.bak
.vs
src/.axoCover
src/.vs
src/AzureTableEntityJsonSerializer/bin
src/AzureTableEntityJsonSerializer/obj
src/AAzureTableEntityJsonSerializerXUnitTest/bin
src/AAzureTableEntityJsonSerializerXUnitTest/obj
*.cache
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# TheByteStuff.AzureTableEntityJsonSerializer

[![Join the chat at https://gitter.im/TheByteStuff/AzureTableUtilities](https://badges.gitter.im/TheByteStuff/AzureTableUtilities.svg)](https://gitter.im/TheByteStuff/AzureTableUtilities?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)


AzureTableEntityJsonSerializer/Deserializer for use with Azure.Data.Tables TableEntity.

Based on the nuget package offered by DoguArslan (https://www.nuget.org/packages/DynamicTableEntityJsonSerializer) which uses Microsoft.WindowsAzure.Storage.Table and .Net Framework 4.5, this package is adapted from the original work to function using Azure.Data.Tables TableEntity and a broader .NetStandard 2.1. The serialization offered under stock Azure.Data.Tables converts Int32 to Int64 upon reserialziation, this serializer preserves Int32.


The Byte Stuff, LLC is not affiliated with Microsoft nor the original author nor have either endorsed this project.

Personal and commercial use of this software is free; however, a donation is appreciated if you find the software useful.

Suggestions or donations are both appreciated and welcome can be made by using the [Contact tab](https://www.thebytestuff.com/Contact?utm_source=nuget&utm_medium=www&utm_campaign=AzureTableEntityJsonSerializer).
31 changes: 31 additions & 0 deletions src/AzureTableEntityJsonSerializer.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.1267
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureTableEntityJsonSerializer", "AzureTableEntityJsonSerializer\AzureTableEntityJsonSerializer.csproj", "{8A794B8D-C110-4B4F-8DF9-8FDCF4EAFBB9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureTableEntityJsonSerializerXUnitTest", "AzureTableEntityJsonSerializerXUnitTest\AzureTableEntityJsonSerializerXUnitTest.csproj", "{782B9675-13D0-40C3-B776-2BEF7D996CC1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8A794B8D-C110-4B4F-8DF9-8FDCF4EAFBB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A794B8D-C110-4B4F-8DF9-8FDCF4EAFBB9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A794B8D-C110-4B4F-8DF9-8FDCF4EAFBB9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A794B8D-C110-4B4F-8DF9-8FDCF4EAFBB9}.Release|Any CPU.Build.0 = Release|Any CPU
{782B9675-13D0-40C3-B776-2BEF7D996CC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{782B9675-13D0-40C3-B776-2BEF7D996CC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{782B9675-13D0-40C3-B776-2BEF7D996CC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{782B9675-13D0-40C3-B776-2BEF7D996CC1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DC9F7673-78DC-4829-BB3E-00C1E080B5E0}
EndGlobalSection
EndGlobal
200 changes: 200 additions & 0 deletions src/AzureTableEntityJsonSerializer/AzureTableEntityJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Azure.Data.Tables;

namespace TheByteStuff.AzureTableEntityJsonSerializer
{
/// <summary>
/// Based on classes from https://www.nuget.org/packages/DynamicTableEntityJsonSerializer/1.0.0
/// </summary>
public class AzureTableEntityJsonConverter : JsonConverter
{
private const int EntityPropertyIndex = 0;
private const int EntityPropertyEdmTypeIndex = 1;
private readonly List<string> excludedProperties;

private static List<string> excludedKeys = new List<string> { "PartitionKey", "RowKey", "Timestamp", "ETag" };

public AzureTableEntityJsonConverter(List<string> excludedProperties = null)
{
this.excludedProperties = excludedProperties;
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
return;
writer.WriteStartObject();
AzureTableEntityJsonConverter.WriteJsonProperties(writer, (TableEntity)value, this.excludedProperties);
writer.WriteEndObject();
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return (object)null;
TableEntity dynamicTableEntity = new TableEntity();

using (List<JProperty>.Enumerator enumerator = JObject.Load(reader).Properties().ToList<JProperty>().GetEnumerator())
{
while (enumerator.MoveNext())
{
JProperty current = enumerator.Current;
if (string.Equals(current.Name, "PartitionKey", StringComparison.Ordinal))
dynamicTableEntity.PartitionKey = ((object)current.Value).ToString();
else if (string.Equals(current.Name, "RowKey", StringComparison.Ordinal))
dynamicTableEntity.RowKey = ((object)current.Value).ToString();
else if (string.Equals(current.Name, "Timestamp", StringComparison.Ordinal))
dynamicTableEntity.Timestamp = (DateTimeOffset)current.Value.ToObject<DateTimeOffset>(serializer);
else if (string.Equals(current.Name, "ETag", StringComparison.Ordinal))
{
dynamicTableEntity.ETag = new Azure.ETag(current.Value.ToString());
}
else
{
KeyValuePair<string, object> data = AzureTableEntityJsonConverter.CreateKeyValue(serializer, current);
dynamicTableEntity.Add(data.Key, data.Value);
}
}
}
return (object)dynamicTableEntity;
}

public override bool CanConvert(Type objectType)
{
return typeof(TableEntity).IsAssignableFrom(objectType);
}

private static void WriteJsonProperties(
JsonWriter writer,
TableEntity entity,
List<string> excludedProperties = null)
{
if (entity == null)
return;
writer.WritePropertyName("PartitionKey");
writer.WriteValue(entity.PartitionKey);
writer.WritePropertyName("RowKey");
writer.WriteValue(entity.RowKey);
writer.WritePropertyName("Timestamp");
writer.WriteValue(entity.Timestamp);
for (int j = 0; j < entity.Count; j++)
{
string ValueType = entity.ElementAt(j).Value.GetType().Name;


if (excludedKeys.Contains(entity.ElementAt(j).Key))
{

}
else
{
EntityProperty ep = new EntityProperty(entity.ElementAt(j), EntityProperty.StringToType(ValueType)); // EntityProperty.EntityPropertyType.String);
AzureTableEntityJsonConverter.WriteJsonProperty(writer, entity.ElementAt(j), EntityProperty.StringToType(ValueType));
}
}

}

private static void WriteJsonProperty(
JsonWriter writer,
KeyValuePair<string, object> property,
EntityProperty.EntityPropertyType type)
{
//https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonToken.htm
if (string.IsNullOrWhiteSpace(property.Key) || property.Value == null)
return;
switch ((int)type)
{
case 0:
AzureTableEntityJsonConverter.WriteJsonPropertyWithEdmType(writer, property.Key, (object)property.Value, EntityProperty.EntityPropertyType.String);
break;
case 1:
throw new NotSupportedException(string.Format((IFormatProvider)CultureInfo.InvariantCulture, "Unsupported EntityProperty.PropertyType:{0} detected during serialization.", type));
case 2:
AzureTableEntityJsonConverter.WriteJsonPropertyWithEdmType(writer, property.Key, (object)property.Value, EntityProperty.EntityPropertyType.Boolean);
break;
case 3:
AzureTableEntityJsonConverter.WriteJsonPropertyWithEdmType(writer, property.Key, (object)property.Value, EntityProperty.EntityPropertyType.DateTime);
break;
case 4:
AzureTableEntityJsonConverter.WriteJsonPropertyWithEdmType(writer, property.Key, (object)property.Value, EntityProperty.EntityPropertyType.Double);
break;
case 5:
AzureTableEntityJsonConverter.WriteJsonPropertyWithEdmType(writer, property.Key, (object)property.Value, EntityProperty.EntityPropertyType.GUID);
break;
case 6:
AzureTableEntityJsonConverter.WriteJsonPropertyWithEdmType(writer, property.Key, (object)property.Value, EntityProperty.EntityPropertyType.Int32);
break;
case 7:
AzureTableEntityJsonConverter.WriteJsonPropertyWithEdmType(writer, property.Key, (object)property.Value, EntityProperty.EntityPropertyType.Int64);
break;
default:
throw new NotSupportedException(string.Format((IFormatProvider)CultureInfo.InvariantCulture, "Unsupported EntityProperty.PropertyType:{0} detected during serialization.", type));
}
}

private static void WriteJsonPropertyWithEdmType(
JsonWriter writer,
string key,
object value,
EntityProperty.EntityPropertyType TableEntityType)
{
writer.WritePropertyName(key);
writer.WriteStartObject();
writer.WritePropertyName(key);
writer.WriteValue(value);
writer.WritePropertyName("EdmType");
writer.WriteValue(TableEntityType.ToString());
writer.WriteEndObject();
}

private static KeyValuePair<string, object> CreateKeyValue(
JsonSerializer serializer,
JProperty property)
{
if (property == null)
return new KeyValuePair<string, object>();
List<JProperty> list = JObject.Parse(((object)property.Value).ToString()).Properties().ToList<JProperty>();
EntityProperty.EntityPropertyType edmType = (EntityProperty.EntityPropertyType)Enum.Parse(typeof(EntityProperty.EntityPropertyType), ((object)list[1].Value).ToString(), true);
//EntityProperty entityProperty = new EntityProperty(new KeyValuePair<string, object>("test", 123), edmType);
KeyValuePair<string, object> KVP = new KeyValuePair<string, object>();
switch ((int)edmType)
{
case 0:
KVP = new KeyValuePair<string, object>(list[0].Name, (string)list[0].Value.ToObject<string>(serializer));
break;
case 1:
KVP = new KeyValuePair<string, object>(list[0].Name, (byte[])list[0].Value.ToObject<byte[]>(serializer));
//entityProperty = EntityProperty.GeneratePropertyForByteArray((byte[])list[0].Value.ToObject<byte[]>(serializer));
break;
case 2:
KVP = new KeyValuePair<string, object>(list[0].Name, new bool?((bool)list[0].Value.ToObject<bool>(serializer)));
break;
case 3:
KVP = new KeyValuePair<string, object>(list[0].Name, new DateTimeOffset?((DateTimeOffset)list[0].Value.ToObject<DateTimeOffset>(serializer)));
break;
case 4:
KVP = new KeyValuePair<string, object>(list[0].Name, new double?((double)list[0].Value.ToObject<double>(serializer)));
break;
case 5:
KVP = new KeyValuePair<string, object>(list[0].Name, new Guid?((Guid)list[0].Value.ToObject<Guid>(serializer)));
break;
case 6:
KVP = new KeyValuePair<string, object>(list[0].Name, new int?((int)list[0].Value.ToObject<int>(serializer)));
break;
case 7:
KVP = new KeyValuePair<string, object>(list[0].Name, new long?((long)list[0].Value.ToObject<long>(serializer)));
break;
default:
throw new NotSupportedException(string.Format((IFormatProvider)CultureInfo.InvariantCulture, "Unsupported EntityProperty.PropertyType:{0} detected during deserialization.", (object)edmType));
}
return KVP;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;

//using Microsoft.Azure.Cosmos.Table;
using Azure.Data.Tables;
using Newtonsoft.Json;
using System.Collections.Generic;

namespace TheByteStuff.AzureTableEntityJsonSerializer
{
/// <summary>
/// Based on classes from https://www.nuget.org/packages/DynamicTableEntityJsonSerializer/1.0.0
/// </summary>
public class AzureTableEntityJsonSerializer
{
private readonly AzureTableEntityJsonConverter jsonConverter;

public AzureTableEntityJsonSerializer(List<string> excludedProperties = null)
{
this.jsonConverter = new AzureTableEntityJsonConverter(excludedProperties);
}

public string Serialize(TableEntity entity)
{
string str;
if (entity != null)
str = JsonConvert.SerializeObject((object)entity, new JsonConverter[1]
{
(JsonConverter) this.jsonConverter
});
else
str = (string)null;
return str;
}

public TableEntity Deserialize(string serializedEntity)
{
TableEntity local;
if (serializedEntity != null)
local = JsonConvert.DeserializeObject<TableEntity>(serializedEntity, new JsonConverter[1] { (JsonConverter)this.jsonConverter });
else
local = null;
return (TableEntity)local;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<ApplicationIcon>CardFront_Clip.ico</ApplicationIcon>
<Description>Based on the nuget package offered by DoguArslan (https://www.nuget.org/packages/DynamicTableEntityJsonSerializer) which uses Microsoft.WindowsAzure.Storage.Table and .Net Framework 4.5, this package is adapted from the original work to function using Azure.Data.Table which does not properly serialize/deserialize int32 and a broader .NetCore 2.1.

In addition, the original converter logic for parsing the Timestamp loses the Offset and just returns the date and time. Added a hack to include the offset in the Timestamp.</Description>
<Authors>The Byte Stuff, LLC</Authors>
<PackageReleaseNotes>Initial Release</PackageReleaseNotes>
<Copyright>2023</Copyright>
<PackageLicenseUrl>https://github.com/TheByteStuff/AzureTableEntitySerializer/blob/master/LICENSE</PackageLicenseUrl>
<PackageIconUrl>https://github.com/TheByteStuff/AzureTableEntitySerializer/blob/master/src/DynamicTableEntityJsonSerializer/CardFront_Clip.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/TheByteStuff/AzureTableEntitySerializer</PackageProjectUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/TheByteStuff/AzureTableEntitySerializer</RepositoryUrl>
<PackageTags>Azure,Table,Azure Table Storage,Azure.Table.Entity,Json,Serializer</PackageTags>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.Data.Tables" Version="12.8.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

</Project>
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit d354119

Please sign in to comment.