I'd like to mimic some popular APIs and one of the things that I see a lot is that the client query a web api and specify which fields to return. So for instance, looking up a user's details could have a ton of info, or just basic info. Rather than creating separate endpoints for all the different levels of detail, I'd like to just be able to allow the client to request as much information as they need. This is a private api.
So on the server, I'd like to just use a users complete data (eagerly loaded or lazy loaded; it hasn't been determined yet), but then once I have that object, I'd like to use the fields specified in the client's request to build the response object.
Is there a library for this? Or any popular techniques or articles would be helpful. TIA
答案 0 :(得分:0)
这是一个涉及的过程,但基本上你想循环返回的对象,如果传入属性并返回这些属性的字典。我创建了一个扩展方法来实现它。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
namespace YourNamespace.Extensions
{
public enum PropertyFormat
{
AsIs,
PascalCase,
CamelCase
}
public static class DataShapingExtensions
{
public static object ToDataShape<ObjectIn>(this ObjectIn objectToShape, string fields, PropertyFormat propertyFormat = PropertyFormat.AsIs) where ObjectIn : class
{
var listOfFields = new List<string>();
if (!string.IsNullOrWhiteSpace(fields))
{
listOfFields = fields.ToLower().Split(',').ToList();
}
if (listOfFields.Any())
{
var objectToReturn = new JObject();
//====
var enumerable = objectToShape as IEnumerable;
if (enumerable != null)
{
var listOfObjects = new List<JObject>();
foreach (var item in enumerable)
{
var objectToReturn2 = new JObject();
listOfFields.ForEach(field =>
{
try
{
var prop = item.GetType()
.GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var fieldName = prop.Name;
var fieldValue = prop.GetValue(item, null);
fieldName = GetName(fieldName, propertyFormat);
objectToReturn2.Add(new JProperty(fieldName, fieldValue));
}
catch (Exception ex) { }
});
listOfObjects.Add(objectToReturn2);
}
return listOfObjects.ConvertAll(o => o);
}
//====
listOfFields.ForEach(field =>
{
try
{
var prop = objectToShape.GetType()
.GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var fieldName = prop.Name;
var fieldValue = prop.GetValue(objectToShape, null);
fieldName = GetName(fieldName, propertyFormat);
objectToReturn.Add(new JProperty(fieldName, fieldValue));
}
catch (Exception ex) { }
});
return objectToReturn;
}
return objectToShape;
}
private static string GetName(string field, PropertyFormat propertyFormat)
{
switch (propertyFormat)
{
case PropertyFormat.AsIs: return field;
case PropertyFormat.PascalCase: return field.ToPascalCase();
case PropertyFormat.CamelCase: return field.ToCamelCase();
default: return field;
}
}
}
}
要使用它,您将检查路线上传入的字段。
[HttpGet, Route("/api/yourRoute")]
public async Task<IHttpActionResult> GetListOfYourObjects(string fields = null)
{
try
{
var yourObject = await repo.GetYourListFromRepo();
if (fields.HasValue())
{
return Ok(yourObject.ToDataShape(fields, PropertyFormat.CamelCase));
}
return Ok(yourObject);
}
catch (Exception)
{
return InternalServerError();
}
}
然后在调用路径时对返回的数据进行整形,例如从ajax中传入您想要的字段。
$.ajax({
url: "/api/yourRoute?fields=field1,field2"
})
只返回那些字段的对象。
{
field1: "",
field2: ""
}