The ASP. NET Web API displays entity Link-related aspects, apilink
Sometimes, when we request an object from the server, we want to return the following format:
Links :[
Href: http: // localhost: 8901/api/user/diaries/2013-08-17,
Rel: "self ",
Method: "GET ",
IsTemplated: false
],
CurrentDate: "2013-08-17"
First, a Link-related class is abstracted:
public class LinkModel{ public stirng Href{get;set;} public stirng Rel{get;set;} public string Method{get;set;} public bool IsTemplated{get;set;}}
Put it in a view model:
Public class DiaryModel {// storage and model-related Links 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 is used to convert the view model and the domain model.
Public class ModelFactory {private UrlHelper _ urlHelper; public ModelFactory (HttpRequestMessage request) {_ urlHelper = new UrlHelper (request );} // convert the domain model to the view Model 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 LinkMode L CreateLink (string href, string rel, string method = "GET", bool isTemplated = false) {return new LinkModel () {Href = href, Rel = rel, Method = method, isTemplated = isTemplated }}// the view model is converted to the 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) {// retrieve the primary key var Uri = new uri (selfLink. href); entity. id = int. parse (uri. segments. last ();} entity. currentDate = model. currentDate; return entity;} catch (Exception ex ){}}}
Diaries controller, routing:
//api/user/diaries//api/user/diaries/2001-01-01config.Routes.MapHttpRoute( name: "Diaries", routeTemplate: "api/user/diaries/{dairyid}", defaults: new {controller="diaries", diaryid=RouteParameter.Optional})
In this way, send the http: // localhost: 8901/api/user/diaries/2013-08-17 GET request on the client and GET the following response:
Links :[
Href: http: // localhost: 8901/api/user/diaries/2013-08-17,
Rel: "self ",
Method: "GET ",
IsTemplated: false
],
CurrentDate: "2013-08-17"
In the actions related to the returned page, you can also return the related Link section.
First define a base class controller:
Public abstract class BaseController: ApiController {ICountingKsRepository _ repo; ModelFactory _ modelFactory; public BaseController (ICountingKsRepository repo) {_ repo = repo; // it is a bit late to write in the constructor, you must wait for the instantiate _ modelFactory to have a value // _ modelFactory = new ModelFactory (this. request);} protected ModelFactory TheModelFactory {get {if (_ modelFactory = null) {_ modelFactory = new ModelFactory (this. request, TheRepository);} return _ modelFactory;} protected ICountingsRepository thereappsitory {get {return _ repo ;}}}
It can be seen that it is a good habit to encapsulate the common part into the base class controller, and then the base class controller subclass obtains some aspects through the attribute.
To the specific controller:
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 ();} // Calculate the total 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 "));}/ /Save the url of the previous and next pages. // var prevUrl = page> 0? Helper. Link ("Food", new {page = page-1}): ""; // var nextUrl = page> 0? Helper. link ("Food", new {page = page + 1}): ""; // total output 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); // It is convenient for the client to receive 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 ));}}
Client request: 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: [...]
}
In addition, the serialization process can be controlled.
In the LinkModel View:
public class LinkModel{ public stirng Href{get;set;} public stirng Rel{get;set;} public string Method{get;set;} public bool IsTemplated{get;set;}}
I may not want IsTemplated to be displayed. How can I achieve this in the serialization process?
-- Use the jsonFormatter. SerializerSettings. Converts attribute to control the display mode of serialized json data.
In WebApiConfig. cs:
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().FirstOrDefault();jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNameContractResolver();jsonFormatter.SerializerSettings.Converts(new LinkModelConverter());
The LinkModelConverter class must inherit the JsonConverter class.
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(); } }}