'How to deserialize a x-www-form-urlencoded encoded string in .NET Core 3.1 or .NET Standard?
How to deserialize a x-www-form-urlencoded encoded string in .NET Core 3.1 or in .NET Standard (C#)?
I'm aware of this question - answer. However, FormDataCollection does not appear to be available in .NET Core 3.1. See here.
EDIT: I am being passed this encoded data back by another external system. I am not writing a ASP.NET Core Website/API.
Solution 1:[1]
I did some digging through the .NET source code to figure out how ASP.NET Core is parsing x-form-urlencoded data internally. It is using the FormPipeReader class which accepts a PipeReader containing the encoded data. A PipeReader can be created from a Stream which in turn can be created from a string.
var data = "foo=bar&baz=qux";
var stream = new MemoryStream(Encoding.UTF8.GetBytes(data));
var reader = new FormPipeReader(PipeReader.Create(stream));
var pairs = await reader.ReadFormAsync();
Assert.Equal("bar", pairs["foo"]);
Assert.Equal("qux", pairs["baz"]);
Solution 2:[2]
So I never found a neat answer to this question. So I banged out my own rough serializer. Posting here in case anyone gets any use from it. I still welcome a better answer! :-)
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
public static class FormUrlEncodedSerializer
{
public static async Task<string> SerializeAsync(object obj)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
var keyValues = obj.GetPropertiesAsDictionary();
var formUrlEncodedContent = new FormUrlEncodedContent(keyValues);
return await formUrlEncodedContent.ReadAsStringAsync();
}
public static T Deserialize<T>(string formUrlEncodedText) where T : new()
{
if (string.IsNullOrEmpty(formUrlEncodedText))
throw new ArgumentException("Form URL Encoded text was null or empty.", nameof(formUrlEncodedText));
var pairs = formUrlEncodedText.Split('&');
var obj = new T();
foreach (var pair in pairs)
{
var nameValue = pair.Split('=');
if (HasValue(nameValue))
{
obj.SetProperty(nameValue[0], nameValue[1]);
}
}
return obj;
}
private static bool HasValue(string[] nameValue)
{
return nameValue.Length == 2 && nameValue[1] != string.Empty;
}
}
public static class ObjectExtensions
{
public static void SetProperty(this object source, string propertyName, object propertyValue)
{
var pi = source.GetProperty(propertyName);
if (pi != null && pi.CanWrite)
{
pi.SetValue(source, propertyValue, null);
}
}
public static PropertyInfo GetProperty(this object source, string propertyName)
{
BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;
return source.GetType().GetProperty(propertyName, bindingFlags);
}
public static IDictionary<string, string> GetPropertiesAsDictionary(this object source)
{
var dict = new Dictionary<string, string>();
if (source == null)
return dict;
var properties = source.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties)
{
var value = property.GetValue(source);
if (value == null)
continue;
dict.Add(property.Name, value.ToString());
}
return dict;
}
}
EDIT: Replaced ToKeyValues with GetPropertiesAsDictionary.
Solution 3:[3]
You could use Microsoft.AspNetCore.WebUtilities.FormReader to deserialize x-www-form-urlencoded content to a dictionary like so:
static Dictionary<string, StringValues> DeserializeForm(string content) {
using var reader = new FormReader(content);
return reader.ReadForm();
}
Solution 4:[4]
One liner linq for this is:
Dictionary<string,string> ParamsDict = ReceivedData.Split('&').Select(x => x.Split('=')).ToDictionary(key => key[0].Trim(), value => value[1].Trim());
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Cyral |
| Solution 2 | |
| Solution 3 | |
| Solution 4 | Bharat Vasant |
