问题
I'm creating a complex object with children (nested objects) to be returned from my web api controller. The object contains list of other object types. These sub-object types within the list follow the pascal casing used in .NET.
var persons = peopleLookup.Values;
var users = userLookup.Values;
var roles = rolesLookup.Values;
var groups = groupLookup.Values;
var roleAssignments = roleAssignmentLookup.Values;
var groupMembers = groupMemberLookup.Values;
return new { persons, users, roles, roleAssignments, groups, groupMembers };
My problem is that WebAPI does not camel case each of the properties of the sub-items. For example the first person in the persons list should have and attributes of id, name instead of the .NET pascal case of Id, Name. The same should apply for all the other sub items.
回答1:
You can configure JSON.NET to produce camel case names in your application startup. Code snippet from Scott Allen's post:
var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
回答2:
I had the same problem. I am returning an object for grid population. It has some properties like Rows, Page, Total etc. Setting the contract resolver to camel case solves the problem for properties at top level. But if any property contains a list of objects with pascal cased property names, it does not changes their case.
So here is what I did to work around the problem.
Grid object with data to return
[DataContract]
public class GridProperties<T>
{
[DataMember]
public List<T> Rows { get; set; }
[DataMember]
public int Records { get; set; }
[DataMember]
public int Total { get; set; }
[DataMember]
public int Page { get; set; }
}
Here Rows holds the list of objects. Here I was returning list of model objects. Model class looks like :
public class ClientListModel
{
[DataMember(Name = "clientId")]
public int ClientId { get; set; }
[DataMember(Name = "firstName")]
public string FirstName { get; set; }
[DataMember(Name = "lastName")]
public string LastName { get; set; }
[DataMember(Name = "startDate")]
public DateTime? StartDate { get; set; }
[DataMember(Name = "status")]
public string Status { get; set; }
public ClientListModel()
{}
}
And below is how I returned JSON data from my API controller
[HttpGet]
public GridProperties<ClientListModel> GetClients(int page)
{
const int rowsToDisplay = 10;
try
{
IEnumerable<ClientListModel> clientList = null;
using (var context = new AngularModelConnection())
{
clientList = context.Clients.Select(i => new ClientListModel()
{
ClientId = i.Id,
FirstName = i.FirstName,
LastName = i.LastName,
StartDate = i.StartDate,
Status = (i.DischargeDate == null || i.DischargeDate > DateTime.Now) ? "Active" : "Discharged"
});
int total = clientList.Count(); //Get count of total records
int totalPages = Convert.ToInt16(Math.Ceiling((decimal) total/rowsToDisplay)); //Get total page of records
return new GridProperties<ClientListModel>
{
Rows = clientList.Skip((page - 1)*rows).Take(rows).ToList(),
Records = total,
Total = totalPages,
Page = page
};
}
}
catch (Exception exc)
{
ExceptionLogger.LogException(exc);
return new GridProperties<ClientListModel>
{
Rows = null,
Records = 0,
Total = 0,
Page = page
};
}
}
[DataMember(Name ="")]
attribute specifies what name to use for the property when the object is serialized.
Hope this helps!
回答3:
I had a similar problem with nested objects when trying to returning a DataSet with relations from WebAPI. Using an ExpandoObject
did the trick for me, maybe this will help you.
private static object ConvertDataSetWithRelationsToCamelCaseObject(DataSet ds)
{
foreach (DataRelation relation in ds.Relations)
{
relation.Nested = true;
}
var doc = new XmlDocument();
doc.LoadXml(ds.GetXml());
var pascalCaseJson = JsonConvert.SerializeXmlNode(doc, Formatting.None, true);
var pascalCaseObject = JsonConvert.DeserializeObject<ExpandoObject>(pascalCaseJson);
var camelCaseJson = JsonConvert.SerializeObject(pascalCaseObject, Formatting.Indented,
new JsonSerializerSettings {ContractResolver = new CamelCasePropertyNamesContractResolver(),});
return JsonConvert.DeserializeObject(camelCaseJson);
}
Sample code for creating a dataset with relations:
var dsTasks = new Tasks().Find(sqlParameters);
var dsValidators = new Validators().Find(sqlParameters);
var dsProperties = new ValidatorProperties().Find(sqlParameters);
dsTasks.Tables[0].TableName = "Tasks";
dsValidators.Tables[0].TableName = "Validators";
dsProperties.Tables[0].TableName = "ValidatorProperties";
var ds = new DataSet {DataSetName = "ValidatorsByTask"};
ds.Tables.Add(dsTasks.Tables[0].Copy());
ds.Tables.Add(dsValidators.Tables[0].Copy());
ds.Tables.Add(dsProperties.Tables[0].Copy());
ds.Relations.Add("Task_Validators", ds.Tables["Tasks"].Columns["Id"], ds.Tables["Validators"].Columns["TaskId"]);
ds.Relations.Add("Validator_Properties", ds.Tables["Validators"].Columns["Id"], ds.Tables["ValidatorProperties"].Columns["ValidatorId"]);
var data = ConvertDataSetWithRelationsToCamelCaseObject(ds);
回答4:
A short and very simple solution to formatting JSON output in CamelCase versus the default .NET's PascalCase.
Add to your WebApiConfig.cs file (under App_Start folder at WebApi 2) the following two lines:
// Get the default json formatter
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
// Switch from PascalCase to CamelCase
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
来源:https://stackoverflow.com/questions/23370619/camelcase-json-webapi-sub-objects-nested-objects-child-objects