资源塑形
如果资源的属性较多, 而且API消费者只需要一分部属性, 那么就应该考虑资源塑形
集合资源
单个资源
异常处理
- IEnumerableExtensions
//集合资源塑性
public static class IEnumerableExtensions
{
public static IEnumerable ToDynamicIEnumerable(this IEnumerable source,string fields = null)
{
if (source ==null)
{
throw new ArgumentNullException(nameof(source));
}
var expandoObjectList = new List();
var propertyInfoList = new List();
if (string.IsNullOrWhiteSpace(fields))
{
var propertyInfos = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance);
propertyInfoList.AddRange(propertyInfos);
}
else
{
var fieldsAfterSplit = fields.Split(',').ToList();
foreach (var field in fieldsAfterSplit)
{
var propertyName = field.Trim();
if (string.IsNullOrEmpty(propertyName))
{
continue;
}
var propertyInfo = typeof(TSource).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo ==null)
{
throw new Exception($"Property {propertyName} was't found on {typeof(TSource)}");
}
propertyInfoList.Add(propertyInfo);
}
}
foreach (TSource sourceObject in source)
{
var dataShapedObject = new ExpandoObject();
foreach (var propertyInfo in propertyInfoList)
{
var propertyValue = propertyInfo.GetValue(sourceObject);
((IDictionary)dataShapedObject).Add(propertyInfo.Name, propertyValue);
}
expandoObjectList.Add(dataShapedObject);
}
return expandoObjectList;
}
}
- ObjectExtensions
//单个资源塑性
public static class ObjectExtensions
{
public static ExpandoObject ToDynamic(this TSoucre source,string fields = null)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
var dataShapedObject = new ExpandoObject();
if (string.IsNullOrWhiteSpace(fields))
{
var propertyInfos = typeof(TSoucre).GetProperties(BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
foreach (var propertyInfo in propertyInfos)
{
var propertyValue = propertyInfo.GetValue(source);
((IDictionary)dataShapedObject).Add(propertyInfo.Name, propertyValue);
}
return dataShapedObject;
}
var fieldsAfterSplit = fields.Split(',').ToList();
foreach (var field in fieldsAfterSplit)
{
var propertyName = field.Trim();
var propertyInfo = typeof(TSoucre).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo ==null)
{
throw new Exception($"Can't found property {typeof(TSoucre)} on {propertyName}");
}
var propertyValue = propertyInfo.GetValue(source);
((IDictionary)dataShapedObject).Add(propertyInfo.Name, propertyValue);
}
return dataShapedObject;
}
}
- 修改controller
[HttpGet(Name ="GetPosts")]
public async Task Get(PostParameters postParameters)
{
var postList = await _postRepository.GetAllPostsAsync(postParameters);
var postResources = _mapper.Map, IEnumerable>(postList);
//集合资源塑性
var shapedPostResources = postResources.ToDynamicIEnumerable(postParameters.Fields);
var previousPageLink = postList.HasPrevious ? CreatePostUri(postParameters, PaginationResourceUriType.PreviousPage) : null;
var nextPageLink = postList.HasNext ? CreatePostUri(postParameters, PaginationResourceUriType.NextPage) : null;
var meta = new
{
postList.PageSize,
postList.PageIndex,
postList.TotalItemsCount,
postList.PageCount,
previousPageLink,
nextPageLink
};
Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(meta, new JsonSerializerSettings
{
//使得命名符合驼峰命名法
ContractResolver = new CamelCasePropertyNamesContractResolver()
}));
return Ok(shapedPostResources);
[HttpGet("{id}")]
public async Task Get(int id, string fields = null)
{
var post = await _postRepository.GetPostByIdAsync(id);
if (post == null)
{
return NotFound();//404
}
var postResource = _mapper.Map(post);
//单个资源塑性
var shapedPostResource = postResource.ToDynamic(fields);
return Ok(shapedPostResource); //200
}
- 修改startup,返回资源命名为驼峰命名
services.AddMvc(
options=>
{
options.ReturnHttpNotAcceptable = true; //开启406
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
})
.AddJsonOptions(options=>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
异常处理
- ITypeHelperService
public interface ITypeHelperService
{
bool TypeHasProperties(string fields);
}
- TypeHelperService
public class TypeHelperService:ITypeHelperService
{
public bool TypeHasProperties(string fields)
{
if (string.IsNullOrWhiteSpace(fields))
{
return true;
}
var fieldsAfterSplit = fields.Split(',');
foreach (var field in fieldsAfterSplit)
{
var propertyName = field.Trim();
if (string.IsNullOrEmpty(propertyName))
{
continue;
}
var propertyInfo = typeof(T)
.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null)
{
return false;
}
}
return true;
}
}
- 注册TypeHelperService
services.AddTransient();
- 修改Controller
[HttpGet(Name ="GetPosts")]
public async Task Get(PostParameters postParameters)
{
if (!_propertyMappingContainer.ValidateMappingExistsFor(postParameters.OrderBy))
{
return BadRequest("cannot finds fields for sorting.");
}
if (!_typeHelperService.TypeHasProperties(postParameters.Fields))
{
return BadRequest("Fields not exist.");
}
var postList = await _postRepository.GetAllPostsAsync(postParameters);
var postResources = _mapper.Map, IEnumerable>(postList);
//集合资源塑性
var shapedPostResources = postResources.ToDynamicIEnumerable(postParameters.Fields);
var previousPageLink = postList.HasPrevious ? CreatePostUri(postParameters, PaginationResourceUriType.PreviousPage) : null;
var nextPageLink = postList.HasNext ? CreatePostUri(postParameters, PaginationResourceUriType.NextPage) : null;
var meta = new
{
postList.PageSize,
postList.PageIndex,
postList.TotalItemsCount,
postList.PageCount,
previousPageLink,
nextPageLink
};
Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(meta, new JsonSerializerSettings
{
//使得命名符合驼峰命名法
ContractResolver = new CamelCasePropertyNamesContractResolver()
}));
return Ok(shapedPostResources);
}
[HttpGet("{id}")]
public async Task Get(int id, string fields = null)
{
if (!_typeHelperService.TypeHasProperties(fields))
{
return BadRequest("Fields not exist.");
}
var post = await _postRepository.GetPostByIdAsync(id);
if (post == null)
{
return NotFound();//404
}
var postResource = _mapper.Map(post);
//单个资源塑性
var shapedPostResource = postResource.ToDynamic(fields);
return Ok(shapedPostResource); //200
}