Is there a way to control the JSON output of JsonResult with attributes, similar to how you can use XmlElementAttribute and its bretheren to control the output of XML serialization?
For example, given the following class:
public class Foo
{
[SomeJsonSerializationAttribute("bar")]
public String Bar { get; set; }
[SomeJsonSerializationAttribute("oygevalt")]
public String Oygevalt { get; set; }
}
I'd like to then get the following output:
{ bar: '', oygevalt: '' }
As opposed to:
{ Bar: '', Oygevalt: '' }
I wanted something a bit more baked into the framework than what Jarrett suggested, so here's what I did:
JsonDataContractActionResult:
public class JsonDataContractActionResult : ActionResult
{
public JsonDataContractActionResult(Object data)
{
this.Data = data;
}
public Object Data { get; private set; }
public override void ExecuteResult(ControllerContext context)
{
var serializer = new DataContractJsonSerializer(this.Data.GetType());
String output = String.Empty;
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, this.Data);
output = Encoding.Default.GetString(ms.ToArray());
}
context.HttpContext.Response.ContentType = "application/json";
context.HttpContext.Response.Write(output);
}
}
JsonContract() method, added to my base controller class:
public ActionResult JsonContract(Object data)
{
return new JsonDataContractActionResult(data);
}
Sample Usage:
public ActionResult Update(String id, [Bind(Exclude="Id")] Advertiser advertiser)
{
Int32 advertiserId;
if (Int32.TryParse(id, out advertiserId))
{
// update
}
else
{
// insert
}
return JsonContract(advertiser);
}
Note: If you're looking for something more performant than JsonDataContractSerializer, you can do the same thing using JSON.NET instead. While JSON.NET doesn't appear to utilize DataMemberAttribute, it does have its own JsonPropertyAttribute which can be used to accomplish the same thing.
Here's my implementation of Daniel Schaffer's answer, with the suggested improvements by Justin Rusbatch and Daniel incorporated.
using System;
using System.Runtime.Serialization.Json;
using System.Web.Mvc;
public class JsonDataContractActionResult : JsonResult
{
public JsonDataContractActionResult( Object data )
{
this.Data = data;
}
public override void ExecuteResult( ControllerContext context )
{
var serializer = new DataContractJsonSerializer( this.Data.GetType() );
context.HttpContext.Response.ContentType = "application/json";
serializer.WriteObject( context.HttpContext.Response.OutputStream,
this.Data );
}
}
This is the solution to use NewtonSoft Json.Net (for performance)
I've found part of the solution here and on SO
public class JsonNetResult : ActionResult
{
public Encoding ContentEncoding { get; set; }
public string ContentType { get; set; }
public object Data { get; set; }
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult(object data, Formatting formatting)
: this(data)
{
Formatting = formatting;
}
public JsonNetResult(object data):this()
{
Data = data;
}
public JsonNetResult()
{
Formatting = Formatting.None;
SerializerSettings = new JsonSerializerSettings();
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType)
? ContentType
: "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (Data == null) return;
var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
var serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Data);
writer.Flush();
}
}
So that in my controller, I can do that
return new JsonNetResult(result);
In my model, I can now have:
[JsonProperty(PropertyName = "n")]
public string Name { get; set; }
Note that now, you have to set the JsonPropertyAttribute to every property you want to serialize.
I know this is an old question but for those looking for just how to avoid properties from being serialized use the ScriptIgnoreAttribute in the namespace System.Web.Script.Serialization. Sadly still can't controll the name of the serialized properties but somebody might find this helpfull.
public class MyClass {
[ScriptIgnoreAttribute]
public bool PropertyNotSerialized { get; set; }
public bool AnyProperty { get; set; }
}
Will output as Json result the following:
{"AnyProperty ": false}
Easy answer: the DataContractJsonSerializer should respect the [DataContract] and [DataMember] attributes in the System.Runtime.Serialization namespace of the BCL.
These answers were helpful to me, but coming to this problem a few years later than everyone else I found that this code didn't work with the current framework version. This version works with Newtonsoft.Json and ASP NET Core 3.1:
/*
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
*/
public class JsonDataContractActionResult : IActionResult
{
public JsonDataContractActionResult(object data)
{
this.Data = data;
}
public object Data { get; private set; }
public async Task ExecuteResultAsync(ActionContext context)
{
context.HttpContext.Response.ContentType = "application/json";
JsonSerializer serializer = new JsonSerializer();
serializer.NullValueHandling = NullValueHandling.Ignore;
using (MemoryStream ms = new MemoryStream()) {
using (StreamWriter sw = new StreamWriter(ms))
{
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, Data);
}
}
byte[] b = ms.ToArray();
await context.HttpContext.Response.Body.WriteAsync(b);
}
}
}
Related
I have a public property which is an object that contains numerous properties itself. Using ASP.net MVC, when I serialize the JSON data I simply add the [JsonIgnore] attribute wherever I use the object so it doesn't display the contents.
Is there a way to add the [JsonIgnore] attribute to the class so it never is serialized?
//[JsonIgnore] ??
public class DataObj
{
public string ConnectionName { get; set; }
public string Query { get; set; }
...
}
public class Customer
{
public string First { get; set; }
public string Last { get; set; }
[JsonIgnore]
public DataObj Foo { get; set; }
}
public class ShipAddress
{
public string Street { get; set; }
public string City { get; set; }
public string Country { get; set; }
[JsonIgnore]
public DataObj Foo { get; set; }
}
My solution after receiving the code provided by jvanrhyn.
Also, here is a link that explains more.
public class DataObjFilterContractResolver : DefaultContractResolver
{
public static readonly DataObjFilterContractResolver Instance = new DataObjFilterContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member,MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType.Name.StartsWith("DataObj") || property.PropertyName == "DataObj")
{
property.ShouldSerialize = instance => false;
}
return property;
}
}
public class UtcJsonResult : JsonResult
{
public UtcJsonResult(object data)
{
Data = data;
JsonRequestBehavior = JsonRequestBehavior.AllowGet;
}
private const string DateFormat = #"yyyy-MM-dd HH:mm:ssZ";
public override void ExecuteResult(ControllerContext context)
{
if (context == null) throw new ArgumentNullException("context");
if (Data == null) return;
var response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
if (ContentEncoding != null) response.ContentEncoding = ContentEncoding;
var isoConvert = new IsoDateTimeConverter {DateTimeFormat = DateFormat};
JsonConvert.DefaultSettings =
() => new JsonSerializerSettings
{ ContractResolver = new DataObjFilterContractResolver()}; //<--- Used here
var json = JsonConvert.SerializeObject(Data, isoConvert);
response.Write(json);
}
}
You can add a Contract Resolver in your project.
public class ShouldSerializeContractResolver : DefaultContractResolver
{
public new static readonly ShouldSerializeContractResolver Instance =
new ShouldSerializeContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member,
MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(DataObj))
{
property.ShouldSerialize =
instance =>
{
return false;
};
}
return property;
}
}
Hi Guys/Girls Im super new to asp.net mvc and Im trying to convert my date to a readable format. Currently it looks like this.
/Date(1444892163827)/
My Model
public class Movie
{
internal string title;
internal DateTime releasedate;
internal string genre;
public int ID { get; set; }
[Required]
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
[Required]
public string Genre { get; set; }
}
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
My Controller
public JsonResult getAll()
{
using (MovieDBContext dataContext = new MovieDBContext())
{
var movieList = dataContext.Movies.ToList();
return Json(movieList, JsonRequestBehavior.AllowGet);
}
}
public JsonResult getMovieByNo(string MovNo)
{
using (MovieDBContext dataContext = new MovieDBContext())
{
int no = Convert.ToInt32(MovNo);
var movieList = dataContext.Movies.Find(no);
return Json(movieList, JsonRequestBehavior.AllowGet);
}
}
Any help would really be appreciated !
You need create CustomJsonResult in MVC where you use for example JSON.Net with IsoDateTimeConverter or you should change your project MVC to WebAPI if you return only JSON.
Create class from this https://stackoverflow.com/a/9302054/4599089 (Approach 2) and then use this in controller:
public JsonResult getAll()
{
using (MovieDBContext dataContext = new MovieDBContext())
{
var movieList = dataContext.Movies.ToList();
return new CustomJsonResult(){Data = movieList};
}
}
public JsonResult getMovieByNo(string MovNo)
{
using (MovieDBContext dataContext = new MovieDBContext())
{
int no = Convert.ToInt32(MovNo);
var movieList = dataContext.Movies.Find(no);
return new CustomJsonResult(){Data = movieList};
}
}
I have an action that returns a JsonResult in my ASP.Net MVC4 application. I'm setting the Data property to an array of pre-defined classes. My issue is that I want to serialize with different property names. No matter what attributes I use, the object is serialized with the pre-defined property names. I've tried the following with no results:
[DataMember(Name = "iTotalRecords")]
[JsonProperty(PropertyName = "iTotalRecords")]
public int TotalRecords { get; set; }
I know "iTotalRecords" seems silly, but this action is for supporting a jQuery plugin that expects "iTotalRecords" and not "TotalRecords". Of course, I want to use names that make sense in my code-behind.
What serializer is used to parse JsonResult? Is there anything I can do or do I have to re-think returning JsonResult as an action result?
What serializer is used to parse JsonResult?
JavaScriptSerializer.
Is there anything I can do or do I have to re-think returning JsonResult as an action result?
Two possibilities come to mind:
define a view model and then map your domain model to the view model
write a custom action result that uses Json.NET or DataContractJsonSerializer and which allow you to control the names of the serialized properties. The following question illustrates this.
Thanks for the suggestions. I went ahead and created an ActionResult that uses Json.Net:
public class JsonNetActionResult : ActionResult
{
public Object Data { get; private set; }
public JsonNetActionResult(Object data)
{
this.Data = data;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.ContentType = "application/json";
context.HttpContext.Response.Write(JsonConvert.SerializeObject(Data));
}
}
FYI, it looks like Json.Net respects both [DataMember] and [JsonProperty], but [JsonProperty] will trump [DataMember] if they differ.
I've found part of the solution here and on SO
public class JsonNetResult : ActionResult
{
public Encoding ContentEncoding { get; set; }
public string ContentType { get; set; }
public object Data { get; set; }
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult(object data, Formatting formatting)
: this(data)
{
Formatting = formatting;
}
public JsonNetResult(object data):this()
{
Data = data;
}
public JsonNetResult()
{
Formatting = Formatting.None;
SerializerSettings = new JsonSerializerSettings();
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType)
? ContentType
: "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (Data == null) return;
var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
var serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Data);
writer.Flush();
}
}
So that in my controller, I can do that
return new JsonNetResult(result);
In my model, I can now have:
[JsonProperty(PropertyName = "n")]
public string Name { get; set; }
Note that now, you have to set the JsonPropertyAttribute to every property you want to serialize.
I have:
VIEW
<script type="text/javascript">
function postData() {
var urlact = '#Url.Action("createDoc")';
var model = '#Html.Raw(Json.Encode(Model))';
alert(model);
$.ajax({
data: stringify(model),
type: "POST",
url: urlact,
datatype: "json",
contentType: "application/json; charset=utf-8",
success: function (result) {
window.location.href = '#Url.Action("CreateWordprocessingDocument","Movies")'
}
});
}
</script>
Controller
[HttpPost]
public void createDoc(string mov)
{
var movies = new JavaScriptSerializer().Deserialize<IEnumerable<Movie>>(mov);
//using movies...
}
Model
//[Serializable]
public class Movie
{
//Added Data Annotations for Title & Genre
public int ID { get; set; }
[Required(ErrorMessage = "Insert name")]
public string Title { get; set; }
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Required(ErrorMessage = "Inserist genre")]
public string Genre { get; set; }
[DataType(DataType.Currency)]
public decimal Price { get; set; }
}
Why when I post the stringified data from View (through the Ajax post function) to Controller (createDoc) it stops throwing a ArgumentNullException (seems the Model passed is empty)?
Any workaround/solution?
Note: without stringifying the model it all works, but I'm trying to stringify it cause the other way I've got some issues with the DateTime format.
Note/2: I've also tried replacing the string mov in the input parameters of the Controller action with IEnumerable movies, but it didn't work either.
You'r model is already JSON encoded hence you do not need to Stringify it. This is probably causing Invalid Json data hence why it is not decoded.
if your DateTime format is the issue then explain that issue so we can help solve it.
Adding to the comment #Jaimal's answer about JSON.NET configuration. I use the following:
public class JsonNetResult : JsonResult
{
public JsonNetResult()
{
Formatting = Formatting.None;
}
public Encoding ContentEncoding { get; set; }
public string ContentType { get; set; }
public object Data { get; set; }
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (Data == null)
return;
// If you need special handling, you can call another form of SerializeObject below
var serializedObject = JsonConvert.SerializeObject(Data, Formatting, new JavaScriptDateTimeConverter());
response.Write(serializedObject);
}
}
with
public abstract class BaseController : Controller
{
/// <summary>
/// Use JSON.NET
/// </summary>
protected override JsonResult Json(object data, string contentType, Encoding contentEncoding)
{
var result = new JsonNetResult
{
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding,
Formatting = Formatting.Indented
};
return result;
}
}
and
public JsonResult Get()
{
return Json(myModel, null, null);
}
You may use different Converters.
I'm using LINQ-to-SQL for CRUD functionality, and DataContractJsonSerializer to serialize the object to JSON. I am also using ASP.NET MVC's data binding to post values to an MVC action that does the inserting. The problem is that it will serialize all of the properties except the Id property. I've got the model set up as so:
[Serializable]
[DataContract(Name = "campaign")]
[Table(Name = "hl.campaigns")]
public class Campaign
{
[DataMember(Name = "id")]
[Column(Name = "id", AutoSync = AutoSync.OnInsert, IsDbGenerated = true, IsPrimaryKey = true)]
public Int32 Id { get; set; }
[DataMember(Name = "createdBy")]
[Column(Name = "created_by")]
public Int32 CreatedBy { get; set; }
[DataMember(Name = "createdOnUtc")]
[Column(Name = "created_on_utc")]
public DateTime CreatedOnUtc { get; set; }
[DataMember(Name = "name")]
[Column(Name = "name", DbType = "NVarChar(256)")]
public String Name { get; set; }
/* more properties here */
}
Here is my custom JsonDataContractActionResult:
public class JsonDataContractActionResult : ActionResult
{
public JsonDataContractActionResult(Object data)
{
this.Data = data;
}
public Object Data { get; private set; }
public override void ExecuteResult(ControllerContext context)
{
var serializer = new DataContractJsonSerializer(this.Data.GetType());
String output = String.Empty;
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, this.Data);
output = Encoding.Default.GetString(ms.ToArray());
}
context.HttpContext.Response.ContentType = "application/json";
context.HttpContext.Response.Write(output);
}
}
Here's the action (JsonContract() returns a JsonDataContractActionResult):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Modify([Bind(Prefix = "campaign")] Campaign campaign)
{
if (campaign.Id == 0)
{
try
{
CoreDB.Campaigns.InsertOnSubmit(campaign);
CoreDB.SubmitChanges();
return JsonContract(campaign);
}
catch(Exception ex)
{
// TODO: error handling
}
}
return null; // TODO: modification
}
The only thing I can think of is that somehow data binding is preventing the Id property from being serialized because it was populated after it was deserialized from the form data. Any suggestions?
What does the regular Json() method return for this object?
According to this post... there might be an issue with the automatic backing fields in C#:
http://aaron-powell.spaces.live.com/blog/cns!91A824220E2BF369!150.entry