Is there a way in MVC3 to set what properties the Json function outputs?
ie. properties on my model have an attribute that tells the Json function not to output them.
It looks like the ScriptIgnoreAttribute will do what you want. Just decorate whatever property you don't want serialized with it.
Use anonymous method for that:
so instead of
return Json(it);
do
return Json(new {
it.Name,
CreatedAt = it.CreatedAt.ToString("D")
// And so on...
});
this way you explicitly publish (map) set of attributes to the web which ensures that only allowed properties can be accessed from JSON.
If you don't want to Repeat Yourself, you can use JSON.NET serializer with which you can customise how objects are serialised. (So you can create custom HideAttribute and take that into account).
With JSON.NET you will also need to write Controller.Json method replacement (SmartJson or so). But it should not be an issue I suppose.
Related
I have the following controller action
[HttpPut("{id}")]
public void Put(int id, [Bind("BirthDate")][FromBody]ExpandoObject value)
{
_dataContext.Update(value);
}
I am trying to limit the allowed properties, and I assumed this would work, however, it doesn't and value receives all the values sent and not just BirthDate - I don't want to use a view model because I want a dynamic object to be sent. FYI, this doesn't work with a normal model object either.
this is the json I am sending in request the body
{
"FirstName": "Lionell",
"LastName": "Messi",
"BirthDate": "2009-04-06T11:54:29.047",
"PhoneNumber": "1234567890",
"EmailAddress": "blabla#gmail.com",
"SchoolId": 1,
"IsIndependent": true
}
After reading through the source code, when posting a json in the request body, the BodyModelBinder is used. Unfortunately this model binder doesn't seem to apply the PropertyFilters provided by instances of the IPropertyBindingPredicateProvider like the [Bind] attribute.
It just uses the JsonInputFormatter to deserialize the json into the model type:
var formatters = bindingContext.OperationBindingContext.InputFormatters;
var formatter = formatters.FirstOrDefault(f => f.CanRead(formatterContext));
...
try
{
var previousCount = bindingContext.ModelState.ErrorCount;
var result = await formatter.ReadAsync(formatterContext);
var model = result.Model;
This seems like a bug to me...
In the meantime, you could try to evaluate some options you have available. As stated in the docs we know the formatter uses Json.Net:
The JsonInputFormatter is the default formatter and it is based off of
Json.NET.
So essentially you would need to follow an approach to exclude the properties that works with Json.Net, like using the [JsonIgnore] attribute. (Or just use some DTO object that doesn't contains those properties :))
Of course in your case is harder because you have a dynamic object and not a strongly typed object, which means:
There is no type for you to apply the attributes
Json.net will be unaware of any attributes you set in the controller action.
You could explore updating the JsonSerializerSettings, for example trying to use a contract resolver to dynamically exclude properties. You might possible need some global configuration that links routes and parameters to be ignored, so you can decide when to ignore a property or not based on the current request.
All of this would be much easier if it was fixed by Microsoft so it works out of the box!
I'm currently developing a small REST API for my application. It works fine. There's one problem, though. The results returned to the user contain too much data. My controller looks like this:
public JsonResult Profile(string name)
{
var encodedName = HttpUtility.HtmlEncode(name);
var n = encodedName.Replace('+', ' ');
var profile = profileSource.GetProfileForName(n);
if (profile == null)
{
HttpContext.Response.StatusCode = 404;
}
// XXXXX: how to remove certain fields from the profile?
return Json(profile, JsonRequestBehavior.AllowGet);
}
Any idea what's the cleanest way to deal with this? Is there some way to annotate the profile model so that certain fields won't get serialized? I guess alternatively I could construct a custom Model for this specific case or hack that JsonResult somehow. Either of these ways adds some extra overhead, though.
You can use the LINQ select method to project into an anonymous type.
You should probably do a custom object with a subset of ProfileĀ“s properties. Then translate the original object to the new DTO like object. (Tip:Try AutoMapper). Serialize and return.
return Json(new{profile.FirstName, profile.LastName, profile.OtherFields}, JsonRequestBehavior.AllowGet);
I ended up using inheritance. Basically I have a "shared" model (base class) and one that derives that and adds some extra fields to it. At the source I simply construct a shared instance for my REST API while the other part of the app uses the derived one. Pretty simple and seems to work well.
I want to make a Configuration Data Manager. This would allow multiple services to store and access configuration data that is common to all of them.
For the purposes of the Manager, I've decided to create a configuration class object - basically what every configuration data entry would look like:
Name, type, and value.
In the object these would all be strings that discribe the configuration data object itself. Once it has gotten this data from its database as strings, it would put it into this configuration object.
Then, I want it to send it through WCF to its destination. BUT, I don't want to send a serialized version of the configuration object, but rather a serialized version of the object discribed by the configuration object.
The reason I'd like to do this is so that
The Data Manager does not need to know anything about the configuration data.
So I can add configuration objects easily without changing the service. Of course, I should be able to do all of the CRUD operations, not just read.
Summary:
Input: string of name, type and value
Output: Serialized output of the object; the object itself is "type name = value"
Questions:
Is this a good method for storing and accessing the data?
How can I/can I serialize in this manner?
What would the function prototype of a getConfigurationData method look like?
I have decided to go in a different direction, thanks for the help.
Is this a good method for storing and accessing the data?
That is difficult to answer, the best I can give you is both a "yes" and a "No". Yes, It's not a bad idea to isolate the serialization/rehydration of this data.... and No, I don't really care much for the way you describe doing it. I'm not sure I would want it stored in text unless I plan on editing it by hand, and if I'm editing it by hand, I'm not sure I'd want it in a database. It could be done; just not sure you're really on the right track yet.
How can I/can I serialize in this manner?
Don't build your own, never that. Use a well-known format that already exists. Either XML or JSON will serve for hand-editable, or there are several binary formats (BSON, protobuffers) if you do not need to be able to edit it.
What would the function prototype of a getConfigurationData method look like?
I would first break-down the 'general' aka common configuration into a seperate call from the service specific configuration. This enables getConfigurationData to simply return a rich type for common information. Then either add a extra param and property for service specific data, or add another method. As an example:
[DataContract]
public class ConfigurationInfo
{
[DataMember]
public string Foo;
...
// This string is a json/xml blob specific to the 'svcType' parameter
[DataMember]
public string ServiceConfig;
}
[DataContract]
public interface IServiceHost
{
ConfigurationInfo GetConfigurationData(string svcType);
}
Obviously you place a little burden on the caller to parse the 'ServiceConfig'; however, your server can treat it as an opaque string value. It's only job is to associate it with the appropriate svcType and store/fetch the correct value.
I've got a IList of Sites in my application and Site has a large amount of properties.
I'm wanting to convert this list to JSON to be used in a dropdownlist similar to this
var sites = SiteRepository.FindAllSites();
return new JsonResult() { Data = sites, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
the problem I have is that I only want to use the id and name properties of the site class. I was thinking a way round this would be to use an 'adaptor' class that would then only expose these two properties and I would then serialize that.
The problem I have is I want to make the class generic so that it can handle any list of objects. Has anybody come across a similar situation and solved it?
EDIT: I can't use the [ScriptIgnore] Attribute as there may be a case when I do want to serialize the whole class.
Can you create an anonymous class from your list of sites?
var sites = SiteRepository.FindAllSites().Select(x=> new { Id=x.Id, Name=x.Name});
Since FindAllSites() seems to return an IList, which is descended from IEnumberable, you should be able to use System.Linq's extension methods (i.e. Select() ). That'll transform the List<Site> (with all the properties) to IEnumerable<some_anon_class> (with only 2 properties) which is then given to that JsonResult thing instead of the list of Site.
If you decorate you class fields with [ScriptIgnore] (System.Web.Script.Serialization) C# will ignore them during serialization using Json in much the same way that decorating with [XmlIgnore] would for Xml serialization.
MSDN
I'm using the JsonConvert.SerializeObject inside a custom ActionFilterAttribute.
Inside the OnActionExecuting I'm serializing the filterContext.ActionParameters for logging purpose.
The problem is that some of the actions are receiving files (System.Web.HttpPostedFileWrapper) via a <from/> with enctype="multipart/form-data" so i'm getting the error
Timeouts are not supported on this stream.
What i want to do is ignore these kind of object which can't get serialize and could through errors.
I found out that i can ignore class Properties with [JsonIgnore] or [ScriptIgnore] attributes, but I'm looking for a more general solution becuase i don't want to place these attributes all over the place.
I also tried to research the JsonSerializerSettings object but didn't find something relevant to my case.
You can simply filter these parameters. somethink like:
var ToBeSerialized = filterContext.ActionParameters.Where(a=>a.Value.GetType()!=typeof(TheTypeYouWantToAvoid));
string result = JsonConvert.SerializeObject(ToBeSerialized);