MVC3 - Modifying object before serializing to JSON - c#

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.

Related

Is it good practice to return anonymous type in respond to HTTP GET request?

My Web API where one of GET endpoint return collection of ProductsByCategory.
public async Task<ActionResult<IEnumerable<ProductsByCategory>>> GetProductsByCategories()
{
var productsByCategories = await northwindContext.Categories.Select(category => new ProductsByCategory
{
CategoryName = category.CategoryName,
ProductCount = category.Products.Count
}
).ToListAsync();
return productsByCategories;
}
But I know that JSON and even XML don`t need in name of the type. They just need in name of the property and its value. So I have another way how to implement this method(using anonymous types):
public async Task<ActionResult<IEnumerable>> GetProductsByCategories()
{
var productsByCategories = await northwindContext.Categories.Select(category => new
{
CategoryName = category.CategoryName,
ProductCount = category.Products.Count
}
).ToListAsync();
return productsByCategories;
}
I liked second approach because I don't need in writing code of such types like ProductsByCategory and seems to me more logical since JSON(XML) don't need in type's name I don't need to create not anonymous type. But this is all my thoughts and I am pretty new in field of ASP .NET Core and it is possible that I miss some parts and my guesses are wrong. So is it good practise to pass collection of anonymous types as respond to HTTP GET request or is it better to specify what type of items is collection keeps?
You right, you will have the same resulting serialized object (xml, json), and you can use anonymous type. But you should keep in mind:
When your explicitly define resulting class, your code will be
cleaner
For explicitly defined resulting class your may define some validation
rules using attributes for serializer
If you use documentation tools, for example swagger, you also may use attributes to provide additional documentation.
Api should not be ambiguous.
Everything depends on your preferences. If you want use anonymous type, you may.

MVC3 Json function hide specific Properties

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.

Don't want to JSON serialize the whole list of classes

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

How can I convert a list of domain objects to viewmodels on the Controller in ASP.NET MVC

I'd like to know the best way of converting a list of domain object I retrieve into custom ViewModels in the controller
e.g.
IList<Balls> _balls = _ballsService.GetBalls(searchCriteria);
into
IList<BallViewModels> _balls = _ballsService.GetBalls(searchCriteria);
it doesn't have to be exactly as I've outlined above i.e. it doesn't have to be an IList and if not accessing the service directly and instead go thru some other layer that converts the objects to viewmodels then that is ok too.
thanks
For simple objects you could just use Linq:
IList<BallViewModel> _balls = _ballsService.GetBalls(searchCriteria)
.Select(b => new BallsViewModel
{
ID = b.ID,
Name = b.Name,
// etc
})
.ToList();
That can get pretty repetitive though, so you may want to give your BallViewModel class a constructor that accepts a Ball and does the work for you.
Another approach is to use a library like AutoMapper to copy the properties (even the nested ones) from your domain object to your view model.
Probably a bit of Linq, something along the lines of
var ballQuery = from ball in _ballsService.GetBalls(searchCriteria)
select new BallViewModels
{
Diameter = ball.Diameter,
color = ball.Color,
...
}
IList<BallViewModels> _balls = ballQuery.ToList();
Either that or the question is more complicated than I think...
I use AutoMapper to do this all the time. It's really flexible and has worked for me without any troubles so far.
First you set up a map like during your app's initialization:
Mapper.CreateMapping<Balls, BallViewModel>();
And whenever you need to map the objects, you would do this:
Mapper.Map<IList<Balls>, IList<BallViewModel>>(_ballsService.GetBalls());
Like I said, it's very flexible and you can modify how the mapping happens for each property using a fluent API.

How to serialize an IList<T>?

I've got an OR mapper (iBatis.Net) that returns an IList.
// IList<T> QueryForList<T>(string statementName, object parameterObject);
var data = mapper.QueryForList<Something>(statement, parameters);
I'm trying to use it in an webservice an want to return the data 1:1. Of course I can't return IList in a WebMethod, because it is an interface and therefore not serializable.
I found that the mapper is really returning an List. But I'm afraid to cast it to List because of course the mappers inner workings could change in future versions (and it just feels dirty).
So should I ...
a) return new List<Something>(data);
b) return (List<Something>)data;
c) // your solution here
Thanks a lot!
If it really is a List<T> but you want to protect against change and have it still work, then the most performant solution will be to attempt to cast it to a list, and if that fails then create a new list from its content, e.g.
var data = mapper.QueryForList<T>(statement, parameters);
var list = data as List<T> ?? new List<T>(data);
However, you mention that you can't return an interface because it's a web service. This may have been true with ASMX and the XmlSerializer class, but if you build the web service using WCF and use the DataContractSerializer then it will happily serialize collection interfaces (both as inputs to and outputs from the service). That type of change may be somewhat larger than you're looking for though!
Why should you serialize IList :) Just use it as a source for your own collection and serialize it:
var data = mapper.QueryForList<T>(statement, parameters);
var yourList = new List<T>(data);
//Serialize yourList here ))
I don't think you need a c).
It should be pretty safe to use solution a).
This solution depends on the public api of IBatis.net. Good api's don't change their public api unless it's really the only solution to a mission critical problem
Hope this helps.

Categories

Resources