Please see the code below, which is similar to some code I am looking at:
[HttpGet]
public IActionResult Create([FromHeader(Name = "x-requestid")] string requestId)
{
return View();
}
[HttpPost]
public IActionResult Create(Person person, [FromHeader(Name = "x-requestid")] string requestId)
{
if (ModelState.IsValid)
{
string test = "got here";
}
return View();
}
requestId is always null. How is requestId populated?
I have read lots of questions over the last two hours e.g. this one: What is the X-REQUEST-ID http header?. An answerer to another question suggesting installing the following Nuget package:
Microsoft.ApplicationInsights.ASPNetCore
However, this made no difference.
In general the "x-*" headers are non-standard ones.
That particular one is probably coincidentally used within Application Insights to uniquely identify a request, but it's unlikely to be sending requests to your server including it.
Whatever client is sending requests to your server has to be explicitly adding that header for you to receive it there; it's not part of any standard HTTP request.
You are bound to request header with name "x-requestid", but it should be called "X-Request-ID". Just try:
[HttpGet]
public IActionResult Get([FromHeader(Name = "x-request-id")] string requestId)
{
return View();
}
Related
Inside my ASP.NET WebApi program, I have an Author model:
public class Author
{
public int Id { get; set; }
[Required] public string Name { get; set; }
}
I also have an AuthorsController, with a PostAuthor(Author author) method:
// POST: api/Authors
[ResponseType(typeof(Author))]
public async Task<IHttpActionResult> PostAuthor(Author author)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// etc.
}
When I send a POST request programmatically inside my unit tests, HTTP Status Code 201 Created is returned:
However, when I send a POST request using Postman, I receive HTTP Status Code 400 Bad Request instead:
As you can see, when I send a POST request using Postman, the argument passed into the PostAuthor(Author author) method is null, and model validation fails as a result:
What should I do to ensure that POST requests from Postman can be processed?
Couple of changes: define it as HttpPost and use FromBody like
// POST: api/Authors
[HttpPost]
[ResponseType(typeof(Author))]
public async Task<IHttpActionResult> PostAuthor([FromBody] Author author)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// etc.
}
Replace = with : in postman body, its a JSON after all.
If you send in application/json and your API wait as INBOUND JSON, so try to send in JSON format, something like
{
"Id":"6",
"Name":"P.G. Wodehouse"
}
I'm having an issue with an endpoint, it takes an object which isn't binding and consequently returning a 400 bad request.
I've gotten around this issue by passing in the individual properties of the object rather than the object itself, but would prefer the passing of an object.
WebClient webClient = new WebClient();
webClient.QueryString.Add("firstName", "value1");
webClient.QueryString.Add("lastName", "value2");
string result = webClient.DownloadString(url);
[HttpGet]
public async Task<IActionResult> DoSomething(string firstName, string lastName)
{
// this endpoint works perfectly
return Ok();
}
[HttpGet]
public async Task<IActionResult> DoSomething([FromBody]SubmitModel model)
{
// this endpoint returns a 400 bad request
return Ok();
}
public class SubmitModel
{
public string FirstName {get; set;}
public string LastName {get; set;
}
By design, GET request does not contain data in the request body.
So when your Submit method recieves a request, it can't bind the model from the body as the data does not exist and therefore returns an bad request response.
As your method is named Submit, it sounds like you should use a POST request instead. POST request, by design, sends data in the request body and is suited for submitting data to the server.
Try it like this
[HttpPost]
public async Task<IActionResult> Submit([FromBody]SubmitModel model)
{
// this endpoint returns a 400 bad request
return Ok();
}
I don't know if there is a good way to do what you're wanting. To get a little bit closer you can add this attribute to pull directly from the url
[HttpGet]
public ActionResult Get([FromUri]SubmitModel model)
{
// this endpoint returns a 400 bad request
return Ok();
}
Another thing you can do if need be is create an extension method that reflects over the model and adds all the properties/values to the query string. Some good examples here How do I serialize an object into query-string format?
I got the following address:
api/users/AddNew/<object here>
And so, I did something like this to test it out:
api/users/AddNew/{"Id":0,"NameFirst":"NewUser","NameLast":"NewUserLast","DateOfBirth":"2018/07/27"}
But all I get is a "This localhost page can't be found". Debugging in Visual Studio I set a breakpoint right when the code is supposed to trigger, but it never hits the debug point. Code below:
[HttpPost(Name = "AddNew")]
[Route("AddNew/{jsonUser}")]
public ActionResult<User> Post([FromBody] User newUser)
{
if (newUser != null) // Debug Point here never triggers
{
return Facade.AddNewUser(newUser);
}
else
{
return new User() { Id = 0, NameFirst = ErrorCodeUtility.GetEnumName(ErrorCodes.API_INVALID_POST_OBJECT) };
}
}
The User Model:
public class User
{
public uint Id;
public String NameFirst;
public String NameLast;
public DateTime DateOfBirth;
}
So, I'm assuming I'm doing something wrong either with my request or my C# code, but I can't quite find out which one of them it is. Sorry I'm a bit new at this :)
There are at least three problems here:
You cannot call a POST method by navigating to an URL, since that executes a GET. You need a tool such as Postman for this testing.
[FromBody] means that the data will come as part of the body of the request, so the data would be ignored even if the request could be processed (which cannot be, as explained in point 1). Note, however, that since you are using ASP.NET Core 2.1, you don't actually need to use [FromBody] as that is the default, as explained here.
You say you want to create a REST API. /AddNew doesn't follow REST.
Your method should be:
[HttpPost]
public ActionResult<User> Post([FromBody] User newUser)
And your URL would then be:
localhost:somePort/api/users
I am new in web api and I am not also a very advanced developer. I've seen an article that shows how we can use multiple http verbs for a single action.
So I like to know that the approach is good. Otherwise then, what can be worse when someone uses multiple http verbs for a single action?
Code taken from this area https://www.codeproject.com/Articles/1005485/RESTful-Day-sharp-Security-in-Web-APIs-Basic#_Toc423441907
[GET("allproducts")]
[GET("all")]
public HttpResponseMessage Get()
{ }
[GET("productid/{id?}")]
[GET("particularproduct/{id?}")]
[GET("myproduct/{id:range(1, 3)}")]
public HttpResponseMessage Get(int id)
{ }
[POST("Create")]
[POST("Register")]
public int Post([FromBody] ProductEntity productEntity)
{ }
[PUT("Update/productid/{id}")]
[PUT("Modify/productid/{id}")]
public bool Put(int id, [FromBody] ProductEntity productEntity)
{ }
// DELETE api/product/5
[DELETE("remove/productid/{id}")]
[DELETE("clear/productid/{id}")]
[PUT("delete/productid/{id}")]
public bool Delete(int id)
{ }
1) In what kind of scenario people use multiple http verbs for a single action because they create multiple routes for a single action that can confuse people ....... should approach below is good or not ?
[GET("productid/{id?}")]
[GET("particularproduct/{id?}")]
[GET("myproduct/{id:range(1, 3)}")]
public HttpResponseMessage Get(int id)
{}
2)PUT and DELETE is different verbs. how one can use different verbs for single action....is it right approach.
[DELETE("remove/productid/{id}")]
[DELETE("clear/productid/{id}")]
[PUT("delete/productid/{id}")]
public bool Delete(int id)
{
if (id > 0)
return _productServices.DeleteProduct(id);
return false;
}
please clarify the pros and corns of the above code and approach in details. thanks
This is more to do with the design of your application, and how you like your app to be routed. For example, particularproduct/{id?} for getting one of any product, while myproduct/{id:range(1, 3) means getting one of my products, and each person can only have a max of 3 products (that's why there is a range limit).
[GET("productid/{id?}")]
[GET("particularproduct/{id?}")]
[GET("myproduct/{id:range(1, 3)}")]
public HttpResponseMessage Get(int id){}
PUT, DELETE both has side effects, i.e. changes to data. You can even use POST for the Delete(..) action method. In some situations, PUT & DELETE may not be supported (Are the PUT, DELETE, HEAD, etc methods available in most web browsers?), so you have to use POST instead.
So, again, it depends on the design of your app, and having multiple URI's allows you to use it in different scenarios. Most of the time, I just use one URI for each action method.
I have simple console application, which send json data to controller.
Client.PostAsJsonAsync("http://[site].azurewebsites.net/api/Decision", report);
And controller:
public class DecisionController : ApiController
{
private readonly TaskManager _taskManager = new TaskManager();
[HttpGet]
public Decision Get(int id)
{
return _taskManager.GetDecision(id);
}
[HttpPost]
public void Post(Decision decision)
{
_taskManager.UpdateDecision(decision);
}
}
Visual Studio debugger shows, that a request does not reach the controller (not trigger a breakpoint). Console application does not throw any exceptions, and report variable does not equal to null.
How can I debug this?
You might want to take a look at Fiddler which is a free tool to debug web requests. Basically, it monitors all web requests going through your machine and lets you see what they look like. You can also generate new ones straight from there too. That way, you can at least make sure that your request is properly formatted.
Also, I noticed that you are trying to call your controller directly when you should be calling an action on your controller instead. When you request GET api/Decision, you also need to provide an action method. I do not know enough of your model to restructure your controller properly, but here is an example based on a simple user profile.
public class ProfileController : ApiController
{
[HttpGet]
public string FullName()
{
return "Foo Bar";
}
[HttpPost]
public void FullName(string newName)
{
// ...
}
[HttpGet]
public int Age()
{
return 22;
}
[HttpPost]
public void Age(int newAge)
{
// ...
}
}
As you can see, the HttpVERB attribute is not used to dispatch requests to a controller to specific methods. It is used to distinguish the different overloads of related restful actions. In this case, it is used to distinguish between getting and setting a FullName and an Age property.
If you with to keep your controller intact, you should be requesting:
POST http://[site].azurewebsites.net/api/Decision/post
GET http://[site].azurewebsites.net/api/Decision/get