How to tell Json.Net globally to apply the StringEnumConverter to all enums
Add a StringEnumConverter
to the JsonSerializerSettings
Converters collection.
Documentation: Serialize with JsonConverters
If you want the serializer to use camelCasing, you can set this as well:
SerializerSettings.Converters.Add(
new StringEnumConverter { CamelCaseText = true });
This will serialize SomeValue
to someValue
.
StringEnumConverter works as an attribute but not globally
In netcore 3.1 or higher, you can use JsonStringEnumConverter:
var options = new JsonSerializerOptions
{
Converters = { new JsonStringEnumConverter() },
//other options
};
Try Example online
How to tell JSON.NET StringEnumConverter to take DisplayName?
You should try using [EnumMember]
instead of [Display]
. You can also put the [JsonConverter]
attribute on the enum itself.
[JsonConverter(typeof(StringEnumConverter))]
public enum Status
{
[EnumMember(Value = "Awaiting Approval")]
AwaitingApproval,
Rejected,
Accepted,
}
The VB.NET version for the JsonConverter attribute is:
<Newtonsoft.Json.JsonConverter(GetType(Newtonsoft.Json.Converters.StringEnumConverter))>
Override global Json.NET enum handling for one particular enum via decoration
Your main difficulty appears to be that you are not decorating your flag enums with FlagsAttribute
, like so:
[Flags]
public enum Hobbies
{
Walking = 0x01,
Biking = 0x02,
// Etc
}
This is the recommended best practice for flag enums:
Designing Flag Enums
√ DO apply the System.FlagsAttribute to flag enums. Do not apply this attribute to simple enums.
See also here. If you don't do this, many enum-related .Net utilities may not work as expected for flag enumerations.
Having done this, StringEnumConverter
will serialize flag enums with composite values as a set of comma-separated values instead of as the numeric value you are currently seeing:
{
"Hobbies": "walking, biking"
}
If you don't want this and still prefer to see default, numeric values for flag enums in your JSON, you can subclass StringEnumConverter
to only convert non-flag enums:
public class NonFlagStringEnumConverter : StringEnumConverter
{
public override bool CanConvert(Type objectType)
{
if (!base.CanConvert(objectType))
return false;
return !HasFlagsAttribute(objectType);
}
static bool HasFlagsAttribute(Type objectType)
{
return Attribute.IsDefined(Nullable.GetUnderlyingType(objectType) ?? objectType, typeof(System.FlagsAttribute));
}
}
Then use it like:
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new NonFlagStringEnumConverter { CamelCaseText = true });
This will cause Json.NET to fall back on any global default JSON converter for enums, or to numeric serialization if there is no applicable fallback. Demo fiddle #1 here.
Additionally, if you need to supersede a converter applied at a higher level and force numeric serialization for flag enums, use the following:
public class ForceNumericFlagEnumConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
if (!(Nullable.GetUnderlyingType(objectType) ?? objectType).IsEnum)
return false;
return HasFlagsAttribute(objectType);
}
public override bool CanRead { get { return false; } }
public override bool CanWrite { get { return false; } }
static bool HasFlagsAttribute(Type objectType)
{
return Attribute.IsDefined(Nullable.GetUnderlyingType(objectType) ?? objectType, typeof(System.FlagsAttribute));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Demo fiddle #2 here.
JavaScriptSerializer - JSON serialization of enum as string
No there is no special attribute you can use. JavaScriptSerializer
serializes enums
to their numeric values and not their string representation. You would need to use custom serialization to serialize the enum
as its name instead of numeric value.
If you can use JSON.Net instead of JavaScriptSerializer
than see answer on this question provided by OmerBakhari: JSON.net covers this use case (via the attribute [JsonConverter(typeof(StringEnumConverter))]
) and many others not handled by the built in .net serializers. Here is a link comparing features and functionalities of the serializers.
Json.NET StringEnumConverter not always working
Thanks for everyone's help! I realized what I've done. Sadly it's pretty dumb, I apologize in advanced for the run around.
Since I am using GET I am sending the parameters as url query parameters so WebAPI is using the normal ModelBinder to map names and not JSON.NET. I'm not actually sending JSON so this make total sense. This question helped me realize this:
Complex type is getting null in a ApiController parameter
My choices are create a custom model binder that handles the enum correctly or change to a POST and send the data with JSON.stringify().
Json.NET StringEnumConverter not working as expected
The ItemConverterType
property of the JsonPropertyAttribute
attribute is the converter to use for items of a collection. You should be using the JsonConverterAttribute
attribute.
public class TestData
{
[JsonConverter(typeof(StringEnumConverter))]
public TestEnum Enum { get; set; }
}
How to serialize enum as string globally (not by attribute in each enum)?
In .NET Core 3.0, the Newtonsoft.JSON package is no longer included by default.
Install the following package and try to add the converter like this:
services.AddMvc(...).AddNewtonsoftJson(opt => SerializerSettings.Converters.Add(new StringEnumConverter()));
deserialize json with array of enum
TL/DR: You have two basic problems here:
.NET Core 3.0+ has a new built-in JSON serializer
System.Text.Json
, and you are mixing up attributes and classes between this new serializer and Json.NET. This is very easy to do when both are installed because they share some class names, such asJsonSerializer
andJsonConverter
.The new serializer is used by default but does not yet support serialization of enums as strings with custom value names; see System.Text.Json: How do I specify a custom name for an enum value? for details.
The easiest way to solve your problem is to switch back to Json.NET as shown here and use attributes, converters and namespaces exclusively from this serializer.
First let's break down the differences and similarities between the two serializers:
System.Text.Json
:Built into .NET Core 3.0+ automatically and used for JSON serialization by ASP.NET Core 3.0+ by default.
Namespaces
System.Text.Json
andSystem.Text.Json.Serialization
.Classes including
System.Text.Json.Serialization.JsonConverter
,System.Text.Json.Serialization.JsonConverter<T>
andSystem.Text.Json.JsonSerializer
.Attributes including
System.Text.Json.Serialization.JsonPropertyNameAttribute
,System.Text.Json.Serialization.JsonConverterAttribute
andSystem.Text.Json.Serialization.JsonExtensionDataAttribute
.Serialization of enums as strings is supported by
System.Text.Json.Serialization.JsonStringEnumConverter
, however renaming via attributes is not implemented.See this answer to System.Text.Json: How do I specify a custom name for an enum value? for potential workarounds.
Json.NET:
A 3rd-party library that can be used for serialization in ASP.NET Core 3.0+ by adding a NuGet reference to
Microsoft.AspNetCore.Mvc.NewtonsoftJson
and then callingAddNewtonsoftJson()
inStartup.ConfigureServices
.For details see this answer to Where did IMvcBuilder AddJsonOptions go in .Net Core 3.0? by poke.
Namespaces including
Newtonsoft.Json
,Newtonsoft.Json.Converters
,Newtonsoft.Json.Linq
andNewtonsoft.Json.Serialization
among others.Classes including
Newtonsoft.Json.JsonConverter
,Newtonsoft.Json.JsonConverter<T>
andNewtonsoft.Json.JsonSerializer
Attributes including
Newtonsoft.Json.JsonPropertyAttribute
,Newtonsoft.Json.JsonConverterAttribute
andNewtonsoft.Json.JsonExtensionDataAttribute
among others.Serialization of enums as renamed strings is supported automatically by
Newtonsoft.Json.Converters.StringEnumConverter
when theEnumMemberAttribute
attribute is applied.
With this in mind, which serializer are you using in your code? Since you helpfully included the namespaces in your question, we can check:
using System.Text.Json.Serialization; // System.Text.Json
using Newtonsoft.Json; // Json.NET
namespace Assignment_1
{
public class MyRequest
{
//...
[JsonProperty( // JsonProperty from Newtonsoft
"changeTypes",
ItemConverterType = typeof(JsonStringEnumConverter)// JsonStringEnumConverter from System.Text.Json
)]
public AppGlobals.BoardSymbols[] GameBoard { get; set; }
}
}
So as you can see, you are mixing up attributes from Newtonsoft with converters from System.Text.Json
, which isn't going to work. (Perhaps you selected the namespaces from a "Resolve -> using ..." right-click in Visual Studio?)
So, how to resolve the problem? Since Json.NET supports renaming of enum values out of the box, the easiest way to resolve your problem is to use this serializer. While possibly not as performant as System.Text.Json
it is much more complete and full-featured.
To do this, remove the namespaces System.Text.Json.Serialization
and System.Text.Json
and references to the type JsonStringEnumConverter
from your code, and modify MyRequest
and BoardSymbols
as follows:
using System.Runtime.Serialization;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json;
namespace Assignment_1
{
public class MyRequest
{
//...
[Required]
[MinLength(9)]
[MaxLength(9)]
[JsonProperty("changeTypes")] // No need to add StringEnumConverter here since it's already applied to the enum itself
public AppGlobals.BoardSymbols[] GameBoard { get; set; }
}
}
namespace AppGlobals
{
[JsonConverter(typeof(StringEnumConverter))]
public enum BoardSymbols
{
[EnumMember(Value = "X")]
First = 'X',
[EnumMember(Value = "O")]
Second = 'O',
[EnumMember(Value = "?")]
EMPTY = '?'
}
}
Then NuGet Microsoft.AspNetCore.Mvc.NewtonsoftJson
and in Startup.ConfigureServices
call AddNewtonsoftJson()
:
services.AddMvc()
.AddNewtonsoftJson();
Or if you prefer to use StringEnumConverter
globally:
services.AddMvc()
.AddNewtonsoftJson(o => o.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()));
Do take note of the following comment from the docs
Note: If the
AddNewtonsoftJson
method isn't available, make sure that you installed the Microsoft.AspNetCore.Mvc.NewtonsoftJson package. A common error is to install the Newtonsoft.Json package instead of the Microsoft.AspNetCore.Mvc.NewtonsoftJson package.
Mockup fiddle here.
Related Topics
How to Detect If a Property Exists on an Expandoobject
How to Multi-Target a .Net Core Class Library with Csproj
How to Marshal a Struct That Contains a Variable-Sized Array to C#
ASP.NET Adding Class to Current Menuitem
Copy Files from Resources/Streamingassets to Application.Persistentdatapath Upon Installation
How to Flatten an Expandoobject Returned via JSONresult in ASP.NET MVC
Class with Single Method -- Best Approach
How Does Hashset Compare Elements for Equality
Using Image Control in Wpf to Display System.Drawing.Bitmap
Performance Tests of Serializations Used by Wcf Bindings
How to Use .Net Reflection to Check for Nullable Reference Type
How to Get the Range of Occupied Cells in Excel Sheet
Custom Deserialization Using JSON.Net
Establish a Link Between Two Lists in Linq to Entities Where Clause
Escape Curly Brace '{' in String.Format
Replace Only Some Groups with Regex