Consider the following two WCF 4.0 REST services:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class WorkspaceService
{
[WebInvoke(UriTemplate = "{id}/documents/{name}", Method = "POST")]
public Document CreateWorkspaceDocument(Stream stream, string id, string name)
{
/* CreateDocument is omitted as it isn't relevant to the question */
Document response = CreateDocument(id, name, stream);
/* set the location header */
SetLocationHeader(response.Id);
}
private void SetLocationHeader(string id)
{
Uri uri = new Uri("https://example.com/documents/" + id);
WebOperationContext.Current.OutgoingResponse.SetStatusAsCreated(uri);
}
/* methods to delete, update etc */
}
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class DocumentService
{
[WebGet(UriTemplate = "{id}")]
public Document GetDocument(string id)
{
}
/* methods to delete, update etc */
}
In essence, when someone creates a document in a workspace, the Location header is set to the location of the document, which is essentially is the same as invoking the DocumentService.GetDocument
operation.
My global.asax looks as follows:
public class Global : HttpApplication
{
private void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
private void RegisterRoutes()
{
var webServiceHostFactory = new WebServiceHostFactory();
RouteTable.Routes.Add(new ServiceRoute("workspaces", webServiceHostFactory, typeof (WorkspaceService)));
RouteTable.Routes.Add(new ServiceRoute("documents", webServiceHostFactory, typeof (DocumentService)));
/* other services */
}
}
The implementation of WorkspaceService.SetLocationHeader
as it makes some assumptions about how routing was setup. If I was to change the route of DocumentService
then the resulting Uri will be incorrect. If I changed the UriTemplate of DocumentService.GetDocument
, then the resulting Uri will be incorrect too.
If WorkspaceService and DocumentService was merged into one service, I could have written SetLocationHeader
as follows:
var itemTemplate = WebOperationContext.Current.GetUriTemplate("GetDocument");
var uri = itemTemplate.BindByPosition(WebOperationContext.Current.IncomingRequest.UriTemplateMatch.BaseUri, id);
WebOperationContext.Current.OutgoingResponse.SetStatusAsCreated(uri);
How would one write WorkspaceService.SetLocationHeader
such that it will use the routing table defined in Global.asax and UriTemplates to return the Uri for the GetDocument operation of the DocumentService?
I'm using plain old WCF 4.0 (not the WCF Web API).