Url Referrer is not available in WebApi 2 MVC project - c#

I have an MVC WebAPI 2 project with a Controllers controller. The Method I'm trying to call is POST (Create). I need to access the referring URL that called that method yet, no matter what object I access, the referring URL either doesn't exist in the object or is null.
For example, I've added the HTTPContext reference and the following returns null:
var thingythingthing = HttpContext.Current.Request.UrlReferrer;
The Request object does not have a UrlReferrer property.
This returns null as well:
HttpContext.Current.Request.ServerVariables["HTTP_REFERER"]
I cannot modify the headers because I need to be able to generate a link to the method and filter access by origin of the call.
Any particular place I should be look or, alternatively, any particular reason why those are returning null?
Edit: I have a solution for GET methods (HttpContext.Current.Request.RequestContext.HttpContext.Request.UrlReferrer) but not for POST methods.

See this answer. Basically, WebAPI requests use a different kind of request object. You can create an extension method that provides a UrlReferrer for you, though. From the linked answer:
First, you can extend HttpRequestMessage to provide a UrlReferrer() method:
public static string UrlReferrer(this HttpRequestMessage request)
{
return request.Headers.Referrer == null ? "unknown" : request.Headers.Referrer.AbsoluteUri;
}
Then your clients need to set the Referrer Header to their API Request:
// Microsoft.AspNet.WebApi.Client
client.DefaultRequestHeaders.Referrer = new Uri(url);
And now the Web API Request includes the referrer data which you can access like this from your Web API:
Request.UrlReferrer();

Related

Can you use custom HTTP request methods with http.client?

Is there a way to use HTTP request methods that are not implemented by System.Net.Http.HttpMethod?
I try to update files with a REST interface. The way it is implemented, I GET a list of files and their hashes. Then I check if any of these files have changed on my side and if so, I POST each file to the API, otherwise I skip it.
When I'm done, the endpoint expects an UPDATE request to know that I'm done sending files. But there is no UPDATE method in HttpMethod.
Is there a way to alter REQUEST_METHOD manually in a HttpRequestMessage or do they need to recode the endpoint?
Looking up System.Net.Http.HttpMethod only gives the following options: GET, PUT, POST, DELETE, HEAD, OPTIONS, TRACE, PATCH and CONNECT. There is no obvious way to add a custom method.
In the case where you need an HttpMethod that does not exist in the static properties of the class, you can just use the constructor which allows you to pass any string method:
var customHttpMethod = new HttpMethod("UPDATE");

How to clean up existing response in webapi?

There is a authentication library that I have to use that helpfully does things like
Response.Redirect(url, false);
inside of it's method calls. I can't change this libraries code and it's fine for MVC style apps but in angular SPA -> WebApi apps this is just awful.
I really need a 401 otherwise I get into trouble with CORS when my angular scripts, using $http, try to call out to the auth server on another domain in response to the 302, that's if it even could as the Response.Redirect also sends down the object moved html and the angle brackets cause an error to be thrown.
Since I have to make the call to the auth library first the Response.Redirect is already in the response pipeline and so I need to clean it up to remove the body content and convert the 302 into a 401. I thought I could just:
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent("data");
}
but this just gets appended to the response and doesn't replace it plus I also need the Location: header which I can't seem to access via WebApi methods.
So instead I've had to do this in my ApiController:
var ctxw = this.Request.Properties["MS_HtpContext"] as HttpContextWrapper;
var ctx = ctxw.ApplicationInstance.Context;
var url = ctx.Response.RedirectLocation;
ctx.Response.ClearContent();
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent(url);
}
But this seems terrible and counter to webapi "feel". Plus I'm tied to the controller in doing this. I can't get the wrapper in a MessageHandler for example.
What I'd like to do is monitor the response for a given route in a message handler or in an AuthorizationFilterAttribute, if its a 302, I want to read it's headers, take what I want, wipe it and replace it with my own "fresh" response as a 401. How can I do this?
You might want to write your own ActionFilter and override its OnActionExecuted method where you can access HttpActionExecutedContext. From there, you can check response code, for example, and overwrite response with whatever you want.
Ref: https://msdn.microsoft.com/en-us/library/system.web.http.filters.actionfilterattribute.onactionexecuted%28v=vs.118%29.aspx#M:System.Web.Http.Filters.ActionFilterAttribute.OnActionExecuted%28System.Web.Http.Filters.HttpActionExecutedContext%29

How do I set out Attribute in Api Controller

is it possible to use out attribute in a Api Controller method? I'm using C#.
for exp:
[HttpGet]
public string GetWhatever(string type, string source,out int errorCode, out string errorMessage)
if it is, an example of how to call it and get the out value would be great.
No, this is not possible. Only the return value is used and sent to the client.
You should sent a proper HTTP status code and the error message in body. Have a look at this: http://www.asp.net/web-api/overview/error-handling/exception-handling
I believe you miss-understand the usage of the Web API.
Your Web Api method will not be called like any other C# class method, unless you access the library directly and reference the api controller and its method like any other C# class.
The method will be called via the ASP.NET action selector and that will depend on your HTTP verb (GET, PUT, POST, DELETE or PATCH) and depending on the type and the number of your parameters.
Now your method can return your data or returns error depending on your situation, but eventually all your responses will convert to statuscode/content/error,...etc which is what the HTTP protocol understands and deals with.
for example your method can return Ok Status code (200), or Notfound status code 404 depending on where your request found the requested resource or not.
You can start with this article about Web API 2, hopefully you get a better understanding.
Hope that helps.

