As I do this now, I pass a dto response that implements the interface
public interface IHaveLinks { [IgnoreDataMember] IEnumerable<Link> Links { get; } } public class Link { public string Name { get; set; } public IReturn Request { get; set; } public string Method { get; set; } }
Then I use the response filter to generate the URLs and fill the response headers with links.
this.ResponseFilters.Add((req, res, dto) => { if (!(dto is IHaveLinks)) return; var links = (dto as IHaveLinks).Links if(links == null || !links.Any()) return; var linksText = links .Select(x => string.Format("<{0}>; rel={1}"), x.Request.ToUrl(x.Method), x.Name)); var linkHeader = string.Join(", ", linksText); res.AddHeader("Link", linkHeader); });
It seems the cleanest way. The Link object above effectively says: "If you make this request using this method, you will return the named resource." The only HTTP thing that expires before the BLL is Method . But you can get rid of this and just go back to the GET URL. Or compare it with some generalized "operation"?
As an example:
public class ExampleService : Service { public ExamplesResponse Get(ExamplesRequest request) { var page = request.Page; var data = // get data; return new ExamplesResponse { Examples = data, Links = new [] { new Link { Name = "next", Request = request.AddPage(1), Method = "GET" }, new Link { Name = "previous", Request = request.AddPage(-1), Method = "GET" }, } } } } [Route("/examples/{Page}")] public class ExamplesRequest : IReturn<ExamplesResponse> { public int Page { get; set; } // ... }
(The AddPage method returns a clone of the request and sets the page property accordingly.)
Hope this helps.
tgmdbm
source share