In .NET 6.0 application it uses Newtonsoft library for JSON serialization. It uses JsonProperty attribute for alias naming in response. However, it provides actual property name(FileName in our example rather it should be label) instead of alias name.
Controller:
public async Task<JsonResult> GetAllFiles(string appId)
{var files = GetAFiles(appId); return Ok(files);}
Model:
[JsonProperty(PropertyName = "label")]
public string FileName { get; set; }
Expected Response:
[{"label":"test.pdf"}]
Root cause: JsonProperty attribute was getting ignored, so it was not applying. To resolve the issue, Newtonsoft library(same version) is added which was referred in other class library(Model).
Secondly, Microsoft.AspNetCore.Mvc.NewtonsoftJson nuget package is added in main project in Startup.cs with following code snippet:
services.AddMvcCore().AddNewtonsoftJson();
In Model
[JsonProperty(PropertyName = "label")]
public string FileName { get; set; }
Related
I am converting my newtonsoft implementation to new JSON library in .net core 3.0. I have the following code
public static bool IsValidJson(string json)
{
try
{
JObject.Parse(json);
return true;
}
catch (Exception ex)
{
Logger.ErrorFormat("Invalid Json Received {0}", json);
Logger.Fatal(ex.Message);
return false;
}
}
I am not able to find any equivalent for JObject.Parse(json);
Also what will be the attribute JsonProperty equivalent
public class ResponseJson
{
[JsonProperty(PropertyName = "status")]
public bool Status { get; set; }
[JsonProperty(PropertyName = "message")]
public string Message { get; set; }
[JsonProperty(PropertyName = "Log_id")]
public string LogId { get; set; }
[JsonProperty(PropertyName = "Log_status")]
public string LogStatus { get; set; }
public string FailureReason { get; set; }
}
One more thing i will be looking for the equivalent of Formating.None.
You are asking a few questions here:
I am not able to find any equivalent for JObject.Parse(json);
You can use JsonDocument to parse and examine any JSON, starting with its RootElement. The root element is of type JsonElement which represents any JSON value (primitive or not) and corresponds to Newtonsoft's JToken.
But do take note of this documentation remark:
This class utilizes resources from pooled memory to minimize the impact of the garbage collector (GC) in high-usage scenarios. Failure to properly dispose this object will result in the memory not being returned to the pool, which will increase GC impact across various parts of the framework.
When you need to use a JsonElement outside the lifetime of its document, you must clone it:
Gets a JsonElement that can be safely stored beyond the lifetime of the original JsonDocument.
Also note that JsonDocument is currently read-only and does not provide an API for creating or modifying JSON. There is an open issue Issue #39922: Writable Json DOM tracking this.
An example of use is as follows:
//https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#using-declarations
using var doc = JsonDocument.Parse(json);
//Print the property names.
var names = doc.RootElement.EnumerateObject().Select(p => p.Name);
Console.WriteLine("Property names: {0}", string.Join(",", names)); // Property names: status,message,Log_id,Log_status,FailureReason
//Re-serialize with indentation.
using var ms = new MemoryStream();
using (var writer = new Utf8JsonWriter(ms, new JsonWriterOptions { Indented = true }))
{
doc.WriteTo(writer);
}
var json2 = Encoding.UTF8.GetString(ms.GetBuffer(), 0, checked((int)ms.Length));
Console.WriteLine(json2);
Also what will be the attribute JsonProperty equivalent?
Attributes that can control JsonSerializer are placed in the System.Text.Json.Serialization namespace and inherit from an abstract base class JsonAttribute. Unlike JsonProperty, there is no omnibus attribute that can control all aspects of property serialization. Instead there are specific attributes to control specific aspects.
As of .NET Core 3 these include:
[JsonPropertyNameAttribute(string)]:
Specifies the property name that is present in the JSON when serializing and deserializing. This overrides any naming policy specified by JsonNamingPolicy.
This is attribute you want to use to control the serialized names of your ResponseJson class:
public class ResponseJson
{
[JsonPropertyName("status")]
public bool Status { get; set; }
[JsonPropertyName("message")]
public string Message { get; set; }
[JsonPropertyName("Log_id")]
public string LogId { get; set; }
[JsonPropertyName("Log_status")]
public string LogStatus { get; set; }
public string FailureReason { get; set; }
}
[JsonConverterAttribute(Type)]:
When placed on a type, the specified converter will be used unless a compatible converter is added to the JsonSerializerOptions.Converters collection or there is another JsonConverterAttribute on a property of the same type.
Note that the documented priority of converters -- Attribute on property, then the Converters collection in options, then the Attribute on type -- differs from the documented order for Newtonsoft converters, which is the JsonConverter defined by attribute on a member, then the JsonConverter defined by an attribute on a class, and finally any converters passed to the JsonSerializer.
[JsonExtensionDataAttribute] - corresponds to Newtonsoft's [JsonExtensionData].
[JsonIgnoreAttribute] - corresponds to Newtonsoft's [JsonIgnore].
When writing JSON via Utf8JsonWriter, indentation can be controlled by setting JsonWriterOptions.Indented to true or false.
When serializing to JSON via JsonSerializer.Serialize, indentation can be controlled by setting JsonSerializerOptions.WriteIndented to true or false.
Demo fiddle here showing serialization with JsonSerializer and parsing with JsonDocument.
This link should get you going, snippets of which I copied below.
https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/
WeatherForecast Deserialize(string json)
{
var options = new JsonSerializerOptions
{
AllowTrailingCommas = true
};
return JsonSerializer.Parse<WeatherForecast>(json, options);
}
class WeatherForecast {
public DateTimeOffset Date { get; set; }
// Always in Celsius.
[JsonPropertyName("temp")]
public int TemperatureC { get; set; }
public string Summary { get; set; }
// Don't serialize this property.
[JsonIgnore]
public bool IsHot => TemperatureC >= 30;
}
In Json.Net we have JsonConstructor attribute in order to instruct deserializer that should use the constructor to create the object.
Is there alternative in System.Text.Json?
Looks like this has now been added as of .NET 5.0 Preview 8:
Announcing .NET 5.0 Preview 8
JsonSerializer improvements in .NET 5
Related issue:
JsonSerializer support for immutable classes and structs
Related pull request:
Add [JsonConstructor] and support for deserializing with parameterized ctors
Please try this library I wrote as an extension to System.Text.Json to offer polymorphism: https://github.com/dahomey-technologies/Dahomey.Json
Add [JsonConstructor] attribute defined in the namespace Dahomey.Json.Attributes on your class.
public class ObjectWithConstructor
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
[JsonConstructor]
public ObjectWithConstructor(int id, string name)
{
Id = id;
Name = name;
}
}
Setup json extensions by calling on JsonSerializerOptions the extension method SetupExtensions defined in the namespace Dahomey.Json.
Then deserialize your class with the regular Sytem.Text.Json API.
JsonSerializerOptions options = new JsonSerializerOptions();
options.SetupExtensions();
const string json = #"{""Id"":12,""Name"":""foo"",""Age"":13}";
ObjectWithConstructor obj = JsonSerializer.Deserialize<ObjectWithConstructor>(json, options);
I have an object which I am de-serializing using ToJson<>() method from ServiceStack.Text namespace.
How to omit all the GET only propeties during serialization? Is there any attribute like [Ignore] or something that I can decorate my properties with, so that they can be omitted?
Thanks
ServiceStack's Text serializers follows .NET's DataContract serializer behavior, which means you can ignore data members by using the opt-out [IgnoreDataMember] attribute
public class Poco
{
public int Id { get; set; }
public string Name { get; set; }
[IgnoreDataMember]
public string IsIgnored { get; set; }
}
An opt-in alternative is to decorate every property you want serialized with [DataMember]. The remaining properties aren't serialized, e.g:
[DataContract]
public class Poco
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
public string IsIgnored { get; set; }
}
Finally there's also a non-intrusive option that doesn't require attributes, e.g:
JsConfig<Poco>.ExcludePropertyNames = new [] { "IsIgnored" };
Dynamically specifying properties that should be serialized
ServiceStack's Serializers also supports dynamically controlling serialization by providing conventionally named ShouldSerialize({PropertyName}) methods to indicate whether a property should be serialized or not, e.g:
public class Poco
{
public int Id { get; set; }
public string Name { get; set; }
public string IsIgnored { get; set; }
public bool? ShouldSerialize(string fieldName)
{
return fieldName == "IsIgnored";
}
}
More examples in ConditionalSerializationTests.cs
For nullable members, you also have the ability to set it to null before serializing.
This is particularly useful if you want to create a single view/api model that is re-used for several API calls. The service can touch it up before setting it on the response object.
Example:
public SignInPostResponse Post(SignInPost request)
{
UserAuthentication auth = _userService.SignIn(request.Domain, true, request.Username, request.Password);
// Map domain model ojbect to API model object. These classes are used with several API calls.
var webAuth = Map<WebUserAuthentication>(auth);
// Exmaple: Clear a property that I don't want to return for this API call... for whatever reason.
webAuth.AuthenticationType = null;
var response = new SignInPostResponse { Results = webAuth };
return response;
}
I do wish there was a way to dynamically control the serialization of all members (including non-nullable) on a per endpoint fashion.
I'm using Ef 4.1 and I've got a POCO object I'd like to serialize to JSON, I've read there is a problem to do so when using lazy loading but I'm not sure I can because a Message can have a collection of Message.
Is there any way to do this? sirialize this kind of object into JSON?
My Message object looks like:
public class Message
{
[Key]
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? LastModified { get; set; }
public virtual User User { get; set; }
public virtual Message Parent { get; set; }
public virtual ICollection<Message> Children { get; set; }
}
The problem is circular references. An easy way to avoid this is to use Json.Net http://james.newtonking.com/projects/json-net.aspx instead of the default MVC json serializer. The latest version of Json.Net will serialize objects with circular references out of the box. http://james.newtonking.com/projects/json/help/PreserveObjectReferences.html for more info on the problem
Eager load it using Include(). Sample linq:
var serializeMe = (from m in MyContext.Message.Include("User") where m.Id == someValue select m).ToList();
That will tell EF to load the User navigation property right away instead of lazy loading it, and the serializer should have no problem with it then.
How about this:
Mark your class as [Serializable]
Use the JsonSerializer to serialize your object to JSON.
Perhaps use eager loading on the properties in your EF query?
Message msg = new Message();
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(msg.GetType());
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, msg);
string json = Encoding.Default.GetString(ms.ToArray());
[Serializable]
public class Message
{
}
Well, lets go by parts.
¿Why is happening this?
Because you have virtual properties. If you are using EF you actually need them if you are using Lazy loading. You can configurate your EF to not do this by this example:
context.Configuration.ProxyCreationEnabled = false;
where context is your ObjectContext or DbContext... this assuming you are using EF. But for most scenarios this is not a good aproach.
Possible Solution
As I always say: "there are not good or bad solutions, just different ways and it depends on the context", saying that, you can create dynamic objects.
In case you only have to serialize a unique object, you can do something like this
Json(new {#property1=yourObject.property1, #property2=yourObject.property2})
In case you have a list, well, you can do this:
var list = new List<dynamic>();
foreach(var item in myRepository.GetAll())
{
list.Add(new
{
#property1= item.property1,
#property2= item.property2,
#property3= item.property3
});
}
return Json(list, JsonRequestBehavior.DenyGet);
I tried to make this as generic as I can. I hope this can help somebody!!
Best regards and have a very nice day! :)
I'm using EclipseLink's MOXy as the JAXB implementation in my RESTEasy project.MOXy's advanced functionality which has been brought by annotations like #XmlDiscriminatorNode & Value helped me a lot. Everything's working fine except one thing: JSON support. I'm using JettisonMappedContext of RESTEasy but unfortunately there're only instance variable fields belong to the abstract superclass in my JSON after marshalling.
#XmlRootElement
#XmlDiscriminatorNode("#type")
public abstract class Entity {
public Entity(){}
public Entity(String id){
this.id = id;
}
private String id;
#XmlElement
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Subclass:
#XmlRootElement
#XmlDiscriminatorValue("photo")
public class Photo extends Entity{
private String thumbnail;
public Photo(){}
public Photo(String id) {
super(id);
}
public void setThumbnail(String thumbnail) {
this.thumbnail = thumbnail;
}
#XmlElement(name="thumbnail")
public String getThumbnail() {
return thumbnail;
}
}
XML after marshalling:
<object type="photo">
<id>photoId423423</id>
<thumbnail>http://dsadasadas.dsadas</thumbnail>
</object>
JSON after marshalling:
"object":{"id":"photoId423423"}
Is there any other way to achieve this?
Thank you.
UPDATE 2
EclipseLink 2.4 has been released with MOXy's JSON binding:
http://www.eclipse.org/eclipselink/releases/2.4.php
UPDATE 1
Get a sneak peak of the native MOXy object-to-JSON binding being added in EclipseLink 2.4:
http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html
Ensure that you have included a file named jaxb.properties file with your model classes that contains the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Without this entry the reference implementation will be used, and the EclipseLink JAXB (MOXy) extensions will not appear in the resulting XML/JSON.
Using the #DescrimatorNode example from my blog, the XML produced would be:
<customer>
<contactInfo classifier="address-classifier">
<street>1 A Street</street>
</contactInfo>
</customer>
When I marshal leveraging Jettison:
StringWriter strWriter = new StringWriter();
MappedNamespaceConvention con = new MappedNamespaceConvention();
AbstractXMLStreamWriter w = new MappedXMLStreamWriter(con, strWriter);
marshaller.marshal(customer, w);
System.out.println(strWriter.toString());
Then I get the following JSON:
{"customer":{"contactInfo":{"#classifier":"address-classifier","street":"1 A Street"}}}
For more information on JAXB and JSON see:
http://bdoughan.blogspot.com/2011/04/jaxb-and-json-via-jettison.html