6

I am writing a C# application that needs to callout to a webapp. I am trying to use System.Uri to combine two URL's: A base URL and the relative path to the specific service (or many) of the webapp I need. I have a class member named webappBackendURL that I want to define in one place, with all calls building from it (webappBackendURL is not defined as close as my examples illustrate).

System.Uri webappBackendURL = new System.Uri("http://example.com/");
System.Uri rpcURL           = new System.Uri(webappBackendURL,"rpc/import");
// Result: http://example.com/rpc/import

This works, however, if webappBackendURL contains a query string, it is not preserved.

System.Uri webappBackendURL = new System.Uri("http://example.com/?authtoken=0x0x0");
System.Uri rpcURL           = new System.Uri(webappBackendURL,"rpc/import");
// Result: http://example.com/rpc/import <-- (query string lost)

Is there a better way combine URLs? The .NET library is extensive, so I'm thinking I might have just overlooked a built-in way to handle this. Ideally, I would like to be able to combine URLs like this:

System.Uri webappBackendURL = new System.Uri("http://example.com/?authtoken=0x0x0");
System.Uri rpcURL           = new System.Uri(webappBackendURL,"rpc/import?method=overwrite&runhooks=true");
// Result: http://example.com/rpc/import?authtoken=0x0x0&method=overwrite&runhooks=true
spender
  • 117,338
  • 33
  • 229
  • 351
jimp
  • 16,999
  • 3
  • 27
  • 36

5 Answers5

2

You could do something like this:

System.Uri webappBackendURL = 
  new System.Uri("http://example.com/?authtoken=0x0x0");
System.Uri rpcURL = new System.Uri(webappBackendURL,
  "rpc/import?ethod=overwrite&runhooks=true" 
  + webappBackendURL.Query.Replace("?", "&"));
spender
  • 117,338
  • 33
  • 229
  • 351
Brad
  • 639
  • 1
  • 9
  • 23
1
System.Uri webappBackendURL = new System.Uri("http://example.com/?authtoken=0x0x0");
System.Uri rpcURL           = new System.Uri(webappBackendURL,string.Format("rpc/import?{0}method=overwrite&runhooks=true", string.IsNullOrWhiteSpace(webappBackendURL.Query) ? "":webappBackendURL.Query + "&"));

Although I would probably create a method that takes two URIs and does the processing there so that it looked a little cleaner.

public static Uri MergerUri(Uri uri1, Uri uri2)
    {
        if (!string.IsNullOrWhiteSpace(uri1.Query))
        {
            string[] split = uri2.ToString().Split('?');

            return new Uri(uri1, split[0] + uri1.Query + "&" + split[1]);
        }
        else return new Uri(uri1, uri2.ToString());
    }
jfin3204
  • 699
  • 6
  • 18
  • I hit a `UriFormatException` when I tried to construct a `Uri` from my simple path, so I don't think I can reliably use `MergerUri`. I might try to wrap your initial suggestion into a method. – jimp Oct 23 '12 at 17:19
  • Sorry about that I didn't test it first. The updated one will work but it is similar to what you decided on. – jfin3204 Oct 23 '12 at 19:05
1

Try UriTemplate:

Uri baseUrl = new Uri("http://www.example.com");
UriTemplate template = new UriTemplate("/{path}/?authtoken=0x0x0");
Uri boundUri = template.BindByName(
    baseUrl,
    new NameValueCollection {{"path", "rpc/import"}});

System.UriTemplate has moved around between different versions of .NET. You'll need to determine which assembly reference is correct for your project.

Brenda Bell
  • 1,139
  • 8
  • 10
  • I only used one parameter because that most closely matched what you were asking for, but you can have templates with more than one (/{x}/{y}/foo). Obviously there would be one entry in the NameValueCollection for each of the placeholders. – Brenda Bell Oct 24 '12 at 13:36
1
var originalUri = new Uri("http://example.com?param1=1&param2=2");
var resultUri = new Uri(new Uri(originalUri, "/something"), originalUri.Query);

resultUri: http://example.com/something?param1=1&param2=2

Kamarey
  • 10,832
  • 7
  • 57
  • 70
0

Using ideas and pieces from the answers received, I wrote a wrapper method that achieved exactly what I was looking for. I hoped the core .NET classes could handle this, but it looks like they cannot.

This method will take a full URL (http://example.com?path?query=string) and combine a relative URL (string) in the form of relative/path?query=string&with=arguemnts into it.

private static System.Uri ExtendURL(System.Uri baseURL, string relURL)
{
    string[] parts = relURL.Split("?".ToCharArray(), 2);
    if (parts.Length < 1)
    {
        return null;
    }
    else if (parts.Length == 1)
    {
        // No query string included with the relative URL:
        return new System.Uri(baseURL,
                              parts[0] + baseURL.Query);
    }
    else
    {
        // Query string included with the relative URL:
        return new System.Uri(baseURL,
                              parts[0] + (String.IsNullOrWhiteSpace(baseURL.Query) ? "?" : baseURL.Query + "&") + parts[1]);
    }
}

ExtendURL(new System.Uri("http://example.com/?authtoken=0x0x0"),"rpc/import?method=overwrite&runhooks=true");
// Result: http://example.com/rpc/import?authtoken=0x0x0&method=overwrite&runhooks=true

Thank you to everyone that contributed! I upvoted all of your answers.

jimp
  • 16,999
  • 3
  • 27
  • 36