deserializing Keyvaluepair and Dictionary with .NET 6 - c#

I have an issue with the following minimal code:
[Fact]
public void DeserializeKeyValuePair()
{
string text = "{\"offer\": 12432515239}";
KeyValuePair<string, long> test = JsonSerializer.Deserialize<KeyValuePair<string, long>>(text);
}
In .NET 7, this code works as expected.
.NET 6 in turn throws an error that the keyvaluepair could not be converted.
System.Text.Json.JsonException :
The JSON value could not be converted to System.Collections.Generic.KeyValuePair`2[System.String,System.Int64].
Path: $.offer | LineNumber: 0 | BytePositionInLine: 9.
Unfortunately, I cannot upgrade my project to .NET 7 due to incompatibilities with another important library.
Perhaps Newtonsoft.Json can do that but I am trying to keep third party libraries to an absolute minimum. I'm also surprised that I do not find more references of this issue in the internet.
Is there a way to resolve the issue?
Update:
the string seems to deserialize into null with .NET 7, which is still unexpected. But, it does not crash. The main purpose is to deserialize dictionaries from server api responses.
The solution was, according to Guru Stron to install the nuget package. Check out his answer for that.

Deserialization to KeyValuePair<,> resulting in exception seems like a bug, but you can use Dictionary<string, long>:
KeyValuePair<string, long> test =
JsonSerializer.Deserialize<Dictionary<string, long>>(text).First();
Or create a custom converter. Another approach you can try is to install System.Text.Json nuget with latest version manually.
P.S.
In .NET 7, this code works as expected.
Or not, I would say that expected here is up for debate (compared to Dictionary<,> handling), though Newtonsoft.Json and System.Text.Json work the same in .NET 7:
KeyValuePair<string, long> test =
JsonSerializer.Deserialize<KeyValuePair<string, long>>(text);
// test = JsonConvert.DeserializeObject<KeyValuePair<string, long>>(text);
Console.WriteLine(test.Key ?? "null"); // prints "null"
Console.WriteLine(test.Value); // prints "0"

Related

Why does my code think a value is Microsoft.IdentityModel.Json.Linq.JObject when it is actually supposed to be Newtonsoft.Json.Linq.JObject?

I am having a lot of difficulty with a failing unit test. Specifically,
JwtRequestAuthorizeTests.authorize_should_accept_complex_objects_in_request_object()
The test attempts to add an Object parameter to the Claims array, and it is failing because after the request goes through the pipeline, an expected parameter called "someObj" is missing.
For the record, someObj is simply a json object defined as:
{{
"foo": {
"bar": "bar"
},
"baz": "baz"
}}
Also for the record, when I pull the latest IdentityServer code from GitHub the test passes.
I've discovered that the reason it's failing is because in the method JwtRequestValidator.ProcessPayloadAsync(JwtSecurityToken token), the variable value is of a type different than what's expected. Specifically, the code thinks it's Microsoft.IdentityModel.Json.Linq.JObject when it should be Newtonsoft.Json.Linq.JObject. I can't for the life of me figure out how or why this is the case.
I've included this image to show you that I'm not crazy (or at least, why I don't think I'm crazy). You can see that the cast from value to JObject fails, as jobj = null, and you can also see that value.GetType() returns Microsoft.IdentityModel.Json.Linq.JObject.
So can StackOverflow please tell me why this is happening, and perhaps how I can fix it?
Also, I think it's worth noting that I'm referencing Newtonsoft.Json as it should be:
After migrating from .Netframework WebAPI to dotnetcore3.1, I ran into the exact same issue. I can't believe I searched all over the internet, and was only able to find this question as the only related result.
Apparently JWT payload type is no longer NewtonSoft.Json.Linq.JObject. It is Microsoft.IdentityModel.Json.Linq.JObject now and is inaccessible outside of its namespace.
My guess is Microsoft has changed the definition and didn't expect people to use the type outside of its namespace.
What I ended up doing is getting rid of the type check, and just parse directly in a try{} catch{} block.
Hope this will help someone else in the future.
Microsoft decided to port in a copy of JSON.NET so that it can maintain a chain of trust. You can find where it's defined: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/1251
I was in a similar situation. I did as chy600 said and used JsonConvert.DeserializeObject to fix it.
Before:
((JObject)jwtPayload["field_1"])["field_2"]?.ToString()?.ToUpper() ?? ""
After:
JsonConvert.DeserializeObject<JwtPayload>(jwtPayload["field_1"].ToString())["field_2"]?.ToString()?.ToUpper() ?? ""

Convert Object to an array of Ushort in c#

I'm fairly new to C# but i'm looking to convert an object to an array of unsigned shorts. The original data is an array of WORD's (numerical value WORD) passed as an object. I've attempted the following but keep getting an error.
object temp = Agent.Port("PumpPressure1_01").Value;
ushort[] PP1_01 = ((IEnumerable)temp).Cast<object>()
.Select(x => x == null ? x.ToUshort())
.ToArray();
When I run this I get the following error:
'System.Collections.Generic.IEnumerable<T>' requires '1' type arguments.
The namespaces I used when I get the above error are:
using System.Linq;
using System.Text; // Don't think this is required but added it in case
If I add the following namespaces:
using System.Collections;
using System.Collections.Generic;
I get the following error.
'System.Linq.ParalleIEnumerable.Select<TTSource,TResult>()' is not supported by the language
I'm sure this is an obvious issue but I've been hunting the net for a while and can't find a solution. My best guess is that the Select function isn't correct as this was originally designed to convert an object to an array of strings.
Any help would be great.
Thanks
IEnumerable is a generic interface, so you have to declare the datatype you are using...
To be honest though, I would want to check what that call to
object temp = Agent.Port("PumpPressure1_01").Value;
is actually returning - by inspecting it in the debugger... If it is simply returning a reference to an array of a numeric type, you should be able to simply cast it. What you are doing though is trying to cast each individual item within the array - I suspect that's not what you should be doing - which would be casting the array itself.
Can you give us any API documentation for the Port method on the Agent object so I can see what it is meant to return? Can you try the inspection and see what that gives you?
Why you casting to IEnumerable and then casting it back to object if your temp variable is already of type object?
Also IEnumerable<T> is a generic interface and must specify exact type (as exception also says to you). If you have an array of integers and you want to work with them it should be IEnumerable<int>
Thanks for all the help and feedback.
Unfortunately I was't paying enough attention to the warnings that was posted which seems to be causing the issue.
Warning: Reference to type 'System.Func '2' claims it is defined in 'c:\Windows\Microsoft.NET\Framework64\v2.0.50727mscorlib.dll'. but it could not be found
It seems that there is some issue with the .NET reference. I have another VM which I tested the following solution on and it seemed to work without issue. Looks like I'll have to reinstall the software package to get it to work on the VM i want to use.
The software package I'm using is a custom package that uses C# to build solutions with prebuilt classes made to look like plug and play blocks. You can connect the blocks together drawings lines from one input/output of a block to another. You can then build C# code inside the blocks. Basically c# for dummy's like me..
Example of the blocks:
As for the code, I did have to make some changes as follows but now works a treat. Agent.Port("PumpPressure1_01").Value.RawValue is used to reference the particular ports on the block.
object temp = (object)Agent.Port("PumpPressure1_01").Value.RawValue;
UInt16[] PP1_01 = ((System.Collections.IEnumerable)temp).Cast<object>()
.Select(x => Convert.ToUInt16(x))
.ToArray();
foreach(UInt16 x in PP1_01)
{
Agent.LogDebug("values: " + x.ToString());
}
Again, thanks for all the help. Just need to resolve the issue with the library reference now.

Specifying locale for string interpolation in C#6 (Roslyn CTP6)

String interpolation in C#6 lets me write:
decimal m = 42.0m;
string x = $"The value is {m}";
However, a very common use case for string formatting is to specify the locale used for formatting the values. Let's say I need to use InvariantCulture for the formatting operation above, what is the syntax for that ?
This discussion suggests that I should be able to do this:
string x = INV($"The value is {m}");
Where INV is defined as
public static string INV(IFormattable formattable)
{
return formattable.ToString(null, System.Globalization.CultureInfo.InvariantCulture);
}
However, this does not work. It compiles, but it leaves my program hanging at in cmd.exe at startup - as if klr.exe, that I assume is being invoked, hangs (Compiler bug?)
This is an ASP.NET 5 Console Project in VS15 CTP 6.
What you have should work. It's the correct syntax. There's also a convenient method on the "System.FormattableString" abstract class which has the same effect as the suggested "INV" helper method.
using static System.FormattableString;
...
string x = Invariant($"The value is {m}");
I finally figured this out. As it turns out, the compiler feature relies on two types, System.FormattableString, and System.Runtime.CompilerServices.FormattableStringFactory. These were not available for my project - I guess they might not yet have made it into all platforms for CTP6.
This apparently made the compiler hang as described. Once I pulled the code for those two types from the CoreCLR code and added it to my project, my code works as expected.
This was figured out through code comments for the InterpolationTests. Hooray for the source being available :-)

monoDevelop ubuntu c# Class List has not the elementAt method

I'm trying to run c# on Ubuntu. So, I downloaded the monoDevelop from the Software Center which version is 3.0.4.3.
I think the problem is about the c# class library version, but i don't know where to see it or to apply a more recent one so that I could use the elementAt method in the List Class.
Thanks
On the documentation there is an indexer that you can use instead: http://docs.go-mono.com/?link=P%3aSystem.Collections.Generic.List%3cT%3e.Item
EDIT
You do use an indexer just like you would do for retrieving/setting an array element :
var list = new List<string>();
list.Add("hello !");
var s = list[0];

Is there .net magic to get parameter values by name in console application?

I've been developing .net console applications using C# and have always just dictated what order parameters must be inserted in so that args[0] is always start date and args[1] is always end date, for example.
however I would like to move over to using named parameters so that any combination of parameters can be sent in any order, such as the typical "-sd" would prefix a start date.
I know I could parse through the args[] looking for "-" and then read the name and look the next position for the accompanying value, but before doing that wanted to see if there was any kind of baked in handling for this rather standard practice.
is there something like this out there already that could do as such:
DateTime startDate = (DateTime)((ConsoleParameters)args[])["sd"]
I'm using C# and .Net 4
There is nothing built into the core framework.
A lot of people think NDesk.Options is useful for this sort of thing. Check out this example (taken directly from the provided link):
string data = null;
bool help = false;
int verbose = 0;
var p = new OptionSet () {
{ "file=", v => data = v },
{ "v|verbose", v => { ++verbose } },
{ "h|?|help", v => help = v != null },
};
List<string> extra = p.Parse (args);
Yes, the "magic" is that this is a common problem and it has been adequately solved. So I recommend using an already written library to handle parsing command line arguments.
CommandLineParser has been great for me. It is reasonably documented and flexible enough for every type of command line argument I've wanted to handle. Plus, it assists with usage documentation.
I will say that I'm not the biggest fan of making a specific class that has to be adorned with attributes to use this library, but it's a minor point considering that it solves my problem. And in reality forcing that attributed class pushes me to keep that class separate from where my app actually retrieves it's settings from and that always seems to be a better design.
You can use NDesk.Options.
There is no such a thing as named parameters. "-sd" is just a choice for a specific application. It can be "/sd" as well. Or "sd=". Or whatever you want.
Since there are no named parameters, there is nothing inside .NET Framework which let you use the "-sd" syntax.
But you can quite easily build your own method to get a set of "named parameters" for your app.
Edit: or, even better, you can use an existing library, like suggested in other answers.
Edit: reading the answer by #Sander Rijken, I see that I was wrong: there were still an implementation of "-sd" syntax in .NET 4.0 before the release. But since it was dropped before the final release, the only ways are still to create your own method or to use an existing library.

Categories