Skip to content

Commit b6d7e44

Browse files
authored
Update serialization to use System.Text.Json (#32) (#34)
* Update json deserialization to use System.Text.Json * Update Readme and fix type of array object * Change namespace * Fix line endings
1 parent f48fdf2 commit b6d7e44

File tree

5 files changed

+142
-8
lines changed

5 files changed

+142
-8
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,17 @@ $ cd duo_api_csharp
3737
5. Open the Test Explorer window (Test > Test Explorer).
3838
6. Run the unit tests by selecting on the top test and hitting the Run All button. There should be about 25 tests.
3939
Visit Microsoft's ["Get started with unit testing page"](https://learn.microsoft.com/en-us/visualstudio/test/getting-started-with-unit-testing?view=vs-2022&tabs=dotnet%2Cmstest) for more information and help.
40-
40+
41+
# Running the examples project
42+
43+
The example project (`examples/Examples.csproj`) connects to an Admin API instance and fetches some data to display to the command line. To run it, create a Duo Admin API instance following [these instructions](https://duo.com/docs/adminapi), making sure to enable Read permissions. Then, after building the example, you can invoke it using the command below, replacing the integration key, secret, and api hostname with the values for your API instance:
44+
45+
```
46+
.\examples\bin\Debug\Examples.exe <IntegrationKey> <SecretKey> <API Hostname>
47+
```
48+
49+
If successful, the command will output a summary of authentications performed against your account.
50+
4151
# Support
4252

4353
Report any bugs, feature requests, etc. to us directly:

duo_api_csharp/Duo.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
using System.Security.Cryptography;
1212
using System.Text.RegularExpressions;
1313
using System.Text;
14-
using System.Web.Script.Serialization;
1514
using System.Web;
1615
using System.Globalization;
1716
using System.Linq;
1817
using System.Runtime.InteropServices;
1918
using System.Security.Cryptography.X509Certificates;
2019
using System.Net.Security;
21-
22-
20+
using System.Text.Json;
21+
using Duo.Extensions;
22+
2323
namespace Duo
2424
{
2525
public class DuoApi
@@ -386,11 +386,9 @@ private Dictionary<string, object> BaseJSONApiCall(string method,
386386
HttpStatusCode statusCode;
387387
string res = this.ApiCall(method, path, parameters, timeout, date, out statusCode);
388388

389-
var jss = new JavaScriptSerializer();
390-
391389
try
392390
{
393-
var dict = jss.Deserialize<Dictionary<string, object>>(res);
391+
var dict = DeserializeJsonToMixedDictionary(res);
394392
if (dict["stat"] as string == "OK")
395393
{
396394
return dict;
@@ -428,6 +426,18 @@ private Dictionary<string, object> BaseJSONApiCall(string method,
428426
}
429427
}
430428

429+
private Dictionary<string, object> DeserializeJsonToMixedDictionary(string json)
430+
{
431+
var sourceDict = JsonSerializer.Deserialize
432+
<Dictionary<string, JsonElement>>(json);
433+
var targetDict = new Dictionary<string, object>();
434+
foreach (var kvp in sourceDict)
435+
{
436+
targetDict.Add(kvp.Key, kvp.Value.ConvertToObject());
437+
}
438+
return targetDict;
439+
}
440+
431441
public T JSONApiCall<T>(string method,
432442
string path,
433443
Dictionary<string, string> parameters)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Text.Json;
5+
6+
namespace Duo.Extensions
7+
{
8+
internal static class JsonElementExtensions
9+
{
10+
/// <summary>
11+
/// Converts a value contained within a System.Text.Json.JsonElement
12+
/// into an object of the contained type
13+
/// </summary>
14+
/// <param name="element"></param>
15+
/// <returns></returns>
16+
/// <exception cref="InvalidOperationException"></exception>
17+
internal static object ConvertToObject(this JsonElement element)
18+
{
19+
switch (element.ValueKind)
20+
{
21+
case JsonValueKind.Undefined:
22+
case JsonValueKind.Null:
23+
return null;
24+
case JsonValueKind.String:
25+
return element.GetString();
26+
case JsonValueKind.Number:
27+
if (element.TryGetInt32(out int intValue))
28+
{
29+
return intValue;
30+
}
31+
if (element.TryGetInt64(out long longValue))
32+
{
33+
return longValue;
34+
}
35+
if (element.TryGetDecimal(out decimal decimalValue))
36+
{
37+
return decimalValue;
38+
}
39+
return element.GetDouble();
40+
case JsonValueKind.True:
41+
case JsonValueKind.False:
42+
return element.GetBoolean();
43+
case JsonValueKind.Object:
44+
var sourceDict = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(element.GetRawText());
45+
var targetDict = new Dictionary<string, object>();
46+
foreach (var kvp in sourceDict)
47+
{
48+
targetDict.Add(kvp.Key, kvp.Value.ConvertToObject());
49+
}
50+
return targetDict;
51+
case JsonValueKind.Array:
52+
// ArrayList was returned by the older serializer, so make sure to keep the type
53+
var list = new ArrayList();
54+
foreach (var item in element.EnumerateArray())
55+
{
56+
list.Add(item.ConvertToObject());
57+
}
58+
return list;
59+
default:
60+
throw new InvalidOperationException("Unexpected JSON value kind: " + element.ValueKind);
61+
}
62+
}
63+
}
64+
}

duo_api_csharp/duo_api_csharp.csproj

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,40 @@
3333
<RootNamespace>duo_api_csharp</RootNamespace>
3434
</PropertyGroup>
3535
<ItemGroup>
36+
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
37+
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
38+
</Reference>
3639
<Reference Include="Microsoft.CSharp" />
3740
<Reference Include="System" />
41+
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
42+
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
43+
</Reference>
3844
<Reference Include="System.Configuration" />
3945
<Reference Include="System.Core" />
4046
<Reference Include="System.Data" />
4147
<Reference Include="System.Data.DataSetExtensions" />
48+
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
49+
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
50+
</Reference>
51+
<Reference Include="System.Numerics" />
52+
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
53+
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
54+
</Reference>
55+
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
56+
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
57+
</Reference>
58+
<Reference Include="System.Text.Encodings.Web, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
59+
<HintPath>..\packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll</HintPath>
60+
</Reference>
61+
<Reference Include="System.Text.Json, Version=6.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
62+
<HintPath>..\packages\System.Text.Json.6.0.2\lib\net461\System.Text.Json.dll</HintPath>
63+
</Reference>
64+
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
65+
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
66+
</Reference>
67+
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
68+
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
69+
</Reference>
4270
<Reference Include="System.Web" />
4371
<Reference Include="System.Web.Extensions" />
4472
<Reference Include="System.Xml" />
@@ -48,13 +76,23 @@
4876
<Compile Include="AssemblyInfo.cs" />
4977
<Compile Include="CertificatePinnerFactory.cs" />
5078
<Compile Include="Duo.cs" />
79+
<Compile Include="Extensions\JsonElementExtensions.cs" />
5180
</ItemGroup>
5281
<ItemGroup>
5382
<EmbeddedResource Include="ca_certs.pem" />
5483
</ItemGroup>
55-
<ItemGroup />
84+
<ItemGroup>
85+
<None Include="packages.config" />
86+
</ItemGroup>
5687
<Import Project="$(MSBuildToolsPath)\Microsoft.CSHARP.Targets" />
5788
<ProjectExtensions>
5889
<VisualStudio AllowExistingFolder="true" />
5990
</ProjectExtensions>
91+
<Import Project="..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets" Condition="Exists('..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets')" />
92+
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
93+
<PropertyGroup>
94+
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
95+
</PropertyGroup>
96+
<Error Condition="!Exists('..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Text.Json.6.0.2\build\System.Text.Json.targets'))" />
97+
</Target>
6098
</Project>

duo_api_csharp/packages.config

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Microsoft.Bcl.AsyncInterfaces" version="6.0.0" targetFramework="net48" />
4+
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
5+
<package id="System.Memory" version="4.5.4" targetFramework="net48" />
6+
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
7+
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
8+
<package id="System.Text.Encodings.Web" version="6.0.0" targetFramework="net48" />
9+
<package id="System.Text.Json" version="6.0.2" targetFramework="net48" />
10+
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
11+
<package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
12+
</packages>

0 commit comments

Comments
 (0)