1

I have an ASP.NET Razor page in which I'm trying to display a log list using a jQuery ajax request. From what I understood in docs and forums I've come up with this ajax request:

$.ajax({
    url: '@Url.Action("GetLogs","Logs")',
    dataType: "json",
    contentType :"application/json; charset=utf-8",
    success: function (data) {
        console.log("success");
        console.log(data);
    },
    error: function (msg) {
        console.log("error");
        console.log(msg);
    }
});

So this works but the json returned by it isn't exactly what I want. Here is the controller code called by the ajax request (and the getAllLogs function):

- LogsController -
public JsonResult GetLogs()
{
    List<Log> _loglist = LogsModel.getAllLogs(UserModel.getUser(Session["FirstName"].ToString(), Session["LastName"].ToString()));

    String json = JsonConvert.SerializeObject(_loglist, Formatting.Indented, new JsonSerializerSettings
    {
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore

    });

    return Json(json, JsonRequestBehavior.AllowGet);
}

- LogsModel -
//get all logs to display in admin tab
public static List<Log> getAllLogs(User _user)
{
    // if user is admin we can show logs concerning all users
    if(UserModel.isAdmin(_user))
        return db.Logs.Where(log => log.Action.Equals("Set Characteristic")).OrderByDescending(log => log.Id).ToList();
    else
        //user is manager and will see only users in same plant
        return db.Logs.Where(log => log.User.Plant.Code.Equals(_user.Plant.Code) && log.Action.Equals("Set Characteristic")).OrderByDescending(log => log.Id).ToList();
        }

As I was having issues with the self referencing loop I used what I found (referenceloophandling). I no longer have issues with it, but as I said before the returned string isn't what I want.

The function getAllLogs() returns logs based on user rights. Here it only returns 1 Log object (for tests purposes) and this only log should be serialized in json with the following format:

[
  {
    "Id" : 1,
    "User_Id": 1,
    "Date": "2014-08-11T10:00:00.000",
    "Action": "Set Characteristic",
    "State": true,
    "Message" : "User changed characteristic [charac_name]"
  }
]

Thing is I designed the database first and the User object is returned with the log so this is the Json returned:

[
  {
    "User": {
      "Characteristic_Value": [],
      "Logs": [
        {
          "Id": 1,
          "User_Id": 1,
          "Date": "2014-08-11T14:11:52.523",
          "Action": "Login attempt",
          "State": true,
          "Message": "User successfully logged in"
        },
        {
          "Id": 2,
          "User_Id": 1,
          "Date": "2014-08-11T14:13:45.07",
          "Action": "Login attempt",
          "State": true,
          "Message": "User successfully logged in"
        },
        {
          "Id": 3,
          "User_Id": 1,
          "Date": "2014-08-11T14:15:07.043",
          "Action": "Login attempt",
          "State": true,
          "Message": "User successfully logged in"
        },
    Other User Data ...
    },
    "Id" : 21,
    "User_Id": 1,
    "Date": "2014-08-11T10:00:00.000",
    "Action": "Set Characteristic",
    "State": true,
    "Message" : "User changed characteristic [charac_name]"
  }
]

I get all the user data. I'm the only one working on this project so right now it doesn't take long to get the data but in the near future, there will be more users and the amount of data to query will never cease to increase, and I'm quite concerned about response time.

So in the end my question is: Is it possible to get rid of the User data that are returned with the logs?

I'm still confused with JsonSerializerSettings but maybe it is the way of solving this?

J. Steen
  • 15,470
  • 15
  • 56
  • 63
Nydieven
  • 38
  • 4
  • Why don't you `Select` *Logs* in your linq? – L.B Aug 12 '14 at 13:54
  • Im' not sure to understand what you mean. but i think that's what i did in my getAllLogs function. Thing is with entity Framework, as i have a foreignkey in logs pointing to the user table, for each log i get, i get all the user info along. Not sure i'm able to explain it right... – Nydieven Aug 12 '14 at 14:16

1 Answers1

2

I think you have two options here:

  1. Mark the properties you don't want serialized as [JsonIgnore] using an attribute. This might not be a great option if your Log class lives in a different layer that really shouldn't care about JSON serialization.

  2. Create ViewModels to represent the information you do want to send down, optionally using a tool like AutoMapper to map classes together.

    For example, LogViewModel might look like this:

    public class LogViewModel
    {
        public int Id { get; set; }
    
        public int User_Id { get; set; }
    
        public DateTime Date { get; set; }
    
        public string Action { get; set; }
    
        public bool State { get; set; }
    
        public string Message { get; set; }
    }
    

    You'd then tweak your code to serialize a bunch of LogViewModels instead:

    IEnumerable<LogViewModel> viewModels =
        _logList.Select(l => new LogViewModel
        {
            Id = l.Id,
            User_Id = l.User_Id
            /* etc. */
        });        
    
    String json = JsonConvert.SerializeObject(viewModels);
    

    The above mapping code can become tedious--that's where a tool like AutoMapper comes in.

    You could also just project an anonymous type containing the properties you care about with similar effect, however I find managing ViewModels to be much easier.

I'd recommend going the ViewModel route, especially since it separates concerns nicely and protects you from problems down the road when people add properties you don't care about in this particular area of the system.

Community
  • 1
  • 1
Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
  • 1. I don't have a Log class, every classes are tables in base, so i can't use annotations. 2. i'm gonna try this :) Came by it wandering forums and stuff but didn't really understand it, i thought ViewModels were incompatible with MVC – Nydieven Aug 12 '14 at 14:18
  • ViewModels are just a pattern and they are widely used in ASP.NET MVC (they do differ from what "ViewModel" means in MVVM though) – Andrew Whitaker Aug 12 '14 at 14:39
  • I just installed automapper and create the LogsViewModel, and it worke perfectly fine :) Thanks a lot ! – Nydieven Aug 12 '14 at 15:08