52

I found a blog post that shows how to "shim" familiar things like HttpResponseMessage back into ASP.NET Core MVC, but I want to know what's the new native way to do the same thing as the following code in a REST Post method in a Controller:

// POST audit/values
[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]string value)
{
    var NewEntity = _repository.InsertFromString(value);

    var msg = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Created);
    msg.Headers.Location = new Uri(Request.RequestUri + NewEntity.ID.ToString());
    return msg;

}

In an ASP.NET Core MVC project, I can't seem to get Request.RequestUri.

I tried inspecting Request, and I was able to make a function like this:

private string UriStr(HttpRequest Request)
{
    return Request.Scheme + "://" + Request.Host + Request.Path; // Request.Path has leading /
}

So I could write UriStr(Request) instead. But I'm not sure that's right. I feel like I'm hacking my way around, and not using this correctly.

A related question for earlier non-Core ASP.NET MVC versions asks how to get the base url of the site.

LatentDenis
  • 2,839
  • 12
  • 48
  • 99
Warren P
  • 65,725
  • 40
  • 181
  • 316

3 Answers3

99

Personally, I use :

new Uri(request.GetDisplayUrl())
  • GetDisplayUrl fully un-escaped form (except for the QueryString)
  • GetEncodedUrl - fully escaped form suitable for use in HTTP headers

These are extension method from the following namespace : Microsoft.AspNetCore.Http.Extensions

Piotr Kula
  • 9,597
  • 8
  • 59
  • 85
t.ouvre
  • 2,856
  • 1
  • 11
  • 17
  • 1
    That seems nice and clean. – Warren P Nov 21 '16 at 21:37
  • elegant one! :+1 – mihai Mar 27 '18 at 13:22
  • 2
    This certainly looks a lot cleaner, and more likely to handle the edge cases that a home-made solution might overlook. However, there is one thing about this that raises a red flag for me. Its purpose is only for display. From the comments: > Returns the combined components of the request URL in a fully un-escaped form > (except for the QueryString) suitable only for display. This format should not > be used in HTTP headers or other HTTP operations. I don't know what display-specific functionality there is, but it might not play nicely with the Uri constructor. – Ken Lyon Jun 25 '18 at 17:37
  • 7
    After writing all that, I now see there's a more appropriate method in the same package: GetEncodedUrl. – Ken Lyon Jun 25 '18 at 17:44
26

A cleaner way would be to use a UriBuilder:

private static Uri GetUri(HttpRequest request)
{
    var builder = new UriBuilder();
    builder.Scheme = request.Scheme;
    builder.Host = request.Host.Value;
    builder.Path = request.Path;
    builder.Query = request.QueryString.ToUriComponent();
    return builder.Uri;
}

(not tested, the code might require a few adjustments)

LatentDenis
  • 2,839
  • 12
  • 48
  • 99
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • If this is the only way to do it, then it's true that they left out capabilities that people used before, when redesigning? Have you seen other similar omissions yet? – Warren P Jul 24 '15 at 19:54
  • 1
    @WarrenP Of course they left a lot of things about. It's basically rewritten from the ground up. And, it's still in beta. – mason Jul 24 '15 at 20:08
  • 1
    Uris may also contain usernames and passwords, which are not accounted for in this snippet. – Andrew Theken Jun 24 '16 at 14:34
  • 5
    also doesn't handle port numbers in the host. use: `builder.Host = request.Host.Host; builder.Port = request.Host.Port ?? -1;` – Ben McIntyre Jul 17 '18 at 13:41
14

Here's a working code. This is based off @Thomas Levesque answer which didn't work well when the request is from a custom port.

public static class HttpRequestExtensions
{
    public static Uri ToUri(this HttpRequest request)
    {
        var hostComponents = request.Host.ToUriComponent().Split(':');

        var builder = new UriBuilder
        {
            Scheme = request.Scheme,
            Host = hostComponents[0],
            Path = request.Path,
            Query = request.QueryString.ToUriComponent()
        };

        if (hostComponents.Length == 2)
        {
            builder.Port = Convert.ToInt32(hostComponents[1]);
        }

        return builder.Uri;
    }
}
Dealdiane
  • 3,984
  • 1
  • 24
  • 35
  • 1
    Watch out for the request.Path property. At present it seems to have a bug and always returns "/" whether or not the application is deployed to a virtual application. – Paul Taylor Mar 02 '16 at 10:09
  • 2
    Uris may also contain usernames and passwords, which are not accounted for in this snippet. – Andrew Theken Jun 24 '16 at 14:34