ASP .NET Core Web API_10_资源塑形
2018-10-22 本文已影响30人
xtddw
资源塑形
如果资源的属性较多, 而且API消费者只需要一分部属性, 那么就应该考虑资源塑形
集合资源
单个资源
异常处理
- IEnumerableExtensions
//集合资源塑性
public static class IEnumerableExtensions
{
public static IEnumerable<ExpandoObject> ToDynamicIEnumerable<TSource>(this IEnumerable<TSource> source,string fields = null)
{
if (source ==null)
{
throw new ArgumentNullException(nameof(source));
}
var expandoObjectList = new List<ExpandoObject>();
var propertyInfoList = new List<PropertyInfo>();
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<string, object>)dataShapedObject).Add(propertyInfo.Name, propertyValue);
}
expandoObjectList.Add(dataShapedObject);
}
return expandoObjectList;
}
}
- ObjectExtensions
//单个资源塑性
public static class ObjectExtensions
{
public static ExpandoObject ToDynamic<TSoucre>(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<string, object>)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<string, object>)dataShapedObject).Add(propertyInfo.Name, propertyValue);
}
return dataShapedObject;
}
}
- 修改controller
[HttpGet(Name ="GetPosts")]
public async Task<IActionResult> Get(PostParameters postParameters)
{
var postList = await _postRepository.GetAllPostsAsync(postParameters);
var postResources = _mapper.Map<IEnumerable<Post>, IEnumerable<PostResource>>(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<IActionResult> Get(int id, string fields = null)
{
var post = await _postRepository.GetPostByIdAsync(id);
if (post == null)
{
return NotFound();//404
}
var postResource = _mapper.Map<Post, PostResource>(post);
//单个资源塑性
var shapedPostResource = postResource.ToDynamic(fields);
return Ok(shapedPostResource); //200
}
![](https://img.haomeiwen.com/i10360443/7736a690b24286ec.png)
![](https://img.haomeiwen.com/i10360443/e181b75926192407.png)
- 修改startup,返回资源命名为驼峰命名
services.AddMvc(
options=>
{
options.ReturnHttpNotAcceptable = true; //开启406
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
})
.AddJsonOptions(options=>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
![](https://img.haomeiwen.com/i10360443/26f2efeeccbf1ade.png)
异常处理
- ITypeHelperService
public interface ITypeHelperService
{
bool TypeHasProperties<T>(string fields);
}
- TypeHelperService
public class TypeHelperService:ITypeHelperService
{
public bool TypeHasProperties<T>(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<ITypeHelperService, TypeHelperService>();
- 修改Controller
[HttpGet(Name ="GetPosts")]
public async Task<IActionResult> Get(PostParameters postParameters)
{
if (!_propertyMappingContainer.ValidateMappingExistsFor<PostResource,Post>(postParameters.OrderBy))
{
return BadRequest("cannot finds fields for sorting.");
}
if (!_typeHelperService.TypeHasProperties<PostResource>(postParameters.Fields))
{
return BadRequest("Fields not exist.");
}
var postList = await _postRepository.GetAllPostsAsync(postParameters);
var postResources = _mapper.Map<IEnumerable<Post>, IEnumerable<PostResource>>(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<IActionResult> Get(int id, string fields = null)
{
if (!_typeHelperService.TypeHasProperties<PostResource>(fields))
{
return BadRequest("Fields not exist.");
}
var post = await _postRepository.GetPostByIdAsync(id);
if (post == null)
{
return NotFound();//404
}
var postResource = _mapper.Map<Post, PostResource>(post);
//单个资源塑性
var shapedPostResource = postResource.ToDynamic(fields);
return Ok(shapedPostResource); //200
}
![](https://img.haomeiwen.com/i10360443/db053efa7e26bfc1.png)