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

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 = ; public object Get(bool includeMeasures = true, int page = )
{
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 > )
{
links.Add(TheModelFactory.CreateLink(helper.Link("Food", new {page = page - },"prevPage"));
} if(page < totalPages - )
{
links.Add(TheModelFactory.CreateLink(helper.Link("Food", new {page = page + },"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();
}
}
}

ASP.NET Web API中展示实体Link相关的方面的更多相关文章

  1. 在ASP.NET Web API中使用OData

    http://www.alixixi.com/program/a/2015063094986.shtml 一.什么是ODataOData是一个开放的数据协议(Open Data Protocol)在A ...

  2. 【ASP.NET Web API教程】6.2 ASP.NET Web API中的JSON和XML序列化

    谨以此文感谢关注此系列文章的园友!前段时间本以为此系列文章已没多少人关注,而不打算继续下去了.因为文章贴出来之后,看的人似乎不多,也很少有人对这些文章发表评论,而且几乎无人给予“推荐”.但前几天有人询 ...

  3. ASP.NET Web API中使用OData

    在ASP.NET Web API中使用OData 一.什么是ODataOData是一个开放的数据协议(Open Data Protocol)在ASP.NET Web API中,对于CRUD(creat ...

  4. Asp.Net Web Api中使用Swagger

    关于swagger 设计是API开发的基础.Swagger使API设计变得轻而易举,为开发人员.架构师和产品所有者提供了易于使用的工具. 官方网址:https://swagger.io/solutio ...

  5. 利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理

    在Asp.net Web API中,对业务数据的分页查询处理是一个非常常见的接口,我们需要在查询条件对象中,定义好相应业务的查询参数,排序信息,请求记录数和每页大小信息等内容,根据这些查询信息,我们在 ...

  6. ASP.NET Web API中的Controller

    虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要 ...

  7. ASP.NET Web API 中的异常处理(转载)

    转载地址:ASP.NET Web API 中的异常处理

  8. Asp.Net Web API 2第十三课——ASP.NET Web API中的JSON和XML序列化

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文描述ASP.NET W ...

  9. ASP.NET WEB API 中的路由调试与执行过程跟踪

    路由调试 RouteDebugger 是调试 ASP.NET MVC 路由的一个好的工具,在ASP.NET WEB API中相应的有 WebApiRouteDebugger ,Nuget安装 Inst ...

随机推荐

  1. umount /mnt/cdrom

    这是因为有程序正在访问这个设备,最简单的办法就是让访问该设备的程序退出以后再umount.可能有时候用户搞不清除究竟是什么程序在访问设备,如果用户不急着umount,则可以用: umount -l / ...

  2. 002_分布式搜索引擎Elasticsearch的查询与过滤

    一.写入 先来一个简单的官方例子,插入的参数为-XPUT,插入一条记录. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 curl -XPUT 'http:/ ...

  3. Uploadify3.2中文提示

    版本:Uploadify Version 3.2官网:http://www.uploadify.com Uploadify是一款基于Jquery的上传插件,用起来很方便.但上传过程中的提示语言为英文, ...

  4. jexus docker

    一.准备工作 1.init.sh 文件 #!/bin/bash # Stop your services function stop_svc { /usr/jexus/jws stop >/de ...

  5. Android BLE设备蓝牙通信框架BluetoothKit

    BluetoothKit是一款功能强大的Android蓝牙通信框架,支持低功耗蓝牙设备的连接通信.蓝牙广播扫描及Beacon解析. 关于该项目的详细文档请关注:https://github.com/d ...

  6. DedeCMS常见问题和技巧

    1: dedecms 访问空白(织梦如何显示详细错误) 我们在使用织梦的时候,有的时候会遇到访问空白的情况,尤其是再刚刚搬家之后,织梦会出现访问空白或者返给您一个500的友好界面错误,遇到这种情况该怎 ...

  7. scanf 输入加逗号(或者不加逗号)出现的异常及解决方案

    我们在写 C 语言代码通常 scanf 的格式控制部分都有两种习惯,加逗号与不加逗号,而这两种情况都会因为我们的不同输入习惯产生一定的问题,这里给出另一种方法. 1.不加逗号 #include< ...

  8. 前端Datatables自定义事件(监听Datatables插件一些常见的事件动作)

    今天开发项目的时候,用Datatables插件做前端分页列表,想在列表发生翻页.排序.搜索.改变单页显示数据条数这些行为的时候做一些其他的操作,看了半天Datatables官网终于找到可以监测到这些事 ...

  9. 【LOJ】#2075. 「JSOI2016」位运算

    题解 压的状态是一个二进制位,我们规定1到n的数字互不相同是从小到大,二进制位记录的是每一位和后一个数是否相等,第n位记录第n个数和原串是否相等,处理出50个转移矩阵然后相乘,再快速幂即可 代码 #i ...

  10. 日志收集框架flume的安装及简单使用

    flume介绍 Flume是一个分布式.可靠.和高可用的海量日志采集.聚合和传输的系统. Flume可以采集文件,socket数据包等各种形式源数据,又可以将采集到的数据输出到HDFS.hbase.h ...