Question

In my ASP.NET MVC Application, I have many actions that return JSONs.
In these JSONs, some sub-structures are repeated.

For example

  1. ajax: "/Bands/Members" is supposed to return the members of a band, which are all musicians
  2. ajax: "/Musicians/All" is supposed to return all the musicians on the system
  3. ajax: "/Musicians/Search" is supposed to return all the musicians that match something

etc...

Here I show (1):

public JsonResult Members(long musicBandId)
{
    MusicBand b = db.MusicBands.SingleOrDefault(b => b.MusicBandId == musicBandId);

    if (b == null)
         return null;

    return Json(new
    {
        error = false,
        message = "",
        persons = from m in b.Members select new
                  {
                      musicianId = p.MusicianId,
                      name = m.Name,
                      instrument = new 
                                   {
                                      instrumentId = m.instrument.InstrumentId,
                                      model = m.instrument.Model
                                   }
                  }

    }, JsonRequestBehavior.AllowGet);
}

And here I show (2):

public JsonResult All(int page, int pageSize)
{
    var musicians = db.Musicians;
    var pageOfMusicians = musicians.Skip((page-1) * pageSize).Take(pageSize);

    return Json(new
    {
        error = false,
        message = "",
        musiciansCount = musicians.Count(),
        page = page,
        pageSize = pageSize
        musicians = from m in pageOfMusicians select new
                    {
                        musicianId = m.MusicianId,
                        name = m.Name,
                        instrument = new 
                                     {
                                        instrumentId = m.instrument.InstrumentId,
                                        model = m.instrument.Model
                                     }
                    }

    }, JsonRequestBehavior.AllowGet);
}

This has several problems:

  1. If I want to change the JSON format, I have to change it in every single action!
    example: If I want to change "name" to "fullname", I have to change it in Members() and All()

  2. Lot of "copy pasting": If I'm creating a new action that somewhere in the structure returns a musician, I need to copy and paste that piece of code that represents the musician

                  {
                      musicianId = p.MusicianId,
                      name = p.Name,
                      instrument = new 
                                   {
                                      instrumentId = instrument.InstrumentId,
                                      model = instrument.Model
                                   }
                  }
    
  3. Code is too large

What solution exists to this problem?
If you propose a framework, please show me how would the previous queries look with that framework

Notice I'm always using Linq-to-entities in my examples, and I would like to keep it like that because of performance issues. I know that with Linq-to-objects I could to something like:

  from m in pageOfMusicians.ToList() select m.GetDTO()

Being GetDTO() some method that can be run with Linq-to-Objects.
But then, again, I want to stick to Linq-to-Entities

Was it helpful?

Solution

Alternative 1

If you don't worry about using dynamics mixed with regular typed C# code you could make a utility method like...

public static dynamic PrepareForMusiciansView(IQuerable<Musician> musicians)
{
    return musicians.Select(m => new
                 {
                    musicianId = m.MusicianId,
                    name = m.Name,
                    instrument = new 
                                 {
                                    instrumentId = m.instrument.InstrumentId,
                                    model = m.instrument.Model
                                 }
                 }
}

...and then...

return Json(new
{
    error = false,
    message = "",
    musiciansCount = musicians.Count(),
    page = page,
    pageSize = pageSize
    musicians = Util.PrepareForMusiciansView(pageOfMusicians)

}, JsonRequestBehavior.AllowGet);

The method name should clearly reflect its purpose in terms of your application. Maybe you want to focus more on the serialization function and use a name like PrepareForJson. Also, it should be consistent with your coding standards. I would avoid it if nowhere else dynamics is used.

Alternative 2

Use AutoMapper (available via NuGet).

With AutoMapper you'd typically have DTO classes for Musician and Instrument, having the properties you want to expose in the view. If these properties have the same names as those in the source classes, AutoMapper will match them by name convention.

Using AutoMapper always involves defining the mappings and executing mappings. Defining the mappings should be done once at application startup. It looks like...

Mapper.CreateMap<Musician, MusicianDto>();
Mapper.CreateMap<Instrument, InstrumentDto>();

There are different ways to execute the mappings, but when working with IQueryable the preferred way is

musicians = pageOfMusicians.Project().To<MusicianDto>()

This projects IQueryable<Musician> to IQueryable<MusicianDto>, including the nested Instrument (if the DTO has a property of that name).

These are two viable alternatives I can think of to reduce the awkward new {} statements to reusable one-liners. It really depends on your application and coding style which alternative you prefer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top