Is there a more elegant way to build URIs in ServiceStack?

servicestack

Solution

Reverse Routing

If you're trying to build urls for ServiceStack services you can use the `RequestDto.ToGetUrl()` and `RequestDto.ToAbsoluteUri()` to build relative and absolute urls as seen in this earlier question on Reverse Routing. e.g:

[Route("/reqstars/search", "GET")]
[Route("/reqstars/aged/{Age}")]
public class SearchReqstars : IReturn<ReqstarsResponse>
{
    public int? Age { get; set; }
}

var relativeUrl = new SearchReqstars { Age = 20 }.ToUrl("GET");
var absoluteUrl = HostContext.Config.WebHostUrl.CombineWith(relativeUrl);

relativeUrl.Print(); //=  /reqstars/aged/20
absoluteUrl.Print(); //=  http://www.myhost.com/reqstars/aged/20

For creating Urls for other 3rd Party APIs look at the Http Utils wiki for example extension methods that can help, e.g:

var url ="http://api.twitter.com/user_timeline.json?screen_name={0}".Fmt(name);
if (sinceId != null)
    url = url.AddQueryParam("since_id", sinceId);
if (maxId != null)
    url = url.AddQueryParam("max_id", maxId);

var tweets = url.GetJsonFromUrl()
    .FromJson<List<Tweet>>();

You can also use the `QueryStringSerializer` to serialize a number of different collection types, e.g:

//Typed POCO
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
   new Login { Username="mythz", Password="password" });

//Anonymous type
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
   new { Username="mythz", Password="password" });

//string Dictionary
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
  new Dictionary<string,string> {{"Username","mythz"}, {"Password","password"}});

You can also serialize the built-in `NameValueCollection.ToFormUrlEncoded()` extension, e.g:

var url = "http://example.org/login?" + new NameValueCollection { 
    {"Username","mythz"}, {"Password","password"} }.ToFormUrlEncoded();

Problem

I'm building a Request/Acknowledge/Poll style REST service with NServiceBus underneath to manage queue processing. I want to give the client a URI to poll for updates. Therefore I want to return a location header element in my web service as part of the acknowledgement. I can see that it is possible to do this: ``` return new HttpResult(response, HttpStatusCode.Accepted) { Location = base.Request.AbsoluteUri.CombineWith(response.Reference) } ``` But for a Url such as: `http://localhost:54567/approvals/?message=test`, which creates a new message (I know I should probably just use a POST), the location will be returned as: `http://localhost:54567/approvals/?message=test/8f0ab1c1a2ca46f8a98b75330fd3ac5c`. The ServiceStack request doesn't expose the Uri fragments, only the AbsouteUri. This means that I need to access the original request. I want this to work regardless of whether this is running in IIS or in a self hosted process. The closest I can come up with is the following, but it seems very clunky: ``` var reference = Guid.NewGuid().ToString("N"); var response = new ApprovalResponse { Reference = reference }; var httpRequest = ((System.Web.HttpRequest)base.Request.OriginalRequest).Url; var baseUri = new Uri(String.Concat(httpRequest.Scheme, Uri.SchemeDelimiter, httpRequest.Host, ":", httpRequest.Port)); var uri = new Uri(baseUri, string.Format("/approvals/{0}", reference)); return new HttpResult(response, HttpStatusCode.Accepted) { Location = uri.ToString() }; ``` This now returns: `http://localhost:55847/approvals/8f0ab1c1a2ca46f8a98b75330fd3ac5c` Any suggestions? Does this work regardless of how ServiceStack is hosted? I'm a little scared of the `System.Web.HttpRequest` casting in a self hosted process. Is this code safe?

Original source

Related problems