Utilizing Web API on client side

I have created a simple web api controller in mvc4 containing 4 methods (one for each CRUD operation). I'm able to use fiddler to test that the methods in my controller work.
I'm now trying to make a unit test to prove that these work. I've managed to serialize my client side object into json format, but now how do I use this string of json to actually invoke my methods?
If it helps, I am using Json.NET to serialize my client object - although I don't think this extention actually handles the delivery and retreival of it to the server.
Your unit tests should be written against the controller - so you don't need to make an actual HTTP request to unit test your Web API code, you just call the methods.
From a design perspective, if you want a restful Web API, the client should be able to send a standard HTTP message without having to serialize the request.
This is the kind of approach I have used to post an object to a restful Web API:
HttpResponseMessage response;
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://url_to_service");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var responseTask = client.PostAsJsonAsync("api/resource/somethingelse", someObjectToPost).Result;
responseTask.Wait();
response = responseTask.Result;
if (response.IsSuccessStatusCode)
{
var contentTask = response.Content.ReadAsAsync<SomeResponseType>();
contentTask.Wait();
SomeResponseType responseContent = contentTask.Result;
}
else
{
//Handle error.
}
In this case, someObjectToPost is your client-side object, though you can leave it to Web API to serialize it for you. In the above example I am assuming the reponse is of fictional type SomeResponseType - you can also use ReadAsStringAsync if the response is expected to be plain text.
The code presented here by nick_w is correct. You need to use HttpClient object. And as Steve Fenton mentioned, to create unit test you don't want to do it - rather test directly against controller. But for the functional test you can do it. I've done same thing. I've created helper class so I need only to call one of Http helper methods, depending if it is GET or POST, etc. that I do. This helper uses generic types so it operates with any types that being passed.

Getting the HTTP Referrer in ASP.NET

I'm looking for a quick, easy and reliable way of getting the browser's HTTP Referrer in ASP.Net (C#). I know the HTTP Referrer itself is unreliable, but I do want a reliable way of getting the referrer if it is present.
You could use the UrlReferrer property of the current request:
Request.UrlReferrer
This will read the Referer HTTP header from the request which may or may not be supplied by the client (user agent).
Request.Headers["Referer"]
Explanation
The Request.UrlReferrer property will throw a System.UriFormatException if the referer HTTP header is malformed (which can happen since it is not usually under your control).
Therefore, the Request.UrlReferrer property is not 100% reliable - it may contain data that cannot be parsed into a Uri class. To ensure the value is always readable, use Request.Headers["Referer"] instead.
As for using Request.ServerVariables as others here have suggested, per MSDN:
Request.ServerVariables Collection
The ServerVariables collection retrieves the values of predetermined environment variables and request header information.
Request.Headers Property
Gets a collection of HTTP headers.
Request.Headers is a better choice than Request.ServerVariables, since Request.ServerVariables contains all of the environment variables as well as the headers, where Request.Headers is a much shorter list that only contains the headers.
So the most reliable solution is to use the Request.Headers collection to read the value directly. Do heed Microsoft's warnings about HTML encoding the value if you are going to display it on a form, though.
Use the Request.UrlReferrer property.
Underneath the scenes it is just checking the ServerVariables("HTTP_REFERER") property.
Like this: HttpRequest.UrlReferrer Property
Uri myReferrer = Request.UrlReferrer;
string actual = myReferrer.ToString();
I'm using .Net Core 2 mvc,
this one work for me ( to get the previews page) :
HttpContext.Request.Headers["Referer"];
Since Google takes you to this post when searching for C# Web API Referrer here's the deal: Web API uses a different type of Request from normal MVC Request called HttpRequestMessage which does not include UrlReferrer. Since a normal Web API request does not include this information, if you really need it, you must have your clients go out of their way to include it. Although you could make this be part of your API Object, a better way is to use Headers.
First, you can extend HttpRequestMessage to provide a UrlReferrer() method:
public static string UrlReferrer(this HttpRequestMessage request)
{
return request.Headers.Referrer == null ? "unknown" : request.Headers.Referrer.AbsoluteUri;
}
Then your clients need to set the Referrer Header to their API Request:
// Microsoft.AspNet.WebApi.Client
client.DefaultRequestHeaders.Referrer = new Uri(url);
And now the Web API Request includes the referrer data which you can access like this from your Web API:
Request.UrlReferrer();
string referrer = HttpContext.Current.Request.UrlReferrer.ToString();
Sometime you must to give all the link like this
System.Web.HttpContext.Current.Request.UrlReferrer.ToString();
(in option when "Current" not founded)
Using .NET Core or .NET 5 I would recommend this:
httpContext.Request.Headers.TryGetValue("Referer", out var refererHeader)
Belonging to other reply, I have added condition clause for getting null.
string ComingUrl = "";
if (Request.UrlReferrer != null)
{
ComingUrl = System.Web.HttpContext.Current.Request.UrlReferrer.ToString();
}
else
{
ComingUrl = "Direct"; // Your code
}

Categories