zoukankan      html  css  js  c++  java
  • ASP.NET Web API中展示实体Link相关的方面

    有时候,向服务端请求一个实体,我们希望返回如下的格式:

    links: [
        href: http://localhost:8901/api/user/diaries/2013-08-17,
        rel: "self",
        method: "GET",
        isTemplated: false
    ],
    currentDate:"2013-08-17"

    首先抽象出一个与Link相关的类:

    public class LinkModel
    {
        public stirng Href{get;set;}
        public stirng Rel{get;set;}
        public string Method{get;set;}
        public bool IsTemplated{get;set;}
    }

    再放到某个视图模型中:

    public class DiaryModel
    {
        //存储和模型相关的链接
        public ICollection<LinkModel> Links{get;set;}
        public DateTime CurrentDate{get;set;}
    }
    
    public class Diary
    {
        public int Id{get;set;}
        public DateTime CurrentDate{get;set;}
    }

    ModelFactory用来实现视图模型和领域模型之间的转化。

    public class ModelFactory
    {
    
        private UrlHelper _urlHelper;
        
        public ModelFactory(HttpRequestMessage request)
        {
            _urlHelper = new UrlHelper(request);
        }
        
        //领域模型转换成视图模型
        public DiaryModel Create(Diary d)
        {
            return new DiaryModel()
            {
                Links = new List<LinkModel>
                {
                    CreateLink(_urlHelper.Link("Diaryis", new {diaryid=d.CurrentDate.ToString("yyyy-MM-dd")}),"self");
                },
                CurrentDate = d.CurrentDate
            }
        }
        
        public LinkModel CreateLink(string href, string rel, string method = "GET", bool isTemplated = false)
        {
            return new LinkModel()
            {
                Href = href,
                Rel = rel,
                Method = method,
                IsTemplated = isTemplated
            }
        }
        
        //视图模型转换成领域模型
        public Diary Parse(DiaryModel model)
        {
            try
            {
                var entity = new Diary();
                var selfLink = model.Links.Where(l => l.Rel == "self").FirstOrDefault();
                
                if(selfLink != null && !string.IsNullOrWhiteSpace(selfLink.Href))
                {
                    //从Uri中取出主键
                    var uri = new Uri(selfLink.Href);
                    entity.Id = int.Parse(uri.Segments.Last());
                }
                
                entity.CurrentDate = model.CurrentDate;
                
                return entity;
            }
            catch(Exception ex)
            {
            
            }
        }
    }

    Diaries这个controller略,路由方面:

    //api/user/diaries
    //api/user/diaries/2001-01-01
    config.Routes.MapHttpRoute(
        name: "Diaries",
        routeTemplate: "api/user/diaries/{dairyid}",
        defaults: new {controller="diaries", diaryid=RouteParameter.Optional}
    )

    这样,在客户端发出 http://localhost:8901/api/user/diaries/2013-08-17 GET请求,得到如下的响应:

    links: [
        href: http://localhost:8901/api/user/diaries/2013-08-17,
        rel: "self",
        method: "GET",
        isTemplated: false
    ],
    currentDate:"2013-08-17"

    在返回分页相关的action中,也可以返回相关的Link部分。

    先定义一个基类控制器:

    public abstract class BaseController : ApiController
    {
        ICountingKsRepository _repo;
        ModelFactory _modelFactory;
        
        public BaseController(ICountingKsRepository repo)
        {
            _repo = repo;
            //写在构造函数里的话有点迟,必须等实例化_modelFactory才有值
            //_modelFactory = new ModelFactory(this.Request);
        }
        
        protected ModelFactory TheModelFactory
        {
            get
            {
                if(_modelFactory == null)
                {
                    _modelFactory = new ModelFactory(this.Request, TheRepository);
                }
                return _modelFactory;
            }
        }
        
        protected ICountingsRepository TheRepoisitory
        {
            get
            {
                return _repo;
            }
        }
    }

    可见,把共同的部分封装到基类控制器中是很好的习惯,然后基类控制器的子类通过属性获取一些方面。

    再到具体的控制器:

    public class FoodsController : BaseController
    {
        ICountingKsRepoisotry _repo;
        ModelFactory _modelFactory;
        
        public FoodsController(ICountingKsRepository repo) : base(repo)
        {
        }
        
        const int PAGE_SIZE = 50;
        
        public object Get(bool includeMeasures = true, int page = 0)
        {
            IQueryable<Food> query;
            
            if(includeMeausres)
            {
                query = TheRepository.GetAllFoodsWithMeausres();
            }
            else
            {
                query = TheRepository.GetAllFoods();
            }
            
            //方便统计总数
            var baseQuery = query.OrderBy(f =>f.Description);
            
            //using System.Web.Http.Routing
            var helper = new UrlHelper(Request);
            
            var links = new List<LinkModel>();
            
            if(page > 0)
            {
                links.Add(TheModelFactory.CreateLink(helper.Link("Food", new {page = page - 1},"prevPage"));
            }
            
            if(page < totalPages - 1)
            {
                links.Add(TheModelFactory.CreateLink(helper.Link("Food", new {page = page + 1},"nextPage"));
            }
            
            //把上一页和下一页的url保存下来
            //var prevUrl = page > 0 ? helper.Link("Food", new {page = page - 1}) : "";
            //var nextUrl = page > 0 ? helper.Link("Food", new {page  = page + 1}) : "";
            
            //输出总数
            var totalCount = baseQuery.Count();
            var totalPages = Math.Ceiling((double)totalCount/PAGE_SIZE);
            
            var result = baseQuery
                            .Skip(PAGE_SIZE * page)
                            .Take(PAGE_SIZE)
                            .ToList()
                            .Select(f => TheModelFactory.FoodFromDomainToView(f));
                            
            //方便客户端接收
            return new
            {
                TotalCount = totalCount,
                TotalPages = totalPages,
                Result = result,
                Links = links
                //PrevPageUrl = prevUrl,
                //NextPageUrl = nextUrl,
            }
        }
        
        public FoodModel Get(int foodid)
        {
            return TheModelFactory.FoodFromDomainToView(TheRepository.GetFood(foodid));
        }
    }

    客户端请求:localhost:8901/api/nutrition/foods

    {
        totalCount:800,
        totalPages:151,
        links: [
            {
                href: http://localhost:8901/api/nutrition/foods?page=1,
                rel: "prevPage",
                method: "GET",
                isTemplated: false,
            },
            {
                href: http://localhost:8901/api/nutrition/foods?page=2,
                rel: "nextPage",
                method: "GET",
                isTemplated: false
            }
        ],
        result: [...]
    }


    另外,还可以控制序列化过程。

    在LinkModel这个视图中:

    public class LinkModel
    {
        public stirng Href{get;set;}
        public stirng Rel{get;set;}
        public string Method{get;set;}
        public bool IsTemplated{get;set;}
    }

    在显示的时候,可能不想让IsTemplated显示出来,如何在序列化的过程中做到呢?

    --通过jsonFormatter.SerializerSettings.Converts属性,用来控制序列化为json数据时的显示方式。

    在WebApiConfig.cs中:

    var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().FirstOrDefault();
    jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNameContractResolver();
    jsonFormatter.SerializerSettings.Converts(new LinkModelConverter());

    而LinkModelConverter类需要继承JsonConverter类。

    public class LinkModelConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType.Equals(typeof(LinkModel));
        }
        
        public override object ReadJson(JsonReader reader, Type object)
        {
            return reader.Value;
        }
        
        public override void WriteJson(JsonWriter wrtier, object value)
        {
            var model = value as LinkModel;
            if(model != null)
            {
                wirter.WriteStartObject();
                
                writer.WirteProeprtyName("href");
                writer.WriteValue(model.Href);
                
                writer.WriteProeprtyName("rel");
                writer.WriteValue(model.Rel);
                
                if(!model.Method.Equals("GET",StringComparison.ordinalIgnoreCase))
                {
                    writer.WritePropertyName("method");
                    writer.WriteValue(model.Method);
                }
                
                if(model.IsTemplated)
                {
                    writer.WriterPropertyName("isTemplated");
                    writer.WriteValue(model.IsTemplated);
                }
                
                writer.WriteEndObject();
            }
        }
    }
  • 相关阅读:
    iperf简单说明
    计算后图像大小参数计算
    ipywidgets安装报错
    Cannot uninstall [pacakage]. It is a distutils installed project
    torch
    es-centos7安装注意细节
    jupyter 指定特定的环境
    未来方向
    深度学习过拟合处理
    归一化
  • 原文地址:https://www.cnblogs.com/darrenji/p/5144162.html
Copyright © 2011-2022 走看看