Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Renamed Resource to Representation, Removed Linkers

  • Loading branch information...
commit 6a1f5eda4574183f579ca91937f6b26237ea04c1 1 parent f6b31d2
@JakeGinnivan authored
Showing with 559 additions and 545 deletions.
  1. +6 −12 WebApi.Hal.Tests/HalResourceListTests.cs
  2. +0 −4 WebApi.Hal.Tests/HalResourceTest.cs
  3. +2 −6 WebApi.Hal.Tests/HalResourceWithPeopleTest.cs
  4. +3 −3 WebApi.Hal.Tests/HalResourceWithPeopleTest.organisation_get_json_test.approved.txt
  5. +0 −14 WebApi.Hal.Tests/Linkers/OrganisationLinker.cs
  6. +0 −19 WebApi.Hal.Tests/Linkers/OrganisationListLinker.cs
  7. +0 −19 WebApi.Hal.Tests/Linkers/OrganisationWithPeopleLinker.cs
  8. +19 −0 WebApi.Hal.Tests/Representations/OrganisationListRepresentation.cs
  9. +7 −1 WebApi.Hal.Tests/Representations/OrganisationRepresentation.cs
  10. +30 −0 WebApi.Hal.Tests/Representations/OrganisationWithPeopleRepresentation.cs
  11. +0 −33 WebApi.Hal.Tests/ResourceLinkerTests.cs
  12. +2 −4 WebApi.Hal.Tests/WebApi.Hal.Tests.csproj
  13. +19 −0 WebApi.Hal.Tests/WebApi.Hal.Tests.ncrunchproject
  14. +13 −16 WebApi.Hal.Web/Api/BeersController.cs
  15. +10 −13 WebApi.Hal.Web/Api/BreweriesController.cs
  16. +0 −20 WebApi.Hal.Web/Api/Linkers/BeerLinker.cs
  17. +0 −23 WebApi.Hal.Web/Api/Linkers/BeerListLinker.cs
  18. +0 −15 WebApi.Hal.Web/Api/Linkers/BeerStyleLinker.cs
  19. +0 −20 WebApi.Hal.Web/Api/Linkers/BeerStyleListLinker.cs
  20. +0 −15 WebApi.Hal.Web/Api/Linkers/BreweryLinker.cs
  21. +0 −20 WebApi.Hal.Web/Api/Linkers/BreweryListLinker.cs
  22. +23 −0 WebApi.Hal.Web/Api/Resources/BeerListRepresentation.cs
  23. +0 −13 WebApi.Hal.Web/Api/Resources/BeerListResource.cs
  24. +26 −0 WebApi.Hal.Web/Api/Resources/BeerRepresentation.cs
  25. +0 −14 WebApi.Hal.Web/Api/Resources/BeerResource.cs
  26. +19 −0 WebApi.Hal.Web/Api/Resources/BeerStyleListRepresentation.cs
  27. +0 −12 WebApi.Hal.Web/Api/Resources/BeerStyleListResource.cs
  28. +15 −0 WebApi.Hal.Web/Api/Resources/BeerStyleRepresentation.cs
  29. +0 −8 WebApi.Hal.Web/Api/Resources/BeerStyleResource.cs
  30. +19 −0 WebApi.Hal.Web/Api/Resources/BreweryListRepresentation.cs
  31. +0 −12 WebApi.Hal.Web/Api/Resources/BreweryListResource.cs
  32. +16 −0 WebApi.Hal.Web/Api/Resources/BreweryRepresentation.cs
  33. +0 −9 WebApi.Hal.Web/Api/Resources/BreweryResource.cs
  34. +11 −14 WebApi.Hal.Web/Api/StylesController.cs
  35. +4 −4 WebApi.Hal.Web/Data/Queries/GetBeersQuery.cs
  36. +2 −10 WebApi.Hal.Web/Global.asax.cs
  37. +6 −12 WebApi.Hal.Web/WebApi.Hal.Web.csproj
  38. +19 −0 WebApi.Hal.Web/WebApi.Hal.Web.ncrunchproject
  39. +2 −2 WebApi.Hal.ncrunchsolution
  40. +88 −0 WebApi.Hal/HypermediaList.cs
  41. +8 −0 WebApi.Hal/Interfaces/IRepresentationList.cs
  42. +1 −1  WebApi.Hal/Interfaces/IResource.cs
  43. +0 −7 WebApi.Hal/Interfaces/IResourceLinker.cs
  44. +0 −7 WebApi.Hal/Interfaces/IResourceLinker`1.cs
  45. +0 −8 WebApi.Hal/Interfaces/IResourceList.cs
  46. +2 −2 WebApi.Hal/JsonConverters/LinksConverter.cs
  47. +4 −4 WebApi.Hal/JsonConverters/ResourceConverter.cs
  48. +5 −5 WebApi.Hal/JsonConverters/ResourceListConverter.cs
  49. +2 −2 WebApi.Hal/JsonHalMediaTypeFormatter.cs
  50. +2 −1  WebApi.Hal/Link.cs
  51. +2 −7 WebApi.Hal/ReflectionExtensions.cs
  52. +103 −0 WebApi.Hal/Representation.cs
  53. +2 −7 WebApi.Hal/{ResourceList.cs → RepresentationList.cs}
  54. +0 −26 WebApi.Hal/Resource.cs
  55. +0 −56 WebApi.Hal/ResourceLinker.cs
  56. +4 −6 WebApi.Hal/WebApi.Hal.csproj
  57. +19 −0 WebApi.Hal/WebApi.Hal.ncrunchproject
  58. +44 −39 WebApi.Hal/XmlHalMediaTypeFormatter.cs
View
18 WebApi.Hal.Tests/HalResourceListTests.cs
@@ -3,7 +3,6 @@
using System.Net.Http;
using ApprovalTests;
using ApprovalTests.Reporters;
-using WebApi.Hal.Tests.Linkers;
using WebApi.Hal.Tests.Representations;
using Xunit;
@@ -11,21 +10,16 @@ namespace WebApi.Hal.Tests
{
public class HalResourceListTests
{
- readonly ResourceLinker resourceLinker;
- readonly ResourceList<OrganisationRepresentation> resource;
+ readonly RepresentationList<OrganisationRepresentation> representation;
public HalResourceListTests()
{
- resourceLinker = new ResourceLinker();
- resourceLinker.AddLinker(new OrganisationListLinker());
- resourceLinker.AddLinker(new OrganisationLinker());
- resource = new ResourceList<OrganisationRepresentation>(
+ representation = new OrganisationListRepresentation(
new List<OrganisationRepresentation>
{
new OrganisationRepresentation(1, "Org1"),
new OrganisationRepresentation(2, "Org2")
});
- resourceLinker.CreateLinks(resource);
}
[Fact]
@@ -35,12 +29,12 @@ public void organisation_list_get_xml_test()
// arrange
var mediaFormatter = new XmlHalMediaTypeFormatter();
var contentHeaders = new StringContent(string.Empty).Headers;
- var type = resource.GetType();
+ var type = representation.GetType();
// act
using (var stream = new MemoryStream())
{
- mediaFormatter.WriteToStream(type, resource, stream, contentHeaders);
+ mediaFormatter.WriteToStream(type, representation, stream, contentHeaders);
stream.Seek(0, SeekOrigin.Begin);
var serialisedResult = new StreamReader(stream).ReadToEnd();
@@ -56,12 +50,12 @@ public void organisation_list_get_json_test()
// arrange
var mediaFormatter = new JsonHalMediaTypeFormatter { Indent = true };
var contentHeaders = new StringContent(string.Empty).Headers;
- var type = resource.GetType();
+ var type = representation.GetType();
// act
using (var stream = new MemoryStream())
{
- mediaFormatter.WriteToStreamAsync(type, resource, stream, contentHeaders, null).Wait();
+ mediaFormatter.WriteToStreamAsync(type, representation, stream, contentHeaders, null).Wait();
stream.Seek(0, SeekOrigin.Begin);
var serialisedResult = new StreamReader(stream).ReadToEnd();
View
4 WebApi.Hal.Tests/HalResourceTest.cs
@@ -2,7 +2,6 @@
using System.Net.Http;
using ApprovalTests;
using ApprovalTests.Reporters;
-using WebApi.Hal.Tests.Linkers;
using WebApi.Hal.Tests.Representations;
using Xunit;
@@ -15,9 +14,6 @@ public class HalResourceTest
public HalResourceTest()
{
resource = new OrganisationRepresentation(1, "Org Name");
- var linker = new ResourceLinker();
- linker.AddLinker(new OrganisationLinker());
- linker.CreateLinks(resource);
}
[Fact]
View
8 WebApi.Hal.Tests/HalResourceWithPeopleTest.cs
@@ -2,7 +2,6 @@
using System.Net.Http;
using ApprovalTests;
using ApprovalTests.Reporters;
-using WebApi.Hal.Tests.Linkers;
using WebApi.Hal.Tests.Representations;
using Xunit;
@@ -10,14 +9,11 @@ namespace WebApi.Hal.Tests
{
public class HalResourceWithPeopleTest
{
- readonly OrganisationRepresentation resource;
+ readonly OrganisationWithPeopleRepresentation resource;
public HalResourceWithPeopleTest()
{
- resource = new OrganisationRepresentation(1, "Org Name");
- var linker = new ResourceLinker();
- linker.AddLinker(new OrganisationWithPeopleLinker());
- linker.CreateLinks(resource);
+ resource = new OrganisationWithPeopleRepresentation(1, "Org Name");
}
[Fact]
View
6 WebApi.Hal.Tests/HalResourceWithPeopleTest.organisation_get_json_test.approved.txt
@@ -2,11 +2,11 @@
"Id": 1,
"Name": "Org Name",
"_links": {
- "people": {
- "href": "/api/organisations/1/people"
- },
"self": {
"href": "/api/organisations/1"
+ },
+ "people": {
+ "href": "/api/organisations/1/people"
}
}
}
View
14 WebApi.Hal.Tests/Linkers/OrganisationLinker.cs
@@ -1,14 +0,0 @@
-using WebApi.Hal.Interfaces;
-using WebApi.Hal.Tests.Representations;
-
-namespace WebApi.Hal.Tests.Linkers
-{
- public class OrganisationLinker : IResourceLinker<OrganisationRepresentation>
- {
- public void CreateLinks(OrganisationRepresentation resource, IResourceLinker resourceLinker)
- {
- resource.Rel = "organisation";
- resource.Href = string.Format("/api/organisations/{0}", resource.Id);
- }
- }
-}
View
19 WebApi.Hal.Tests/Linkers/OrganisationListLinker.cs
@@ -1,19 +0,0 @@
-using WebApi.Hal.Interfaces;
-using WebApi.Hal.Tests.Representations;
-
-namespace WebApi.Hal.Tests.Linkers
-{
- public class OrganisationListLinker : IResourceLinker<ResourceList<OrganisationRepresentation>>
- {
- public void CreateLinks(ResourceList<OrganisationRepresentation> resource, IResourceLinker resourceLinker)
- {
- resource.Rel = "organisations";
- resource.Href = "/api/organisations";
-
- foreach (var organisationRepresentation in resource)
- {
- resourceLinker.CreateLinks(organisationRepresentation);
- }
- }
- }
-}
View
19 WebApi.Hal.Tests/Linkers/OrganisationWithPeopleLinker.cs
@@ -1,19 +0,0 @@
-using WebApi.Hal.Interfaces;
-using WebApi.Hal.Tests.Representations;
-
-namespace WebApi.Hal.Tests.Linkers
-{
- public class OrganisationWithPeopleLinker : IResourceLinker<OrganisationRepresentation>
- {
- public void CreateLinks(OrganisationRepresentation resource, IResourceLinker resourceLinker)
- {
- resource.Rel = "organisation";
- resource.Href = string.Format("/api/organisations/{0}", resource.Id);
- resource.Links.Add(new Link
- {
- Rel = "people",
- Href = string.Format("/api/organisations/{0}/people", resource.Id)
- });
- }
- }
-}
View
19 WebApi.Hal.Tests/Representations/OrganisationListRepresentation.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+
+namespace WebApi.Hal.Tests.Representations
+{
+ public class OrganisationListRepresentation : RepresentationList<OrganisationRepresentation>
+ {
+ public OrganisationListRepresentation(IList<OrganisationRepresentation> organisationRepresentations) :
+ base(organisationRepresentations)
+ {
+
+ }
+
+ protected override void CreateHypermedia()
+ {
+ Rel = "organisations";
+ Href = "/api/organisations";
+ }
+ }
+}
View
8 WebApi.Hal.Tests/Representations/OrganisationRepresentation.cs
@@ -1,6 +1,6 @@
namespace WebApi.Hal.Tests.Representations
{
- public class OrganisationRepresentation : Resource
+ public class OrganisationRepresentation : Representation
{
public OrganisationRepresentation()
{
@@ -14,5 +14,11 @@ public OrganisationRepresentation(int id, string name)
public int Id { get; set; }
public string Name { get; set; }
+
+ protected override void CreateHypermedia()
+ {
+ Rel = "organisation";
+ Href = string.Format("/api/organisations/{0}", Id);
+ }
}
}
View
30 WebApi.Hal.Tests/Representations/OrganisationWithPeopleRepresentation.cs
@@ -0,0 +1,30 @@
+namespace WebApi.Hal.Tests.Representations
+{
+ public class OrganisationWithPeopleRepresentation : Representation
+ {
+ public OrganisationWithPeopleRepresentation()
+ {
+ }
+
+ public OrganisationWithPeopleRepresentation(int id, string name)
+ {
+ Id = id;
+ Name = name;
+ }
+
+ public int Id { get; set; }
+ public string Name { get; set; }
+
+ protected override void CreateHypermedia()
+ {
+ Rel = "organisation";
+ Href = string.Format("/api/organisations/{0}", Id);
+
+ Links.Add(new Link
+ {
+ Rel = "people",
+ Href = string.Format("/api/organisations/{0}/people", Id)
+ });
+ }
+ }
+}
View
33 WebApi.Hal.Tests/ResourceLinkerTests.cs
@@ -1,33 +0,0 @@
-using System;
-using System.Collections.Generic;
-using ApprovalTests;
-using ApprovalTests.Reporters;
-using Xunit;
-
-namespace WebApi.Hal.Tests
-{
- public class ResourceLinkerTests
- {
- [Fact]
- [UseReporter(typeof(DiffReporter))]
- public void throws_meaningful_exception_when_cannot_find_linker()
- {
- // arrange
- var resourceLinker = new ResourceLinker();
- Exception exception = null;
-
- // act
- try
- {
- resourceLinker.CreateLinks(new List<Resource>());
- }
- catch (ArgumentException ex)
- {
- exception = ex;
- }
-
- // assert
- Approvals.Verify(exception.Message);
- }
- }
-}
View
6 WebApi.Hal.Tests/WebApi.Hal.Tests.csproj
@@ -55,13 +55,11 @@
<ItemGroup>
<Compile Include="HalResourceWithPeopleTest.cs" />
<Compile Include="HalResourceTest.cs" />
- <Compile Include="Linkers\OrganisationLinker.cs" />
- <Compile Include="Linkers\OrganisationListLinker.cs" />
- <Compile Include="Linkers\OrganisationWithPeopleLinker.cs" />
+ <Compile Include="Representations\OrganisationListRepresentation.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="HalResourceListTests.cs" />
<Compile Include="Representations\OrganisationRepresentation.cs" />
- <Compile Include="ResourceLinkerTests.cs" />
+ <Compile Include="Representations\OrganisationWithPeopleRepresentation.cs" />
<Compile Include="UriBuilderTests.cs" />
</ItemGroup>
<ItemGroup>
View
19 WebApi.Hal.Tests/WebApi.Hal.Tests.ncrunchproject
@@ -0,0 +1,19 @@
+<ProjectConfiguration>
+ <CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
+ <ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
+ <PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
+ <AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
+ <AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
+ <IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
+ <RunPreBuildEvents>false</RunPreBuildEvents>
+ <RunPostBuildEvents>false</RunPostBuildEvents>
+ <PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
+ <InstrumentAssembly>true</InstrumentAssembly>
+ <PreventSigningOfAssembly>false</PreventSigningOfAssembly>
+ <AnalyseExecutionTimes>true</AnalyseExecutionTimes>
+ <IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
+ <DefaultTestTimeout>60000</DefaultTestTimeout>
+ <UseBuildConfiguration />
+ <ProxyProcessPath />
+ <UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
+</ProjectConfiguration>
View
29 WebApi.Hal.Web/Api/BeersController.cs
@@ -2,7 +2,6 @@
using System.Net;
using System.Net.Http;
using System.Web.Http;
-using WebApi.Hal.Interfaces;
using WebApi.Hal.Web.Api.Resources;
using WebApi.Hal.Web.Data;
using WebApi.Hal.Web.Data.Queries;
@@ -14,49 +13,47 @@ public class BeersController : ApiController
{
public const int PageSize = 5;
- readonly IResourceLinker resourceLinker;
readonly IBeerDbContext beerDbContext;
readonly IRepository repository;
- public BeersController(IResourceLinker resourceLinker, IBeerDbContext beerDbContext, IRepository repository)
+ public BeersController(IBeerDbContext beerDbContext, IRepository repository)
{
- this.resourceLinker = resourceLinker;
this.beerDbContext = beerDbContext;
this.repository = repository;
}
// GET api/beers
- public BeerListResource Get()
+ public BeerListRepresentation Get()
{
return GetPage(1);
}
- public BeerListResource GetPage(int page)
+ public BeerListRepresentation GetPage(int page)
{
var beers = repository.Find(new GetBeersQuery(), page, PageSize);
- var resourceList = new BeerListResource(beers.ToList()) { Total = beers.TotalResults, Page = page };
+ var resourceList = new BeerListRepresentation(beers.ToList()) { Total = beers.TotalResults, Page = page };
if (page > 1)
resourceList.Links.Add(LinkTemplates.Beers.GetBeers.CreateLink("prev", _page => page - 1));
if (page < beers.TotalPages)
resourceList.Links.Add(LinkTemplates.Beers.GetBeers.CreateLink("next", _page => page + 1));
- return resourceLinker.CreateLinks(resourceList);
+ return resourceList;
}
[HttpGet]
- public BeerListResource Search(string searchTerm)
+ public BeerListRepresentation Search(string searchTerm)
{
return Search(searchTerm, 1);
}
- public BeerListResource Search(string searchTerm, int page)
+ public BeerListRepresentation Search(string searchTerm, int page)
{
var beers = repository.Find(new GetBeersQuery(b=>b.Name.Contains(searchTerm)), page, PageSize);
var link = LinkTemplates.Beers.SearchBeers.CreateLink(_searchTerm => searchTerm, _page => page);
- var beersResource = new BeerListResource(beers.ToList())
+ var beersResource = new BeerListRepresentation(beers.ToList())
{
Page = 1,
Total = beers.TotalResults,
@@ -69,15 +66,15 @@ public BeerListResource Search(string searchTerm, int page)
if (page < beers.TotalPages)
beersResource.Links.Add(LinkTemplates.Beers.SearchBeers.CreateLink("next", _searchTerm => searchTerm, _page => page + 1));
- return resourceLinker.CreateLinks(beersResource);
+ return beersResource;
}
// GET api/beers/5
- public BeerResource Get(int id)
+ public BeerRepresentation Get(int id)
{
var beer = beerDbContext.Beers.Find(id);
- return resourceLinker.CreateLinks(new BeerResource
+ return new BeerRepresentation
{
Id = beer.Id,
Name = beer.Name,
@@ -85,11 +82,11 @@ public BeerResource Get(int id)
BreweryName = beer.Brewery == null ? null : beer.Brewery.Name,
StyleId = beer.Style == null ? (int?)null : beer.Style.Id,
StyleName = beer.Style == null ? null : beer.Style.Name
- });
+ };
}
// POST api/beers
- public HttpResponseMessage Post(BeerResource value)
+ public HttpResponseMessage Post(BeerRepresentation value)
{
var newBeer = new Beer(value.Name);
beerDbContext.Beers.Add(newBeer);
View
23 WebApi.Hal.Web/Api/BreweriesController.cs
@@ -1,6 +1,5 @@
using System.Linq;
using System.Web.Http;
-using WebApi.Hal.Interfaces;
using WebApi.Hal.Web.Api.Resources;
using WebApi.Hal.Web.Data;
@@ -8,19 +7,17 @@ namespace WebApi.Hal.Web.Api
{
public class BreweriesController : ApiController
{
- readonly IResourceLinker resourceLinker;
readonly IBeerDbContext beerDbContext;
- public BreweriesController(IResourceLinker resourceLinker, IBeerDbContext beerDbContext)
+ public BreweriesController(IBeerDbContext beerDbContext)
{
- this.resourceLinker = resourceLinker;
this.beerDbContext = beerDbContext;
}
- public BreweryListResource Get()
+ public BreweryListRepresentation Get()
{
var breweries = beerDbContext.Styles
- .Select(s => new BreweryResource
+ .Select(s => new BreweryRepresentation
{
Id = s.Id,
Name = s.Name,
@@ -31,25 +28,25 @@ public BreweryListResource Get()
})
.ToList();
- return resourceLinker.CreateLinks(new BreweryListResource(breweries));
+ return new BreweryListRepresentation(breweries);
}
- public BreweryResource Get(int id)
+ public BreweryRepresentation Get(int id)
{
var brewery = beerDbContext.Breweries.Find(id);
- return resourceLinker.CreateLinks(new BreweryResource
+ return new BreweryRepresentation
{
Id = brewery.Id,
Name = brewery.Name
- });
+ };
}
- public BeerListResource GetBeers(int id)
+ public BeerListRepresentation GetBeers(int id)
{
var beers = beerDbContext.Beers
.Where(b => b.Brewery.Id == id)
- .Select(b=> new BeerResource
+ .Select(b=> new BeerRepresentation
{
Id = b.Id,
Name = b.Name,
@@ -62,7 +59,7 @@ public BeerListResource GetBeers(int id)
}
}).ToList();
- return resourceLinker.CreateLinks(new BeerListResource(beers));
+ return new BeerListRepresentation(beers);
}
}
}
View
20 WebApi.Hal.Web/Api/Linkers/BeerLinker.cs
@@ -1,20 +0,0 @@
-using WebApi.Hal.Interfaces;
-using WebApi.Hal.Web.Api.Resources;
-
-namespace WebApi.Hal.Web.Api.Linkers
-{
- public class BeerLinker : IResourceLinker<BeerResource>
- {
- public void CreateLinks(BeerResource resource, IResourceLinker resourceLinker)
- {
- var selfLink = LinkTemplates.Beers.Beer.CreateLink(id => resource.Id);
- resource.Href = selfLink.Href;
- resource.Rel = selfLink.Rel;
-
- if (resource.StyleId != null)
- resource.Links.Add(LinkTemplates.BeerStyles.Style.CreateLink(id => resource.StyleId));
- if (resource.BreweryId != null)
- resource.Links.Add(LinkTemplates.Breweries.Brewery.CreateLink(id => resource.BreweryId));
- }
- }
-}
View
23 WebApi.Hal.Web/Api/Linkers/BeerListLinker.cs
@@ -1,23 +0,0 @@
-using WebApi.Hal.Interfaces;
-using WebApi.Hal.Web.Api.Resources;
-
-namespace WebApi.Hal.Web.Api.Linkers
-{
- public class BeerListLinker : IResourceLinker<BeerListResource>
- {
- public void CreateLinks(BeerListResource resource, IResourceLinker resourceLinker)
- {
- var selfLink = LinkTemplates.Beers.GetBeers.CreateLink(page => resource.Page);
- resource.Href = resource.Href ?? selfLink.Href;
- resource.Rel = resource.Rel ?? selfLink.Rel;
-
- resource.Links.Add(new Link("page", LinkTemplates.Beers.GetBeers.Href));
- resource.Links.Add(new Link("search", LinkTemplates.Beers.SearchBeers.Href));
-
- foreach (var beer in resource)
- {
- resourceLinker.CreateLinks(beer);
- }
- }
- }
-}
View
15 WebApi.Hal.Web/Api/Linkers/BeerStyleLinker.cs
@@ -1,15 +0,0 @@
-using WebApi.Hal.Interfaces;
-using WebApi.Hal.Web.Api.Resources;
-
-namespace WebApi.Hal.Web.Api.Linkers
-{
- public class BeerStyleLinker : IResourceLinker<BeerStyleResource>
- {
- public void CreateLinks(BeerStyleResource resource, IResourceLinker resourceLinker)
- {
- var selfLink = LinkTemplates.BeerStyles.Style.CreateLink(id => resource.Id);
- resource.Href = selfLink.Href;
- resource.Rel = selfLink.Rel;
- }
- }
-}
View
20 WebApi.Hal.Web/Api/Linkers/BeerStyleListLinker.cs
@@ -1,20 +0,0 @@
-using WebApi.Hal.Interfaces;
-using WebApi.Hal.Web.Api.Resources;
-
-namespace WebApi.Hal.Web.Api.Linkers
-{
- public class BeerStyleListLinker : IResourceLinker<BeerStyleListResource>
- {
- public void CreateLinks(BeerStyleListResource resource, IResourceLinker resourceLinker)
- {
- var beerStyles = LinkTemplates.BeerStyles.GetStyles;
- resource.Href = beerStyles.Href;
- resource.Rel = beerStyles.Rel;
-
- foreach (var style in resource)
- {
- resourceLinker.CreateLinks(style);
- }
- }
- }
-}
View
15 WebApi.Hal.Web/Api/Linkers/BreweryLinker.cs
@@ -1,15 +0,0 @@
-using WebApi.Hal.Interfaces;
-using WebApi.Hal.Web.Api.Resources;
-
-namespace WebApi.Hal.Web.Api.Linkers
-{
- public class BreweryLinker : IResourceLinker<BreweryResource>
- {
- public void CreateLinks(BreweryResource resource, IResourceLinker resourceLinker)
- {
- var selfLink = LinkTemplates.Breweries.Brewery.CreateLink(id => resource.Id);
- resource.Href = selfLink.Href;
- resource.Rel = selfLink.Rel;
- }
- }
-}
View
20 WebApi.Hal.Web/Api/Linkers/BreweryListLinker.cs
@@ -1,20 +0,0 @@
-using WebApi.Hal.Interfaces;
-using WebApi.Hal.Web.Api.Resources;
-
-namespace WebApi.Hal.Web.Api.Linkers
-{
- public class BreweryListLinker : IResourceLinker<BreweryListResource>
- {
- public void CreateLinks(BreweryListResource resource, IResourceLinker resourceLinker)
- {
- var selfLink = LinkTemplates.Breweries.GetBreweries;
- resource.Href = selfLink.Href;
- resource.Rel = selfLink.Rel;
-
- foreach (var brewery in resource)
- {
- resourceLinker.CreateLinks(brewery);
- }
- }
- }
-}
View
23 WebApi.Hal.Web/Api/Resources/BeerListRepresentation.cs
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+
+namespace WebApi.Hal.Web.Api.Resources
+{
+ public class BeerListRepresentation : RepresentationList<BeerRepresentation>
+ {
+ public BeerListRepresentation(IList<BeerRepresentation> beers) : base(beers)
+ { }
+
+ public int Total { get; set; }
+ public int Page { get; set; }
+
+ protected override void CreateHypermedia()
+ {
+ var selfLink = LinkTemplates.Beers.GetBeers.CreateLink(page => Page);
+ Href = Href ?? selfLink.Href;
+ Rel = Rel ?? selfLink.Rel;
+
+ Links.Add(new Link("page", LinkTemplates.Beers.GetBeers.Href));
+ Links.Add(new Link("search", LinkTemplates.Beers.SearchBeers.Href));
+ }
+ }
+}
View
13 WebApi.Hal.Web/Api/Resources/BeerListResource.cs
@@ -1,13 +0,0 @@
-using System.Collections.Generic;
-
-namespace WebApi.Hal.Web.Api.Resources
-{
- public class BeerListResource : ResourceList<BeerResource>
- {
- public BeerListResource(IList<BeerResource> beers) : base(beers)
- { }
-
- public int Total { get; set; }
- public int Page { get; set; }
- }
-}
View
26 WebApi.Hal.Web/Api/Resources/BeerRepresentation.cs
@@ -0,0 +1,26 @@
+namespace WebApi.Hal.Web.Api.Resources
+{
+ public class BeerRepresentation : Representation
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
+
+ public int? BreweryId { get; set; }
+ public string BreweryName { get; set; }
+
+ public int? StyleId { get; set; }
+ public string StyleName { get; set; }
+
+ protected override void CreateHypermedia()
+ {
+ var selfLink = LinkTemplates.Beers.Beer.CreateLink(id => Id);
+ Href = selfLink.Href;
+ Rel = selfLink.Rel;
+
+ if (StyleId != null)
+ Links.Add(LinkTemplates.BeerStyles.Style.CreateLink(id => StyleId));
+ if (BreweryId != null)
+ Links.Add(LinkTemplates.Breweries.Brewery.CreateLink(id => BreweryId));
+ }
+ }
+}
View
14 WebApi.Hal.Web/Api/Resources/BeerResource.cs
@@ -1,14 +0,0 @@
-namespace WebApi.Hal.Web.Api.Resources
-{
- public class BeerResource : Resource
- {
- public int Id { get; set; }
- public string Name { get; set; }
-
- public int? BreweryId { get; set; }
- public string BreweryName { get; set; }
-
- public int? StyleId { get; set; }
- public string StyleName { get; set; }
- }
-}
View
19 WebApi.Hal.Web/Api/Resources/BeerStyleListRepresentation.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+
+namespace WebApi.Hal.Web.Api.Resources
+{
+ public class BeerStyleListRepresentation : RepresentationList<BeerStyleRepresentation>
+ {
+ public BeerStyleListRepresentation(IList<BeerStyleRepresentation> beerStyles) : base(beerStyles)
+ {
+
+ }
+
+ protected override void CreateHypermedia()
+ {
+ var beerStyles = LinkTemplates.BeerStyles.GetStyles;
+ Href = beerStyles.Href;
+ Rel = beerStyles.Rel;
+ }
+ }
+}
View
12 WebApi.Hal.Web/Api/Resources/BeerStyleListResource.cs
@@ -1,12 +0,0 @@
-using System.Collections.Generic;
-
-namespace WebApi.Hal.Web.Api.Resources
-{
- public class BeerStyleListResource : ResourceList<BeerStyleResource>
- {
- public BeerStyleListResource(List<BeerStyleResource> beerStyles) : base(beerStyles)
- {
-
- }
- }
-}
View
15 WebApi.Hal.Web/Api/Resources/BeerStyleRepresentation.cs
@@ -0,0 +1,15 @@
+namespace WebApi.Hal.Web.Api.Resources
+{
+ public class BeerStyleRepresentation : Representation
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
+
+ protected override void CreateHypermedia()
+ {
+ var selfLink = LinkTemplates.BeerStyles.Style.CreateLink(id => Id);
+ Href = selfLink.Href;
+ Rel = selfLink.Rel;
+ }
+ }
+}
View
8 WebApi.Hal.Web/Api/Resources/BeerStyleResource.cs
@@ -1,8 +0,0 @@
-namespace WebApi.Hal.Web.Api.Resources
-{
- public class BeerStyleResource : Resource
- {
- public int Id { get; set; }
- public string Name { get; set; }
- }
-}
View
19 WebApi.Hal.Web/Api/Resources/BreweryListRepresentation.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+
+namespace WebApi.Hal.Web.Api.Resources
+{
+ public class BreweryListRepresentation : RepresentationList<BreweryRepresentation>
+ {
+ public BreweryListRepresentation(IList<BreweryRepresentation> breweries)
+ : base(breweries)
+ {
+ }
+
+ protected override void CreateHypermedia()
+ {
+ var selfLink = LinkTemplates.Breweries.GetBreweries;
+ Href = selfLink.Href;
+ Rel = selfLink.Rel;
+ }
+ }
+}
View
12 WebApi.Hal.Web/Api/Resources/BreweryListResource.cs
@@ -1,12 +0,0 @@
-using System.Collections.Generic;
-
-namespace WebApi.Hal.Web.Api.Resources
-{
- public class BreweryListResource : ResourceList<BreweryResource>
- {
- public BreweryListResource(List<BreweryResource> breweries)
- : base(breweries)
- {
- }
- }
-}
View
16 WebApi.Hal.Web/Api/Resources/BreweryRepresentation.cs
@@ -0,0 +1,16 @@
+namespace WebApi.Hal.Web.Api.Resources
+{
+ public class BreweryRepresentation : Representation
+ {
+ public int Id { get; set; }
+
+ public string Name { get; set; }
+
+ protected override void CreateHypermedia()
+ {
+ var selfLink = LinkTemplates.Breweries.Brewery.CreateLink(id => Id);
+ Href = selfLink.Href;
+ Rel = selfLink.Rel;
+ }
+ }
+}
View
9 WebApi.Hal.Web/Api/Resources/BreweryResource.cs
@@ -1,9 +0,0 @@
-namespace WebApi.Hal.Web.Api.Resources
-{
- public class BreweryResource : Resource
- {
- public int Id { get; set; }
-
- public string Name { get; set; }
- }
-}
View
25 WebApi.Hal.Web/Api/StylesController.cs
@@ -3,7 +3,6 @@
using System.Net;
using System.Net.Http;
using System.Web.Http;
-using WebApi.Hal.Interfaces;
using WebApi.Hal.Web.Api.Resources;
using WebApi.Hal.Web.Data;
using WebApi.Hal.Web.Data.Queries;
@@ -13,21 +12,19 @@ namespace WebApi.Hal.Web.Api
public class StylesController : ApiController
{
readonly IBeerDbContext beerDbContext;
- readonly IResourceLinker resourceLinker;
readonly IRepository repository;
- public StylesController(IResourceLinker resourceLinker, IBeerDbContext beerDbContext, IRepository repository)
+ public StylesController(IBeerDbContext beerDbContext, IRepository repository)
{
- this.resourceLinker = resourceLinker;
this.beerDbContext = beerDbContext;
this.repository = repository;
}
- public BeerStyleListResource Get()
+ public BeerStyleListRepresentation Get()
{
- List<BeerStyleResource> beerStyles = beerDbContext.Styles
+ var beerStyles = beerDbContext.Styles
.ToList()
- .Select(s => new BeerStyleResource
+ .Select(s => new BeerStyleRepresentation
{
Id = s.Id,
Name = s.Name,
@@ -38,7 +35,7 @@ public BeerStyleListResource Get()
})
.ToList();
- return resourceLinker.CreateLinks(new BeerStyleListResource(beerStyles));
+ return new BeerStyleListRepresentation(beerStyles);
}
public HttpResponseMessage Get(int id)
@@ -47,7 +44,7 @@ public HttpResponseMessage Get(int id)
if (beerStyle == null)
return Request.CreateResponse(HttpStatusCode.NotFound);
- var beerStyleResource = new BeerStyleResource
+ var beerStyleResource = new BeerStyleRepresentation
{
Id = beerStyle.Id,
Name = beerStyle.Name,
@@ -57,26 +54,26 @@ public HttpResponseMessage Get(int id)
}
};
- return Request.CreateResponse(HttpStatusCode.OK, resourceLinker.CreateLinks(beerStyleResource));
+ return Request.CreateResponse(HttpStatusCode.OK, beerStyleResource);
}
[HttpGet]
- public BeerListResource AssociatedBeers(int id)
+ public BeerListRepresentation AssociatedBeers(int id)
{
return AssociatedBeers(id, 1);
}
[HttpGet]
- public BeerListResource AssociatedBeers(int id, int page)
+ public BeerListRepresentation AssociatedBeers(int id, int page)
{
var beers = repository.Find(new GetBeersQuery(b => b.Style.Id == id), page, BeersController.PageSize);
- var resourceList = new BeerListResource(beers.ToList())
+ var resourceList = new BeerListRepresentation(beers.ToList())
{
Total = beers.TotalResults
};
- return resourceLinker.CreateLinks(resourceList);
+ return resourceList;
}
}
}
View
8 WebApi.Hal.Web/Data/Queries/GetBeersQuery.cs
@@ -9,7 +9,7 @@ namespace WebApi.Hal.Web.Data.Queries
/// <summary>
/// Gets a list of beers, with no hypermedia on the resource
/// </summary>
- public class GetBeersQuery : IPagedQuery<BeerResource>
+ public class GetBeersQuery : IPagedQuery<BeerRepresentation>
{
readonly Expression<Func<Beer, bool>> where;
@@ -18,7 +18,7 @@ public GetBeersQuery(Expression<Func<Beer, bool>> where = null)
this.where = where ?? (b=>true);
}
- public PagedResult<BeerResource> Execute(IBeerDbContext dbContext, int skip, int take)
+ public PagedResult<BeerRepresentation> Execute(IBeerDbContext dbContext, int skip, int take)
{
var beers = dbContext
.Beers
@@ -26,7 +26,7 @@ public PagedResult<BeerResource> Execute(IBeerDbContext dbContext, int skip, int
.OrderBy(b => b.Name)
.Skip(skip)
.Take(take)
- .Select(b => new BeerResource
+ .Select(b => new BeerRepresentation
{
Id = b.Id,
Name = b.Name,
@@ -41,7 +41,7 @@ public PagedResult<BeerResource> Execute(IBeerDbContext dbContext, int skip, int
.Where(where)
.Count();
- return new PagedResult<BeerResource>(beers, count, skip, take);
+ return new PagedResult<BeerRepresentation>(beers, count, skip, take);
}
}
}
View
12 WebApi.Hal.Web/Global.asax.cs
@@ -8,7 +8,6 @@
using Autofac;
using Autofac.Integration.Mvc;
using Autofac.Integration.WebApi;
-using WebApi.Hal.Interfaces;
using WebApi.Hal.Web.App_Start;
using WebApi.Hal.Web.Data;
@@ -36,10 +35,8 @@ protected void Application_Start()
GlobalConfiguration.Configuration.Formatters.Add(new XmlHalMediaTypeFormatter());
var containerBuilder = new ContainerBuilder();
- var resourceLinker = new ResourceLinker();
- resourceLinker.AddLinkersFromAssembly(typeof(WebApiApplication).Assembly);
- ConfigureContainer(containerBuilder, resourceLinker);
+ ConfigureContainer(containerBuilder);
Database.SetInitializer(new DbUpDatabaseInitializer(connectionString));
@@ -47,17 +44,12 @@ protected void Application_Start()
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
- private void ConfigureContainer(ContainerBuilder containerBuilder, ResourceLinker resourceLinker)
+ private void ConfigureContainer(ContainerBuilder containerBuilder)
{
// Register API controllers using assembly scanning.
containerBuilder.RegisterApiControllers(Assembly.GetExecutingAssembly());
containerBuilder
- .RegisterInstance(resourceLinker)
- .As<IResourceLinker>()
- .SingleInstance();
-
- containerBuilder
.Register(c=> new BeerDbContext(connectionString))
.As<IBeerDbContext>()
.InstancePerHttpRequest();
View
18 WebApi.Hal.Web/WebApi.Hal.Web.csproj
@@ -141,22 +141,16 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Api\BreweriesController.cs" />
- <Compile Include="Api\Linkers\BreweryLinker.cs" />
- <Compile Include="Api\Linkers\BreweryListLinker.cs" />
- <Compile Include="Api\Resources\BeerStyleListResource.cs" />
- <Compile Include="Api\Resources\BeerStyleResource.cs" />
- <Compile Include="Api\Resources\BreweryListResource.cs" />
- <Compile Include="Api\Resources\BreweryResource.cs" />
+ <Compile Include="Api\Resources\BeerStyleListRepresentation.cs" />
+ <Compile Include="Api\Resources\BeerStyleRepresentation.cs" />
+ <Compile Include="Api\Resources\BreweryListRepresentation.cs" />
+ <Compile Include="Api\Resources\BreweryRepresentation.cs" />
<Compile Include="Api\StylesController.cs" />
<Compile Include="App_Start\BundleConfig.cs" />
<Compile Include="App_Start\FilterConfig.cs" />
<Compile Include="App_Start\RouteConfig.cs" />
- <Compile Include="Api\Resources\BeerListResource.cs" />
- <Compile Include="Api\Resources\BeerResource.cs" />
- <Compile Include="Api\Linkers\BeerLinker.cs" />
- <Compile Include="Api\Linkers\BeerListLinker.cs" />
- <Compile Include="Api\Linkers\BeerStyleLinker.cs" />
- <Compile Include="Api\Linkers\BeerStyleListLinker.cs" />
+ <Compile Include="Api\Resources\BeerListRepresentation.cs" />
+ <Compile Include="Api\Resources\BeerRepresentation.cs" />
<Compile Include="BeerRepository.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Api\BeersController.cs" />
View
19 WebApi.Hal.Web/WebApi.Hal.Web.ncrunchproject
@@ -0,0 +1,19 @@
+<ProjectConfiguration>
+ <CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
+ <ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
+ <PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
+ <AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
+ <AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
+ <IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
+ <RunPreBuildEvents>false</RunPreBuildEvents>
+ <RunPostBuildEvents>false</RunPostBuildEvents>
+ <PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
+ <InstrumentAssembly>true</InstrumentAssembly>
+ <PreventSigningOfAssembly>false</PreventSigningOfAssembly>
+ <AnalyseExecutionTimes>true</AnalyseExecutionTimes>
+ <IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
+ <DefaultTestTimeout>60000</DefaultTestTimeout>
+ <UseBuildConfiguration />
+ <ProxyProcessPath />
+ <UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
+</ProjectConfiguration>
View
4 WebApi.Hal.ncrunchsolution
@@ -1,6 +1,6 @@
<SolutionConfiguration>
- <FileVersion>0</FileVersion>
- <AutoEnableOnStartup>Default</AutoEnableOnStartup>
+ <FileVersion>1</FileVersion>
+ <AutoEnableOnStartup>True</AutoEnableOnStartup>
<AllowParallelTestExecution>false</AllowParallelTestExecution>
<FrameworkUtilisationTypeForNUnit>UseDynamicAnalysis</FrameworkUtilisationTypeForNUnit>
<FrameworkUtilisationTypeForGallio>UseStaticAnalysis</FrameworkUtilisationTypeForGallio>
View
88 WebApi.Hal/HypermediaList.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace WebApi.Hal
+{
+ public class HypermediaList : IList<Link>
+ {
+ readonly Action onEnumerate;
+ readonly List<Link> innerList;
+
+ public HypermediaList(Action onEnumerate)
+ {
+ this.onEnumerate = onEnumerate;
+ innerList = new List<Link>();
+ }
+
+ public IEnumerator<Link> GetEnumerator()
+ {
+ onEnumerate();
+
+ return innerList.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public void Add(Link link)
+ {
+ var singleOrDefault = innerList.SingleOrDefault(l => l.Rel == link.Rel);
+ if (singleOrDefault != null)
+ innerList[innerList.IndexOf(singleOrDefault)] = link;
+ else
+ innerList.Add(link);
+ }
+
+ public void Clear()
+ {
+ innerList.Clear();
+ }
+
+ public bool Contains(Link link)
+ {
+ return innerList.Contains(link);
+ }
+
+ public void CopyTo(Link[] array, int arrayIndex)
+ {
+ innerList.CopyTo(array, arrayIndex);
+ }
+
+ public bool Remove(Link link)
+ {
+ return innerList.Remove(link);
+ }
+
+ public int Count
+ {
+ get { return innerList.Count; }
+ }
+
+ public bool IsReadOnly { get { return false; } }
+
+ public int IndexOf(Link link)
+ {
+ return innerList.IndexOf(link);
+ }
+
+ public void Insert(int index, Link item)
+ {
+ innerList.Insert(index, item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ innerList.RemoveAt(index);
+ }
+
+ public Link this[int index]
+ {
+ get { return innerList[index]; }
+ set { innerList[index] = value; }
+ }
+ }
+}
View
8 WebApi.Hal/Interfaces/IRepresentationList.cs
@@ -0,0 +1,8 @@
+using System.Collections;
+
+namespace WebApi.Hal.Interfaces
+{
+ public interface IRepresentationList : IResource, IEnumerable
+ {
+ }
+}
View
2  WebApi.Hal/Interfaces/IResource.cs
@@ -15,6 +15,6 @@ public interface IResource
string LinkName { get; set; }
[JsonProperty("_links")]
- List<Link> Links { get; set; }
+ IList<Link> Links { get; set; }
}
}
View
7 WebApi.Hal/Interfaces/IResourceLinker.cs
@@ -1,7 +0,0 @@
-namespace WebApi.Hal.Interfaces
-{
- public interface IResourceLinker
- {
- T CreateLinks<T>(T resource);
- }
-}
View
7 WebApi.Hal/Interfaces/IResourceLinker`1.cs
@@ -1,7 +0,0 @@
-namespace WebApi.Hal.Interfaces
-{
- public interface IResourceLinker<in T>
- {
- void CreateLinks(T resource, IResourceLinker resourceLinker);
- }
-}
View
8 WebApi.Hal/Interfaces/IResourceList.cs
@@ -1,8 +0,0 @@
-using System.Collections;
-
-namespace WebApi.Hal.Interfaces
-{
- public interface IResourceList : IResource, IEnumerable
- {
- }
-}
View
4 WebApi.Hal/JsonConverters/LinksConverter.cs
@@ -8,7 +8,7 @@ public class LinksConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
- var links = (List<Link>)value;
+ var links = (IList<Link>)value;
writer.WriteStartObject();
foreach (var link in links)
@@ -36,7 +36,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
public override bool CanConvert(Type objectType)
{
- return typeof(List<Link>) == objectType;
+ return typeof(IList<Link>).IsAssignableFrom(objectType);
}
}
}
View
8 WebApi.Hal/JsonConverters/ResourceConverter.cs
@@ -8,9 +8,9 @@ public class ResourceConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
- var resource = (Resource)value;
+ var resource = (Representation)value;
- resource.Links.Add(new Link
+ resource.Links.Insert(0, new Link
{
Rel = "self",
Href = resource.Href
@@ -34,12 +34,12 @@ public override bool CanConvert(Type objectType)
static bool IsResourceList(Type objectType)
{
- return typeof(IResourceList).IsAssignableFrom(objectType);
+ return typeof(IRepresentationList).IsAssignableFrom(objectType);
}
static bool IsResource(Type objectType)
{
- return typeof(Resource).IsAssignableFrom(objectType);
+ return typeof(Representation).IsAssignableFrom(objectType);
}
}
}
View
10 WebApi.Hal/JsonConverters/ResourceListConverter.cs
@@ -9,7 +9,7 @@ public class ResourceListConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
- var list = (IResourceList)value;
+ var list = (IRepresentationList)value;
list.Links.Add(new Link
{
@@ -25,7 +25,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
writer.WriteStartObject();
writer.WritePropertyName(list.Rel);
writer.WriteStartArray();
- foreach (Resource halResource in list)
+ foreach (Representation halResource in list)
{
serializer.Serialize(writer, halResource);
}
@@ -34,7 +34,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
writer.WriteEndObject();
var listType = list.GetType();
- var propertyInfos = typeof(ResourceList<>).GetProperties().Select(p => p.Name);
+ var propertyInfos = typeof(RepresentationList<>).GetProperties().Select(p => p.Name);
foreach (var property in listType.GetProperties().Where(p => !propertyInfos.Contains(p.Name)))
{
writer.WritePropertyName(property.Name.ToLower());
@@ -56,12 +56,12 @@ public override bool CanConvert(Type objectType)
static bool IsResourceList(Type objectType)
{
- return typeof(IResourceList).IsAssignableFrom(objectType);
+ return typeof(IRepresentationList).IsAssignableFrom(objectType);
}
static bool IsResource(Type objectType)
{
- return typeof(Resource).IsAssignableFrom(objectType);
+ return typeof(Representation).IsAssignableFrom(objectType);
}
}
}
View
4 WebApi.Hal/JsonHalMediaTypeFormatter.cs
@@ -21,12 +21,12 @@ public JsonHalMediaTypeFormatter()
public override bool CanReadType(Type type)
{
- return typeof(Resource).IsAssignableFrom(type);
+ return typeof(Representation).IsAssignableFrom(type);
}
public override bool CanWriteType(Type type)
{
- return typeof(Resource).IsAssignableFrom(type);
+ return typeof(Representation).IsAssignableFrom(type);
}
}
}
View
3  WebApi.Hal/Link.cs
@@ -13,7 +13,8 @@ public Link(string rel, string href)
{
Rel = rel;
Href = href;
- IsTemplated = Regex.Match(href, @"{\w+}", RegexOptions.Compiled).Success;
+ if (href != null)
+ IsTemplated = Regex.Match(href, @"{\w+}", RegexOptions.Compiled).Success;
}
public string Rel { get; set; }
View
9 WebApi.Hal/ReflectionExtensions.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
+using WebApi.Hal.Interfaces;
namespace WebApi.Hal
{
@@ -21,18 +22,12 @@ public static bool IsGenericListOfApiResource(this Type type)
if (type.IsGenericType && typeof(IList).IsAssignableFrom(type))
{
var genericType = type.GetGenericArguments().Single();
- return typeof(Resource).IsAssignableFrom(genericType);
+ return typeof(Representation).IsAssignableFrom(genericType);
}
return false;
}
- public static bool IsGenericResourceList(this Type type)
- {
- var args = type.GetGenericArguments();
- return args.Length == 1 && typeof(Resource).IsAssignableFrom(type) && typeof(ResourceList<>).MakeGenericType(args).IsAssignableFrom(type);
- }
-
public static PropertyInfo[] GetPublicInstanceProperties(this Type type)
{
return type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.SetField);
View
103 WebApi.Hal/Representation.cs
@@ -0,0 +1,103 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using WebApi.Hal.Interfaces;
+
+namespace WebApi.Hal
+{
+ public abstract class Representation : IResource
+ {
+ string href;
+ bool creatingHyperMedia;
+ string rel;
+ string linkName;
+ bool selfLinkUpToDate;
+
+ protected Representation()
+ {
+ Links = new HypermediaList(CreateHypermedia);
+ }
+
+ [JsonIgnore]
+ public string Rel
+ {
+ get
+ {
+ // Prevent CreateHypermedia from being reentrant to this method
+ if (creatingHyperMedia || selfLinkUpToDate)
+ return href;
+ creatingHyperMedia = true;
+ try
+ {
+ CreateHypermedia();
+ }
+ finally
+ {
+ creatingHyperMedia = false;
+ }
+ return rel;
+ }
+ set
+ {
+ rel = value;
+ selfLinkUpToDate = false;
+ }
+ }
+
+ [JsonIgnore]
+ public string Href
+ {
+ get
+ {
+ // Prevent CreateHypermedia from being reentrant to this method
+ if (creatingHyperMedia || selfLinkUpToDate)
+ return href;
+ creatingHyperMedia = true;
+ try
+ {
+ CreateHypermedia();
+ }
+ finally
+ {
+ creatingHyperMedia = false;
+ }
+ return href;
+ }
+ set
+ {
+ href = value;
+ selfLinkUpToDate = false;
+ }
+ }
+
+ [JsonIgnore]
+ public string LinkName
+ {
+ get
+ {
+ // Prevent CreateHypermedia from being reentrant to this method
+ if (creatingHyperMedia || selfLinkUpToDate)
+ return href;
+ creatingHyperMedia = true;
+ try
+ {
+ CreateHypermedia();
+ }
+ finally
+ {
+ creatingHyperMedia = false;
+ }
+ return linkName;
+ }
+ set
+ {
+ linkName = value;
+ selfLinkUpToDate = false;
+ }
+ }
+
+ [JsonProperty("_links")]
+ public IList<Link> Links { get; set; }
+
+ protected internal abstract void CreateHypermedia();
+ }
+}
View
9 WebApi.Hal/ResourceList.cs → WebApi.Hal/RepresentationList.cs
@@ -6,16 +6,11 @@
namespace WebApi.Hal
{
- public class ResourceList<T> : Resource, IResourceList, IEnumerable<T> where T : Resource
+ public abstract class RepresentationList<T> : Representation, IRepresentationList, IEnumerable<T> where T : Representation
{
private readonly IList<T> resources;
- public ResourceList()
- {
- resources = new List<T>();
- }
-
- public ResourceList(IList<T> res)
+ protected RepresentationList(IList<T> res)
{
resources = res ?? new List<T>();
}
View
26 WebApi.Hal/Resource.cs
@@ -1,26 +0,0 @@
-using System.Collections.Generic;
-using Newtonsoft.Json;
-using WebApi.Hal.Interfaces;
-
-namespace WebApi.Hal
-{
- public abstract class Resource : IResource
- {
- protected Resource()
- {
- Links = new List<Link>();
- }
-
- [JsonIgnore]
- public string Rel { get; set; }
-
- [JsonIgnore]
- public string Href { get; set; }
-
- [JsonIgnore]
- public string LinkName { get; set; }
-
- [JsonProperty("_links")]
- public List<Link> Links { get; set; }
- }
-}
View
56 WebApi.Hal/ResourceLinker.cs
@@ -1,56 +0,0 @@
-using System;
-using System.CodeDom;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using Microsoft.CSharp;
-using WebApi.Hal.Interfaces;
-
-namespace WebApi.Hal
-{
- public class ResourceLinker : IResourceLinker
- {
- readonly Dictionary<Type, object> resourceLinkers = new Dictionary<Type, object>();
-
- public void AddLinker<T>(IResourceLinker<T> resourceLinker)
- {
- var type = typeof(T);
- if (!resourceLinkers.ContainsKey(type))
- resourceLinkers.Add(type, resourceLinker);
- }
-
- public T CreateLinks<T>(T resource)
- {
- var type = typeof(T);
- if (!resourceLinkers.ContainsKey(type))
- throw new ArgumentException(CreateExceptionMessage(type));
-
- var linker = (IResourceLinker<T>)resourceLinkers[type];
-
- linker.CreateLinks(resource, this);
- return resource;
- }
-
- static string CreateExceptionMessage(Type type)
- {
- return string.Format("No resource linker found for {0}", new CSharpCodeProvider().GetTypeOutput(new CodeTypeReference(type)));
- }
-
- public void AddLinkersFromAssembly(Assembly assembly)
- {
- var linkerTypes = assembly.GetTypes()
- .SelectMany(types => types.GetInterfaces()
- .Where(interfaces => interfaces.IsGenericType && interfaces.GetGenericTypeDefinition() == typeof(IResourceLinker<>))
- .Select(interfaces => new { Type = types, Interface = interfaces}))
- .Where(a=>a.Interface != null);
-
- foreach (var linkerType in linkerTypes)
- {
- var resourceType = linkerType.Interface.GetGenericArguments()[0];
-
- var instance = Activator.CreateInstance(linkerType.Type);
- resourceLinkers.Add(resourceType, instance);
- }
- }
- }
-}
View
10 WebApi.Hal/WebApi.Hal.csproj
@@ -47,12 +47,11 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="Interfaces\IRepresentationList.cs" />
<Compile Include="Interfaces\IResource.cs" />
- <Compile Include="Interfaces\IResourceList.cs" />
- <Compile Include="Resource.cs" />
+ <Compile Include="HypermediaList.cs" />
+ <Compile Include="Representation.cs" />
<Compile Include="HttpRequestExtensions.cs" />
- <Compile Include="Interfaces\IResourceLinker.cs" />
- <Compile Include="Interfaces\IResourceLinker`1.cs" />
<Compile Include="JsonConverters\LinksConverter.cs" />
<Compile Include="JsonConverters\ResourceConverter.cs" />
<Compile Include="JsonConverters\ResourceListConverter.cs" />
@@ -60,8 +59,7 @@
<Compile Include="Link.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReflectionExtensions.cs" />
- <Compile Include="ResourceLinker.cs" />
- <Compile Include="ResourceList.cs" />
+ <Compile Include="RepresentationList.cs" />
<Compile Include="XmlHalMediaTypeFormatter.cs" />
</ItemGroup>
<ItemGroup>
View
19 WebApi.Hal/WebApi.Hal.ncrunchproject
@@ -0,0 +1,19 @@
+<ProjectConfiguration>
+ <CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
+ <ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
+ <PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
+ <AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
+ <AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
+ <IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
+ <RunPreBuildEvents>false</RunPreBuildEvents>
+ <RunPostBuildEvents>false</RunPostBuildEvents>
+ <PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
+ <InstrumentAssembly>true</InstrumentAssembly>
+ <PreventSigningOfAssembly>false</PreventSigningOfAssembly>
+ <AnalyseExecutionTimes>true</AnalyseExecutionTimes>
+ <IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
+ <DefaultTestTimeout>60000</DefaultTestTimeout>
+ <UseBuildConfiguration />
+ <ProxyProcessPath />
+ <UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
+</ProjectConfiguration>
View
83 WebApi.Hal/XmlHalMediaTypeFormatter.cs
@@ -8,6 +8,7 @@
using System.Reflection;
using System.Xml;
using System.Xml.Linq;
+using WebApi.Hal.Interfaces;
namespace WebApi.Hal
{
@@ -20,7 +21,7 @@ public XmlHalMediaTypeFormatter()
public override object ReadFromStream(Type type, Stream stream, HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
{
- if (!typeof(Resource).IsAssignableFrom(type))
+ if (!typeof(Representation).IsAssignableFrom(type))
{
return null;
}
@@ -31,7 +32,7 @@ public override object ReadFromStream(Type type, Stream stream, HttpContentHeade
public override void WriteToStream(Type type, object value, Stream stream, HttpContentHeaders contentHeaders)
{
- var resource = value as Resource;
+ var resource = value as Representation;
if (resource == null)
{
return;
@@ -52,7 +53,7 @@ public override void WriteToStream(Type type, object value, Stream stream, HttpC
/// <returns>returns deserialized object</returns>
static object ReadHalResource(Type type, XElement xml)
{
- Resource resource;
+ Representation representation;
if (xml == null)
{
@@ -60,7 +61,7 @@ static object ReadHalResource(Type type, XElement xml)
}
// First, determine if Resource of type Generic List and construct Instance with respective Parameters
- if (type.IsGenericResourceList())
+ if (typeof(IRepresentationList).IsAssignableFrom(type))
{
var resourceListXml = xml.Elements("resource"); // .Where(x => x.Attribute("rel").Value == "item");
var genericTypeArg = type.GetGenericArguments().Single();
@@ -71,82 +72,86 @@ static object ReadHalResource(Type type, XElement xml)
resourceList.Add(resourceListItem);
}
- resource = Activator.CreateInstance(type, new object[] { resourceList }) as Resource;
+ representation = Activator.CreateInstance(type, new object[] { resourceList }) as Representation;
}
else
{
- resource = Activator.CreateInstance(type) as Resource;
+ representation = Activator.CreateInstance(type) as Representation;
}
// Second, set the well-known HAL properties ONLY if type of Resource
- CreateSelfHypermedia(type, xml, resource);
+ CreateSelfHypermedia(type, xml, representation);
// Third, read/set the rest of the properties
- SetProperties(type, xml, resource);
+ SetProperties(type, xml, representation);
// Fourth, read each link element
var links = xml.Elements("link");
- var linksList = links.Select(link => new Link { Rel = link.Attribute("rel").Value, Href = link.Attribute("href").Value }).ToList();
+ var linksList = links.Select(link => new Link
+ {
+ Rel = link.Attribute("rel").Value,
+ Href = link.Attribute("href").Value
+ }).ToList();
- type.GetProperty("Links").SetValue(resource, linksList, null);
+ type.GetProperty("Links").SetValue(representation, linksList, null);
- return resource;
+ return representation;
}
- static void SetProperties(Type type, XElement xml, Resource resource)
+ static void SetProperties(Type type, XElement xml, Representation representation)
{
foreach (var property in type.GetPublicInstanceProperties())
{
if (property.IsValidBasicType())
{
- type.SetPropertyValue(property.Name, xml.Element(property.Name), resource);
+ type.SetPropertyValue(property.Name, xml.Element(property.Name), representation);
}
- else if (typeof(Resource).IsAssignableFrom(property.PropertyType) &&
+ else if (typeof(Representation).IsAssignableFrom(property.PropertyType) &&
property.GetIndexParameters().Length == 0)
{
var resourceXml =
xml.Elements("resource").SingleOrDefault(x => x.Attribute("name").Value == property.Name);
var halResource = ReadHalResource(property.PropertyType, resourceXml);
- property.SetValue(resource, halResource, null);
+ property.SetValue(representation, halResource, null);
}
}
}
- static void CreateSelfHypermedia(Type type, XElement xml, Resource resource)
+ static void CreateSelfHypermedia(Type type, XElement xml, Representation representation)
{
- type.GetProperty("Rel").SetValue(resource, xml.Attribute("rel").Value, null);
- type.SetPropertyValue("Href", xml.Attribute("href"), resource);
- type.SetPropertyValue("LinkName", xml.Attribute("name"), resource);
+ type.GetProperty("Rel").SetValue(representation, xml.Attribute("rel").Value, null);
+ type.SetPropertyValue("Href", xml.Attribute("href"), representation);
+ type.SetPropertyValue("LinkName", xml.Attribute("name"), representation);
}
- static void WriteHalResource(Resource resource, XmlWriter writer, string propertyName = null)
+ static void WriteHalResource(Representation representation, XmlWriter writer, string propertyName = null)
{
- if (resource == null)
+ if (representation == null)
{
return;
}
// First write the well-known HAL properties
writer.WriteStartElement("resource");
- writer.WriteAttributeString("rel", resource.Rel);
- writer.WriteAttributeString("href", resource.Href);
- if (resource.LinkName != null || propertyName != null)
+ writer.WriteAttributeString("rel", representation.Rel);
+ writer.WriteAttributeString("href", representation.Href);
+ if (representation.LinkName != null || propertyName != null)
{
- writer.WriteAttributeString("name", resource.LinkName = resource.LinkName ?? propertyName);
+ writer.WriteAttributeString("name", representation.LinkName = representation.LinkName ?? propertyName);
}
// Second, determine if resource is of Generic Resource List Type , list out all the items
- if (resource.GetType().IsGenericResourceList())
+ var representationList = representation as IRepresentationList;
+ if (representationList != null)
{
- var propertyValue = resource as IEnumerable;
- foreach (Resource item in propertyValue)
+ foreach (var item in representationList.Cast<Representation>())
{
WriteHalResource(item, writer);
}
}
//Third write out the links of the resource
- foreach (var link in resource.Links)
+ foreach (var link in representation.Links)
{
writer.WriteStartElement("link");
writer.WriteAttributeString("rel", link.Rel);
@@ -155,31 +160,31 @@ static void WriteHalResource(Resource resource, XmlWriter writer, string propert
}
// Fourth, write the rest of the properties
- WriteResourceProperties(resource, writer);
+ WriteResourceProperties(representation, writer);
writer.WriteEndElement();
}
- static void WriteResourceProperties(Resource resource, XmlWriter writer)
+ static void WriteResourceProperties(Representation representation, XmlWriter writer)
{
// Only simple type and nested ApiResource type will be handled : for any other type, exception will be thrown
// including List<ApiResource> as representation of List would require properties rel, href and linkname
- // To overcome the issue, use "ResourceList<T>"
- foreach (var property in resource.GetType().GetPublicInstanceProperties())
+ // To overcome the issue, use "RepresentationList<T>"
+ foreach (var property in representation.GetType().GetPublicInstanceProperties())
{
if (property.IsValidBasicType())
{
- var propertyString = GetPropertyString(property, resource);
+ var propertyString = GetPropertyString(property, representation);
if (propertyString != null)
{
writer.WriteElementString(property.Name, propertyString);
}
}
- else if (typeof (Resource).IsAssignableFrom(property.PropertyType) &&
+ else if (typeof (Representation).IsAssignableFrom(property.PropertyType) &&
property.GetIndexParameters().Length == 0)
{
- var halResource = property.GetValue(resource, null);
- WriteHalResource((Resource) halResource, writer, property.Name);
+ var halResource = property.GetValue(representation, null);
+ WriteHalResource((Representation) halResource, writer, property.Name);
}
}
}
@@ -197,12 +202,12 @@ static string GetPropertyString(PropertyInfo property, object instance)
public override bool CanReadType(Type type)
{
- return typeof(Resource).IsAssignableFrom(type);
+ return typeof(Representation).IsAssignableFrom(type);
}
public override bool CanWriteType(Type type)
{
- return typeof(Resource).IsAssignableFrom(type);
+ return typeof(Representation).IsAssignableFrom(type);
}
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.