Get header values in ASP.NET MVC - asp.net-mvc

I have a requirement to capture the HTTP User Agent header coming in from a device, take the value and remove a 'uuid' This UUID can then be used to direct the device to the correct location to give it the files relevant to the device.
In webforms I was able to get it using
Request.ServerVariables["HTTP_USER_AGENT"]; //inside of Page_Load method
How would I go about this in MVC?

if in controller, you can easily get the header by this:
Request.Headers.GetValues("XXX");
if the name does not exist, it will throw an exception.

You do it the same way, in the controller:
Request.ServerVariables.Get("HTTP_USER_AGENT");
The Request object is part of ASP.NET, MVC or not.
See this for example.

It should be in the Request.Headers dictionary.

.Net 6 and above, this is how it works:
Request.Headers.TryGetValue("Auth-Token", out StringValues headerValues);
string jsonWebToken = headerValues.FirstOrDefault();
I prefer the new syntax which is more concise:
[HttpGet]
public async Task<IActionResult> GetAuth(FromHeader(Name = "Auth-Token")] string jwt) {
Headers without hypens -'s don't need the Name, they map automagically:
[HttpGet]
public async Task<IActionResult> GetAuth([FromHeader]string host) {

If there is anyone like me, who Googled to see how to get the Content-Type HTTP request header specifically, it's fairly easy:
Request.ContentType

With Core 3.1 and Microsoft.AspNetCore.Mvc.Razor 3.1, you can:
string sid = Request.Headers["SID"];
For whatever header variable you are looking for. Returns NULL if not found.

Related

How to pass value to httpget ActionResult

The Url bellow i am passing and wanted to receive value from my httpget ActionResult method. I already tested and getting error HTTP Error 404.0 - Not Found. Any idea to correct url or whats the solution?
http://localhost:53081/Dashboard/UpdatePassword/Email=John#gmail.com/Token=809a5bc2-5f1b-ce5b0203ff1b
[HttpGet]
public ActionResult UpdatePassword(string Email, string Token)
{
using (var db = new MyappEntities())
{
return View();
}
}
Parameter are used as query strings unless you setup routing for them in the pattern you want. Therefore your URL should look like
http://localhost:53081/Dashboard/UpdatePassword?Email=John#gmail.com&Token=809a5bc2-5f1b-ce5b0203ff1b
This is an incorrect way to pass the parameters. You need to follow the query string format (notice that # is encoded):
http://localhost:53081/Dashboard/UpdatePassword?Email=John%40gmail.com&Token=809a5bc2-5f1b-ce5b0203ff1b
Another option would be
http://localhost:53081/Dashboard/UpdatePassword/John%40gmail.com/809a5bc2-5f1b-ce5b0203ff1b
but that requires additional setup in your routing config, and frankly looks a bit off.
Updated url, try this:
http://localhost:53081/Dashboard/UpdatePassword?Email=John#gmail.com&Token=809a5bc2-5f1b-ce5b0203ff1b
You can read more about what a querystring is:
https://www.dotnetperls.com/querystring

OData Web API routing

I have a web API exposing ODATA from a SQL stored proc. I want to use a url like /odata/firmhierarchy(225) to pass 225 into a param for the stored proc. It just tells me that it can't find a matching resource. It hits the controller, just skips the method. Thoughts?
In webapiconfig
private static IEdmModel GenerateEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Employee>("Employees");
builder.EntitySet<Employee>("FirmHierarchy");
return builder.GetEdmModel();
}
Context:
public virtual ObjectResult<Employee> sp_EmployeeHierarchy(Nullable<int> managerEmpID)
{
var managerEmpIDParameter = managerEmpID.HasValue ?
new SqlParameter("ManagerEmpID", managerEmpID) :
new SqlParameter("ManagerEmpID", 0);
return ((IObjectContextAdapter)this).ObjectContext.ExecuteStoreQuery<Employee>("sp_EmployeeHierarchy #ManagerEmpID", managerEmpIDParameter);
}
Only method in controller:
[Queryable]
public IQueryable<Employee> GetFirmHierarchy()
{
return db.sp_EmployeeHierarchy(225).AsQueryable();
//return SingleResult.Create(db.Employees.Where(employee => employee.EmpId == key));
}
This should work:
1.Write another method in your controller:
[EnableQuery]
public IQueryable<Employee> Get([FromODataUri] int key)
{
return db.sp_EmployeeHierarchy(key).AsQueryable();
}
Please note that [EnableQuery] is an attribute introduced in Web API for OData V4. If you are still using Web API for OData V1-3, use [Queryable] still.
2.Then you can send the request
GET /odata/firmhierarchy(225)
and get the employees.
I was able to make ODATA work for a table, when auto-generated from entity framework. However, that generation process didn't want to work for a complex type returned by a Table Valued Function (similar scenario to a SP), because it didn't seem to understand where the key was.
What I found was that I could however make it work. First, I check out this article. He sets things up a bit more manually, where his Get on a companyProcessingController ends up routing for id 3 as "http://localhost:10020/odata/companyProcessing(3)" .
This surprised me. My other generated classes set up the pattern that SomeEntity became SomeEntityController, with methods like GetSomeEntities, and a routing that seemed to me to match the method but dropping the word get. Therefore, dropping the entity name from the Get method name seemed different, but it worked. Proving that the path is actually matching the controller name, not the method name.
In this Case you configure the routing using the data type you're querying for, and the beginning of the controller name. Then the actual path utilizes the beginning of the controller name as well.
And then all of this just brings us essentially to the other posted solution, assuming your controller name is firmhierarchyController
So, now, making sense of this... Try going to http://localhost:55063/odata/$metadata , where your port may differ. You'll notice that ODATA exposes a DataType, which is accessed via a DataSet. When a client tries to query into ODATA, they are trying to query against the DataSet, getting items of the DataType.
The DataSet matching the controller name (less Controller), and the Get methods can indeed just be Get without further extension of the name - and otherwise in this scenario was giving me problems.

ASP.NET MVC Read Raw JSON Post Data

This is driving me crazy. I'm using ASP.NET MVC. I have a controller with an HttpPost action that acts as a callback URL that is called by another server (not under my control). I want to dynamically read JSON posted to it without using WebAPI or Model Binding. The URL also has a query string parameter passed to it.
The callback URL looks something like this:
http://domain.com/callback?secret=1234
I've tried reading the posted input using:
[HttpPost]
public ActionResult Callback( String secret )
{
String jsonData = new StreamReader(this.Request.InputStream).ReadToEnd();
// ...
}
However "jsonData" is always null or empty.
I just want to get the posted input and stick it into JsonFx so I can dynamically access the contents. Any ideas on how to do this the easiest possible way?
UPDATE
I've discovered the following ...
While the above DOES NOT work (jsonData will be null or empty), the following DOES if I configure what little options I have on the calling server so as to omit the "secret" query string parameter, which is about all I can do on that end since it is not my server. In this case, jsonData will have the correct posted JSON string:
[HttpPost]
public ActionResult Callback( /* String secret */ )
{
String jsonData = new StreamReader(this.Request.InputStream).ReadToEnd();
// ...
}
This is very frustrating to work around and I don't know an easy way to accept both a query string and posted JSON data on a standard MVC controller.
I have a "callback controller" with Action methods that accept various data (via GET, via form POST, via JSON POST, via JSON POST w/ a Query String, etc.) from different third-party servers. These are merchant-type callbacks where I have no control over the formats or methods used to convey information. I just need to accept the callbacks and process the information that should be there.
All of it works fine in my Controller, except the case of "JSON POST w/ a Query String".
This appears (at least to me) to be a shortcoming in standard ASP.NET MVC controllers. ???
Can anyone suggest a solution to this that can be used in a standard ASP.NET MVC controller?
Your initial approach should work if you take into consideration the fact, that ASP.NET MVC model binding has already read the stream, so you should rewind it:
[HttpPost]
public ActionResult Callback(string secret)
{
Request.InputStream.Seek(0, SeekOrigin.Begin);
string jsonData = new StreamReader(Request.InputStream).ReadToEnd();
// ...
}
Reset the position to Zero before reading the stream.
Request.InputStream.Position = 0
For ASP.NET Core 2,this works for me.
[HttpPost]
public ActionResult RawTest() {
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
string content = reader.ReadToEndAsync().Result;
//...
}
//...
}

Is there simple way to use bookmarks in controller action's generated urls?

Currently I am working with simple Forum module in ASP.NET MVC 3 which i will add later to my main application. The possibility to link to certain blocks like div used to present thread replies is very useful.
I figured out something which work and propably will be enough for my needs, I just wonder if there is something more elegant and simple aswell. I found a solution using ActionFilters, and since I'm quite begginner in MVC I would like to find some easier solution (if exists). Well i will propably learn ActionFilters soon aswell :)
So here is what I've done:
public ActionResult ShowThread(int id, int? postID)
{
var thread = db.ForumThreads.Find(id);
if (postID != null)
{
return Redirect(Url.Action("ShowThread",new {id=id})+"#post-"+postID.ToString());
}
return View(thread);
}
I know it is quite simple, but it is working. Also it doesn't check if the postID is valid yet, but it is not a part of question.
The solution is to use one of RedirectToAction overloads: http://msdn.microsoft.com/en-us/library/dd470154(v=vs.108).aspx.
Perhaps, in your case, the next one would do: http://msdn.microsoft.com/en-us/library/dd460291(v=vs.108).aspx
And the call would be:
return this.RedirectToAction("ShowThread", new { id = id, post = postID });
Another (simpler, but not safer!) solution is to format the URL you need to redirect to and to use the Redirect() method like this:
var redirectUrl = string.Format("/Home/ShowThread/{0}?post={1}", id, postID);
return this.Redirect(redirectUrl);
Pay attention to your URL mappings, though. The examples above assume the method
public ActionResult ShowThread(int id, int? post)
is in HomeController and the default route has not been changed. Otherwise you should
adjust the URL prepending the controller name (w/o Controller), or
change your default route to map to the controller's name.

ASP.NET MVC Preview 5 routing ambiguity

I have a problem with a sample routing with the preview 5 of asp.net mvc.
In the AccountController I have 2 actions:
public ActionResult Delete()
public ActionResult Delete(string username)
While trying to look for Account/Delete or Account/Delete?username=davide the ControllerActionInvoker throws a exception saying that Delete request is ambiguous between my tow actions methods.
The default route in the global.asax hasn't been changed.
Shouldn't the action invoker understand what's the method to call looking in the parameters list?
Using the preview 4 I hadn't these kind of problem performing the same operation.
Any idea?
Solution found!
With the introduction of the ActionNameAttribute, it's now necessary to filter manually which method to call depending on the request. This is done by the ActionSelectionAttribute.
Full explanation here: http://haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx
I can't say for sure why this is happening. But you might want to consider only having the Delete(string username) action and removing the parameter-less overload.
Because string is nullable my understanding is that simply calling Account/Delete will invoke the action with a null username parameter which you can then test for at the beginning of the action method.
What I'd do is ditch the blank Delete(), and only use Delete(string username)
In your url routing you'd have something similar to "/{Controller}/{Action}/{username}/" ?
If you have "/{Controller}/{Action}/{Id}/" you'd be better off doing Delete(string id) and that way just using the url to handle this "/Account/Delete/davide/"
That said use your default route which should be something like the default Id is ""
Then in your Delete(string id) method have:
public ActionResult Delete(string id)
{
if(string.IsNullOrEmpty(id)) return EmptyID();
// Continue normal Delete method
}
public ActionResult EmptyID()
{
// The method you were going to have on a blank delete.
}
That or just wrap it up in the one method on an if {} else {}
Either way I'd just be going with the one method and doing a default on your username/id in your route of an empty string and handle it that way.
If you want to contact me on further follow up to what I mean, or whatever will help, ping me at andrew# my domain on my info page.
Edit: Ah pretty much what Berko said anyway, I'm not sure how Named Attributes would help - so please post a comment here detailing it for other guys who find the same issues! :)
Its ambiguous because the two controller action are the same post method..
You can only used that in form posting scenario for example you are submitting a form data that uses HTTP post..

Resources