电子购物网站开发公司,平面设计作品欣赏,页面设计在哪个选项卡,东莞做网站公司首选!上一篇写的是使用静态基类方法的实现步骤: 使用dynamic (ExpandoObject)的好处就是可以动态组建返回类型, 之前使用的是ViewModel, 如果想返回结果的话, 肯定需要把ViewModel所有的属性都返回, 如果属性比较多, 就有可能造成性能和灵活性等问题. 而使用ExpandoObject(dynamic)就… 上一篇写的是使用静态基类方法的实现步骤: 使用dynamic (ExpandoObject)的好处就是可以动态组建返回类型, 之前使用的是ViewModel, 如果想返回结果的话, 肯定需要把ViewModel所有的属性都返回, 如果属性比较多, 就有可能造成性能和灵活性等问题. 而使用ExpandoObject(dynamic)就可以解决这个问题.返回一个对象返回一个dynamic类型的对象, 需要把所需要的属性从ViewModel抽取出来并转化成dynamic对象, 这里所需要的属性通常是从参数传进来的, 例如针对下面的CustomerViewModel类, 参数可能是这样的: Name, Company:using System;using SalesApi.Core.Abstractions.DomainModels;namespace SalesApi.ViewModels{ public class CustomerViewModel: EntityBase { public string Company { get; set; } public string Name { get; set; } public DateTimeOffset EstablishmentTime { get; set; } }}还需要一个Extension Method可以把对象按照需要的属性转化成dynamic类型:using System;using System.Collections.Generic;using System.Dynamic;using System.Reflection;namespace SalesApi.Shared.Helpers{ public static class ObjectExtensions { public static ExpandoObject ToDynamicTSource(this TSource source, string fields null) { if (source null) { throw new ArgumentNullException(source); } var dataShapedObject new ExpandoObject(); if (string.IsNullOrWhiteSpace(fields)) { // 所有的 public properties 应该包含在ExpandoObject里 var propertyInfos typeof(TSource).GetProperties(BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); foreach (var propertyInfo in propertyInfos) { // 取得源对象上该property的值 var propertyValue propertyInfo.GetValue(source); // 为ExpandoObject添加field ((IDictionarystring, object)dataShapedObject).Add(propertyInfo.Name, propertyValue); } return dataShapedObject; } // field是使用 , 分割的, 这里是进行分割动作. var fieldsAfterSplit fields.Split(,); foreach (var field in fieldsAfterSplit) { var propertyName field.Trim(); // 使用反射来获取源对象上的property // 需要包括public和实例属性 并忽略大小写. var propertyInfo typeof(TSource).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); if (propertyInfo null) { throw new Exception($没有在‘{typeof(TSource)}’上找到‘{propertyName}’这个Property); } // 取得源对象property的值 var propertyValue propertyInfo.GetValue(source); // 为ExpandoObject添加field ((IDictionarystring, object)dataShapedObject).Add(propertyInfo.Name, propertyValue); } return dataShapedObject; } }}注意: 这里的逻辑是如果没有选择需要的属性的话, 那么就返回所有合适的属性.然后在CustomerController里面:首先创建为对象添加link的方法:private IEnumerableLinkViewModel CreateLinksForCustomer(int id, string fields null) { var links new ListLinkViewModel(); if (string.IsNullOrWhiteSpace(fields)) { links.Add( new LinkViewModel(_urlHelper.Link(GetCustomer, new { id id }), self, GET)); } else { links.Add( new LinkViewModel(_urlHelper.Link(GetCustomer, new { id id, fields fields }), self, GET)); } links.Add( new LinkViewModel(_urlHelper.Link(DeleteCustomer, new { id id }), delete_customer, DELETE)); links.Add( new LinkViewModel(_urlHelper.Link(CreateCustomer, new { id id }), create_customer, POST)); return links; }针对返回一个对象, 添加了本身的连接, 添加的连接 以及 删除的连接.然后修改Get和Post的Action:[HttpGet] [Route({id}, Name GetCustomer)] public async TaskIActionResult Get(int id, string fields) { var item await _customerRepository.GetSingleAsync(id); if (item null) { return NotFound(); } var customerVm Mapper.MapCustomerViewModel(item); var links CreateLinksForCustomer(id, fields); var dynamicObject customerVm.ToDynamic(fields) as IDictionarystring, object; dynamicObject.Add(links, links); return Ok(dynamicObject); } [HttpPost(Name CreateCustomer)] public async TaskIActionResult Post([FromBody] CustomerViewModel customerVm) { if (customerVm null) { return BadRequest(); } if (!ModelState.IsValid) { return BadRequest(ModelState); } var newItem Mapper.MapCustomer(customerVm); _customerRepository.Add(newItem); if (!await UnitOfWork.SaveAsync()) { return StatusCode(500, 保存时出错); } var vm Mapper.MapCustomerViewModel(newItem); var links CreateLinksForCustomer(vm.Id); var dynamicObject vm.ToDynamic() as IDictionarystring, object; dynamicObject.Add(links, links); return CreatedAtRoute(GetCustomer, new { id dynamicObject[Id] }, dynamicObject); }红色部分是相关的代码. 创建links之后把vm对象按照需要的属性转化成dynamic对象. 然后往这个dynamic对象里面添加links属性. 最后返回该对象.下面测试一下.POST:结果:由于POST方法里面没有选择任何fields, 所以返回所有的属性.下面试一下GET: 再试一下GET, 选择几个fields:OK, 效果都如预期.但是有一个问题, 因为返回的json的Pascal case的(只有dynamic对象返回的是Pascal case, 其他ViewModel现在返回的都是camel case的), 而camel case才是更好的选择 .所以在Startup里面可以这样设置:services.AddMvc(options { options.ReturnHttpNotAcceptable true; // the default formatter is the first one in the list. options.OutputFormatters.Remove(new XmlDataContractSerializerOutputFormatter()); // set authorization on all controllers or routes var policy new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); }) .AddJsonOptions(options { options.SerializerSettings.ContractResolver new CamelCasePropertyNamesContractResolver(); }) .AddFluetValidations();然后再试试:OK. 返回集合 首先编写创建links的方法:private IEnumerableLinkViewModel CreateLinksForCustomers(string fields null) { var links new ListLinkViewModel(); if (string.IsNullOrWhiteSpace(fields)) { links.Add( new LinkViewModel(_urlHelper.Link(GetAllCustomers, new { fields fields }), self, GET)); } else { links.Add( new LinkViewModel(_urlHelper.Link(GetAllCustomers, new { }), self, GET)); } return links; }这个很简单.然后需要针对IEnumerableT类型创建把ViewModel转化成dynamic对象的Extension方法:using System;using System.Collections.Generic;using System.Dynamic;using System.Reflection;namespace SalesApi.Shared.Helpers{ public static class IEnumerableExtensions { public static IEnumerableExpandoObject ToDynamicIEnumerableTSource(this IEnumerableTSource source, string fields) { if (source null) { throw new ArgumentNullException(source); } var expandoObjectList new ListExpandoObject(); var propertyInfoList new ListPropertyInfo(); if (string.IsNullOrWhiteSpace(fields)) { var propertyInfos typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance); propertyInfoList.AddRange(propertyInfos); } else { var fieldsAfterSplit fields.Split(,); foreach (var field in fieldsAfterSplit) { var propertyName field.Trim(); var propertyInfo typeof(TSource).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); if (propertyInfo null) { throw new Exception($Property {propertyName} wasnt 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); ((IDictionarystring, object)dataShapedObject).Add(propertyInfo.Name, propertyValue); } expandoObjectList.Add(dataShapedObject); } return expandoObjectList; } }}注意: 反射的开销很大, 注意性能.然后修改GetAll方法:[HttpGet(Name GetAllCustomers)] public async TaskIActionResult GetAll(string fields) { var items await _customerRepository.GetAllAsync(); var results Mapper.MapIEnumerableCustomerViewModel(items); var dynamicList results.ToDynamicIEnumerable(fields); var links CreateLinksForCustomers(fields); var dynamicListWithLinks dynamicList.Select(customer { var customerDictionary customer as IDictionarystring, object; var customerLinks CreateLinksForCustomer( (int)customerDictionary[Id], fields); customerDictionary.Add(links, customerLinks); return customerDictionary; }); var resultWithLink new { Value dynamicListWithLinks, Links links }; return Ok(resultWithLink); }红色部分是相关代码.测试一下:不选择属性:选择部分属性:OK. HATEOAS这部分就写到这.其实 翻页的逻辑很适合使用HATEOAS结构. 有空我再写一个翻页的吧.原文地址 https://www.cnblogs.com/cgzl/p/8745631.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com