我为迷宫游戏服务创建了 Web API 项目。它使用WebApi.Hal来返回hal+json
和hal+xml
媒体类型。它在大多数情况下都有效——除了以下问题。
- 虽然 page 在请求中是 2,但它返回所有页面的所有单元格。如何纠正它?
- 在 hal+json 中,除了嵌入的单元格之外,还有指向自身中所有单元格的“链接”。在 hal+xml 中,只有嵌入的单元格。为什么有区别?哪个是对的?
有一个链接添加为
rel="page" href="~/api/cells/page/{page}"
。尽管我已经编写了以下代码,但为什么会rel
以“页面”的形式出现`public static Link GetCells { get { return new Link("cell","~/api/cells/page/{page}"); } }
- searchTerm 添加了一个链接。如何在客户端使用它?我找不到任何有用的例子。
- 所有的细胞都是嵌入的。是正确的
HAL
收藏方式吗?还是应该是链接?
请求:http://localhost:51910/api/cells/page/2
应用程序/hal+xml
<?xml version="1.0" encoding="utf-8"?>
<resource rel="" href="~/api/cells/page/2">
<link rel="prev" href="~/api/cells/page/1" />
<link rel="next" href="~/api/cells/page/3" />
<link rel="page" href="~/api/cells/page/{page}" />
<link rel="page" href="~/api/cells{?searchTerm,page}" />
<TotalResults>6</TotalResults>
<TotalPages>3</TotalPages>
<Page>2</Page>
<resource rel="self" href="~/api/cells/00">
<link rel="left" href="~/api/cells/10" />
<link rel="left" href="~/api/cells/01" />
<CellID>00</CellID>
<IsExit>False</IsExit>
</resource>
<resource rel="self" href="~/api/cells/10">
<link rel="down" href="~/api/cells/00" />
<link rel="down" href="~/api/cells/20" />
<CellID>10</CellID>
<IsExit>False</IsExit>
</resource>
<resource rel="self" href="~/api/cells/20">
<link rel="left" href="~/api/cells/10" />
<link rel="right" href="~/api/cells/21" />
<CellID>20</CellID>
<IsExit>False</IsExit>
</resource>
<resource rel="self" href="~/api/cells/01">
<link rel="down" href="~/api/cells/00" />
<link rel="left" href="~/api/cells/11" />
<CellID>01</CellID>
<IsExit>False</IsExit>
</resource>
<resource rel="self" href="~/api/cells/11">
<link rel="left" href="~/api/cells/01" />
<link rel="right" href="~/api/cells/21" />
<CellID>11</CellID>
<IsExit>False</IsExit>
</resource>
<resource rel="self" href="~/api/cells/21">
<link rel="down" href="~/api/cells/20" />
<link rel="left" href="~/api/cells/11" />
<CellID>21</CellID>
<IsExit>False</IsExit>
</resource>
</resource>
应用程序/hal+json
控制器
public class CellsController : ApiController
{
//Get all cells in the maze
[HttpGet]
[Route("api/cells")]
public CellListRep Get()
{
Maze m = new Maze();
int page = 1;
int totalPages = 1;
List<CellRepresentation> cellRepresentations = GetAllCellRepresentation(m);
int totalCells = cellRepresentations.Count;
return new CellListRep(cellRepresentations, totalCells, totalPages, page, LinkTemplates.CellLinks.GetCells);
}
//Get paged list
[HttpGet]
[Route("api/cells/page/{page}")]
public CellListRep Get(int page)
{
Maze m = new Maze();
List<CellRepresentation> cellRepresentations = GetAllCellRepresentation(m);
int totalCells = cellRepresentations.Count;
int totalPages = cellRepresentations.Count / 2;
return new CellListRep(cellRepresentations, totalCells, totalPages, page, LinkTemplates.CellLinks.GetCells);
}
//Get specific cell
[HttpGet]
[Route("api/cells/{id}")]
public CellRepresentation Get(string id)
{
Maze m = new Maze();
Cell c = m.GetSpecificCell(id);
List<Cell> possibleLists = m.GetPossibleRelatedCells(c);
CellRepresentation beerRep = new CellRepresentation(c, possibleLists);
return beerRep;
}
private List<CellRepresentation> GetAllCellRepresentation(Maze m)
{
List<CellRepresentation> cellRepresentations = new List<CellRepresentation>();
List<Cell> cells = m.GetAllCells();
foreach (Cell c in cells)
{
List<Cell> possibleLists = m.GetPossibleRelatedCells(c);
CellRepresentation beerRep = new CellRepresentation(c, possibleLists);
cellRepresentations.Add(beerRep);
}
return cellRepresentations;
}
}
表示和链接
public static class LinkTemplates
{
public static class CellLinks
{
public static Link CellEntry { get { return new Link("self", "~/api/cells/{id}"); } }
public static Link UpLink { get { return new Link("up", "~/api/cells/{id}"); } }
public static Link RightLink { get { return new Link("right", "~/api/cells/{id}"); } }
public static Link DownLink { get { return new Link("down", "~/api/cells/{id}"); } }
public static Link LeftLink { get { return new Link("left", "~/api/cells/{id}"); } }
public static Link GetCells { get { return new Link("cell", "~/api/cells/page/{page}"); } }
public static Link SearchCells { get { return new Link("page", "~/api/cells{?searchTerm,page}"); } }
}
}
public class CellRepresentation : WebApi.Hal.Representation
{
Cell theCell;
List<Cell> possibleMoveCells;
public String CellID
{
get
{
return theCell.CellID ;
}
}
public bool IsExit
{
get
{
return theCell.IsExtCell;
}
}
public CellRepresentation(Cell c, List<Cell> possibleMoveCells )
{
theCell = c;
//_cellIDVal = c.CellID;
this.possibleMoveCells = possibleMoveCells;
}
public override string Rel
{
get { return LinkTemplates.CellLinks.CellEntry.Rel; }
set { }
}
public override string Href
{
get { return LinkTemplates.CellLinks.CellEntry.CreateLink(new { id = theCell.CellID }).Href; }
set { }
}
protected override void CreateHypermedia()
{
foreach (Cell relatedCell in possibleMoveCells)
{
if (relatedCell.RelativeName == "Up")
{
Links.Add(LinkTemplates.CellLinks.UpLink.CreateLink(new { id = relatedCell.CellID }));
}
if (relatedCell.RelativeName == "Right")
{
Links.Add(LinkTemplates.CellLinks.RightLink.CreateLink(new { id = relatedCell.CellID }));
}
if (relatedCell.RelativeName == "Down")
{
Links.Add(LinkTemplates.CellLinks.DownLink.CreateLink(new { id = relatedCell.CellID }));
}
if (relatedCell.RelativeName == "Left")
{
Links.Add(LinkTemplates.CellLinks.LeftLink.CreateLink(new { id = relatedCell.CellID }));
}
}
}
}
public class CellListRep : PagedRepresentationList<CellRepresentation>
{
public CellListRep(IList<CellRepresentation> beers, int totalResults, int totalPages, int page, Link uriTemplate) :
base(beers, totalResults, totalPages, page, uriTemplate, null)
{ }
public CellListRep(IList<CellRepresentation> beers, int totalResults, int totalPages, int page, Link uriTemplate,
object uriTemplateSubstitutionParams) :
base(beers, totalResults, totalPages, page, uriTemplate, uriTemplateSubstitutionParams)
{ }
protected override void CreateHypermedia()
{
base.CreateHypermedia();
var search = LinkTemplates.CellLinks.SearchCells;
if (Links.Count(l => l.Rel == search.Rel && l.Href == search.Href) == 0)
{
Links.Add(LinkTemplates.CellLinks.SearchCells);
}
}
}
public abstract class PagedRepresentationList<TRepresentation> : SimpleListRepresentation<TRepresentation> where TRepresentation : Representation
{
readonly Link uriTemplate;
protected PagedRepresentationList(IList<TRepresentation> res, int totalResults, int totalPages, int page, Link uriTemplate, object uriTemplateSubstitutionParams)
: base(res)
{
this.uriTemplate = uriTemplate;
TotalResults = totalResults;
TotalPages = totalPages;
Page = page;
UriTemplateSubstitutionParams = uriTemplateSubstitutionParams;
}
public int TotalResults { get; set; }
public int TotalPages { get; set; }
public int Page { get; set; }
protected object UriTemplateSubstitutionParams;
protected override void CreateHypermedia()
{
var prms = new List<object> { new { page = Page } };
if (UriTemplateSubstitutionParams != null)
prms.Add(UriTemplateSubstitutionParams);
Href = Href ?? uriTemplate.CreateLink(prms.ToArray()).Href;
Links.Add(new Link { Href = Href, Rel = "self" });
if (Page > 1)
{
var item = UriTemplateSubstitutionParams == null
? uriTemplate.CreateLink("prev", new { page = Page - 1 })
: uriTemplate.CreateLink("prev", UriTemplateSubstitutionParams, new { page = Page - 1 }); // page overrides UriTemplateSubstitutionParams
Links.Add(item);
}
if (Page < TotalPages)
{
var link = UriTemplateSubstitutionParams == null // kbr
? uriTemplate.CreateLink("next", new { page = Page + 1 })
: uriTemplate.CreateLink("next", UriTemplateSubstitutionParams, new { page = Page + 1 }); // page overrides UriTemplateSubstitutionParams
Links.Add(link);
}
Links.Add(new Link("page", uriTemplate.Href));
}
}
商务舱
public class Cell
{
public int XVal { get; set; }
public int YVal { get; set; }
public bool TopIsWall { get; set; }
public bool RightIsWall { get; set; }
public bool BottomIsWall { get; set; }
public bool LeftIsWall { get; set; }
public bool IsStartCell { get; set; }
public bool IsExtCell { get; set; }
public string RelativeName { get; set; } //Top, Right, Etc.
public string CellID
{
get
{
string characterID = XVal.ToString() + YVal.ToString();
return characterID; //Example 10
}
}
}
public class Maze
{
List<Cell> cells;
public Maze()
{
cells = CreateCells();
}
public Cell GetFirtCell()
{
Cell firstCell = null;
foreach (Cell c in cells)
{
if(c.IsStartCell )
{
firstCell = c;
break;
}
}
return firstCell;
}
public Cell GetSpecificCell(string cellID)
{
Cell theCell = null;
foreach (Cell c in cells)
{
if (c.CellID == cellID)
{
theCell = c;
break;
}
}
return theCell;
}
public List<Cell> GetAllCells()
{
return cells;
}
public List<Cell> GetPossibleRelatedCells(Cell inputCell)
{
List<Cell> possibleCells = new List<Cell>();
foreach (Cell c in cells)
{
if (c.YVal == 2 && c.XVal == 3)
{
int test = 0;
}
if (c.XVal == inputCell.XVal-1 && c.RightIsWall == false && c.YVal== inputCell.YVal )
{
//Go left from the input cell
c.RelativeName = "Left";
possibleCells.Add(c);
}
else if (c.XVal == inputCell.XVal + 1 && c.LeftIsWall == false && c.YVal == inputCell.YVal )
{
//Go right from the input cell
c.RelativeName = "Right";
possibleCells.Add(c);
}
else if (c.YVal == inputCell.YVal - 1 && c.TopIsWall == false && c.XVal == inputCell.XVal )
{
//Go down from the input cell
c.RelativeName = "Down";
possibleCells.Add(c);
}
else if (c.YVal == inputCell.YVal + 1 && c.BottomIsWall == false && c.XVal == inputCell.XVal)
{
//Go up from the input cell
c.RelativeName = "Up";
possibleCells.Add(c);
}
}
return possibleCells;
}
public List<Cell> CreateCells()
{
List<Cell> cells = new List<Cell>();
Cell cell1 = new Cell
{
XVal = 0,YVal = 0,TopIsWall = false,RightIsWall = false,BottomIsWall = true,LeftIsWall = true,
RelativeName="Self"
};
Cell cell2 = new Cell
{
XVal = 1,YVal = 0,TopIsWall = true,RightIsWall = false,BottomIsWall = false,LeftIsWall = false,
IsStartCell = true, //--Start
RelativeName="Self"
};
Cell cell3 = new Cell
{
XVal = 2,YVal = 0,TopIsWall = false,RightIsWall = false,BottomIsWall = true,LeftIsWall = false,
RelativeName="Self"
};
Cell cell5 = new Cell
{
XVal = 0,YVal = 1,TopIsWall = true,RightIsWall = false,BottomIsWall = false,LeftIsWall = true,
RelativeName = "Self"
};
Cell cell7 = new Cell
{
XVal = 1,YVal = 1,TopIsWall = true,RightIsWall = false,BottomIsWall = true,LeftIsWall = false,
RelativeName = "Self"
};
Cell cell8 = new Cell
{
XVal = 2,YVal = 1,TopIsWall = false,RightIsWall = true,BottomIsWall = false,LeftIsWall = false,
RelativeName = "Self"
};
cells.Add(cell1);
cells.Add(cell2);
cells.Add(cell3);
cells.Add(cell5);
cells.Add(cell7);
cells.Add(cell8);
return cells;
}
}