Related
I have the following api definition
[RoutePrefix("api/lead/1.0")]
public class LeadController:ApiController
{
[Route("/{id:integer}/request-td")]
[HttpPost]
public IHttpActionResult SubmitLead(int id,
FromBody]FormData FormData)
{
}
}
When my QA department is testing this code, they are calling
/api/lead/1.0/12345/request-td
with a valid body and everything passes
However if they change the id from an int to a string,
/api/lead/1.0/invalidid/request-td
They are getting back an iis 404 message.
As a temp solution I have changed the id from an int to a string, and removed the definition from the route.
Within the controller is performing a TyParse to make sure that a valid integer has been passed in the url
However this solution is not very elegant for me
Is there any way so that i can leave the id field defined as an int, with the correct type defined in the route, trap the invalid api request, and then send back my own custom error. ie different http status code and message body
If I have the signature as an int, but with no variable definiton in the route,
[Route("/{id}/request-td")]
[HttpPost]
public IHttpActionResult SubmitLead(int id,
FromBody]FormData FormData)
It is sending back too much information as to why the request is invalid
What I have seen so far, is that you need to get the definitions created in the correct order in global.asax not how to trap invalid api requests and return my own response
If you want receive "string" or "int" as request parameter then you need to write multiple time your "Route" attribute to add it in routing map.
Following is solution to receive values.
[Route("{id:int}/request-td")]
[Route("{id:alpha}/request-td")]
This will accept both "string" and "int" request and don't 404 page.
Hope this code will help you.
I would actually create a custom attribute.
public class CheckArgumentTypeAttribute : ActionFilterAttribute
{
private readonly string ActionArgumentName;
public CheckArgumentIsPositiveAttribute(string actionArgumentName)
{
if (string.IsNullOrWhiteSpace(actionArgumentName)) throw new ArgumentException(nameof(actionArgumentName));
ActionArgumentName = actionArgumentName;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
var keyValuePair = actionContext.ActionArguments.FirstOrDefault(x => x.Key.Equals(ActionArgumentName, StringComparison.OrdinalIgnoreCase));
if (keyValuePair.Equals(default(KeyValuePair<string, object>)) || !int.TryParse(keyValuePair.Value, out in result))
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(JsonConvert.SerializeObject(new YourClass())), Encoding.UTF8, MimeTypes.Application.Json)
};
}
}
}
Then I would decorate my action methods as
[CheckArgumentType("id")]. It is possible to create dynamic error message based on the ActionArgumentName or to further extend this attribute.
I am new to C#. I tried to create a post service with using int. All get and post service are working fine.
But when I pass parameter to post service, it's always null. But after creating a class it works fine. Can we pass direct int to service or we must have to create a model class for it?
[System.Web.Http.HttpPost]
public IHttpActionResult GetUserByID(int id)
{
var user = userList.FirstOrDefault((p) => p.Id == id);
if (user== null)
{
return NotFound();
}
return Ok(user);
}
but it always send 0 . but when i create a class and add that int as attribute it works fine.
Working code
[System.Web.Http.HttpPost]
public IHttpActionResult GetUserByID(data id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
return Ok();
}
public class data
{
[Required]
public int id { get; set; }
}
Edit
are my header accurate?
I think you need to add [FromBody] to the parameter:
[System.Web.Http.HttpPost]
public IHttpActionResult GetUserByID([FromBody]int id)
{
var user = userList.FirstOrDefault((p) => p.Id == id);
if (user== null)
{
return NotFound();
}
return Ok(user);
}
According to the docs: Parameter Binding in ASP.NET Web API
By default, Web API uses the following rules to bind parameters:
If the parameter is a "simple" type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from
a string.
For complex types, Web API tries to read the value from the message body, using a media-type formatter.
It goes on to say: Using [FromBody]
To force Web API to read a simple type from the request body, add the [FromBody] attribute to the parameter
UPDATES - to get [HttpPost] working...
As #Shahbaz suggested below, make sure that you've got the Content-Type header set to application/json, otherwise you will get error message saying:
The request entity's media type 'text/plain' is not supported for this resource.
Also, make sure you're posting just the id in the Request Body e.g. 1, as opposed to posting the id wrapped in a JSON object as a key/value pair { "id": "1" }.
FINALLY - consider using [HttpGet] instead...
It's worth pointing out, because you are now just sending a single int to get a single record, even if you can get this working using [HttpPost], it's still probably best to change it to [HttpGet] which is semantically correct - you are getting a user record, and don't actually need to post anything at all. So something like this might be better:
[System.Web.Http.HttpGet]
[Route("api/users/{id}")]
public IHttpActionResult GetUserByID(int id)
{
var user = userList.FirstOrDefault((p) => p.Id == id);
if (user== null)
{
return NotFound();
}
return Ok(user);
}
Then put your id in the request URL, something like:
https://yourdomain/api/users/1
The above example makes use of Attribute Routing which can help you create your own custom URLs to target your own API Action Methods.
Send Data to Web Api by a Jquery Like Below :
function PostSth(fid){
$.ajax({
url: apiBaseUrl + 'api/Controller/ActionMethod',
type: 'Post',
data:`'`+fid+`'`,
contentType: "application/json; charset=utf-8",
success: function (data) {
alert(data);
},
error: function () {
alert('Error');
}
});
}
Don't Forget
data:`'`+fid+`'`,
above.
and do in the Code Behind Part :
public string ActionMethod([FromBody]int fid)
{
string result = string.Empty;
//TODO: Your Code
return result;
}
I'm looking for the correct way to return JSON with a HTTP status code in my .NET Core Web API controller. I use to use it like this:
public IHttpActionResult GetResourceData()
{
return this.Content(HttpStatusCode.OK, new { response = "Hello"});
}
This was in a 4.6 MVC application but now with .NET Core I don't seem to have this IHttpActionResult I have ActionResult and using like this:
public ActionResult IsAuthenticated()
{
return Ok(Json("123"));
}
But the response from the server is weird, as in the image below:
I just want the Web API controller to return JSON with a HTTP status code like I did in Web API 2.
The most basic version responding with a JsonResult is:
// GET: api/authors
[HttpGet]
public JsonResult Get()
{
return Json(_authorRepository.List());
}
However, this isn't going to help with your issue because you can't explicitly deal with your own response code.
The way to get control over the status results, is you need to return a ActionResult which is where you can then take advantage of the StatusCodeResult type.
for example:
// GET: api/authors/search?namelike=foo
[HttpGet("Search")]
public IActionResult Search(string namelike)
{
var result = _authorRepository.GetByNameSubstring(namelike);
if (!result.Any())
{
return NotFound(namelike);
}
return Ok(result);
}
Note both of these above examples came from a great guide available from Microsoft Documentation: Formatting Response Data
Extra Stuff
The issue I come across quite often is that I wanted more granular control over my WebAPI rather than just go with the defaults configuration from the "New Project" template in VS.
Let's make sure you have some of the basics down...
Step 1: Configure your Service
In order to get your ASP.NET Core WebAPI to respond with a JSON Serialized Object along full control of the status code, you should start off by making sure that you have included the AddMvc() service in your ConfigureServices method usually found in Startup.cs.
It's important to note thatAddMvc() will automatically include the Input/Output Formatter for JSON along with responding to other request types.
If your project requires full control and you want to strictly define your services, such as how your WebAPI will behave to various request types including application/json and not respond to other request types (such as a standard browser request), you can define it manually with the following code:
public void ConfigureServices(IServiceCollection services)
{
// Build a customized MVC implementation, without using the default AddMvc(), instead use AddMvcCore().
// https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc/MvcServiceCollectionExtensions.cs
services
.AddMvcCore(options =>
{
options.RequireHttpsPermanent = true; // does not affect api requests
options.RespectBrowserAcceptHeader = true; // false by default
//options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
//remove these two below, but added so you know where to place them...
options.OutputFormatters.Add(new YourCustomOutputFormatter());
options.InputFormatters.Add(new YourCustomInputFormatter());
})
//.AddApiExplorer()
//.AddAuthorization()
.AddFormatterMappings()
//.AddCacheTagHelper()
//.AddDataAnnotations()
//.AddCors()
.AddJsonFormatters(); // JSON, or you can build your own custom one (above)
}
You will notice that I have also included a way for you to add your own custom Input/Output formatters, in the event you may want to respond to another serialization format (protobuf, thrift, etc).
The chunk of code above is mostly a duplicate of the AddMvc() method. However, we are implementing each "default" service on our own by defining each and every service instead of going with the pre-shipped one with the template. I have added the repository link in the code block, or you can check out AddMvc() from the GitHub repository..
Note that there are some guides that will try to solve this by "undoing" the defaults, rather than just not implementing it in the first place... If you factor in that we're now working with Open Source, this is redundant work, bad code and frankly an old habit that will disappear soon.
Step 2: Create a Controller
I'm going to show you a really straight-forward one just to get your question sorted.
public class FooController
{
[HttpPost]
public async Task<IActionResult> Create([FromBody] Object item)
{
if (item == null) return BadRequest();
var newItem = new Object(); // create the object to return
if (newItem != null) return Ok(newItem);
else return NotFound();
}
}
Step 3: Check your Content-Type and Accept
You need to make sure that your Content-Type and Accept headers in your request are set properly. In your case (JSON), you will want to set it up to be application/json.
If you want your WebAPI to respond as JSON as default, regardless of what the request header is specifying you can do that in a couple ways.
Way 1
As shown in the article I recommended earlier (Formatting Response Data) you could force a particular format at the Controller/Action level. I personally don't like this approach... but here it is for completeness:
Forcing a Particular Format If you would like to restrict the response formats for a specific action you can, you can apply the
[Produces] filter. The [Produces] filter specifies the response
formats for a specific action (or controller). Like most Filters, this
can be applied at the action, controller, or global scope.
[Produces("application/json")]
public class AuthorsController
The [Produces] filter will force all actions within the
AuthorsController to return JSON-formatted responses, even if other
formatters were configured for the application and the client provided
an Accept header requesting a different, available format.
Way 2
My preferred method is for the WebAPI to respond to all requests with the format requested. However, in the event that it doesn't accept the requested format, then fall-back to a default (ie. JSON)
First, you'll need to register that in your options (we need to rework the default behavior, as noted earlier)
options.RespectBrowserAcceptHeader = true; // false by default
Finally, by simply re-ordering the list of the formatters that were defined in the services builder, the web host will default to the formatter you position at the top of the list (ie position 0).
More information can be found in this .NET Web Development and Tools Blog entry
You have predefined methods for most common status codes.
Ok(result) returns 200 with response
CreatedAtRoute returns 201 + new resource URL
NotFound returns 404
BadRequest returns 400 etc.
See BaseController.cs and Controller.cs for a list of all methods.
But if you really insist you can use StatusCode to set a custom code, but you really shouldn't as it makes code less readable and you'll have to repeat code to set headers (like for CreatedAtRoute).
public ActionResult IsAuthenticated()
{
return StatusCode(200, "123");
}
With ASP.NET Core 2.0, the ideal way to return object from Web API (which is unified with MVC and uses same base class Controller) is
public IActionResult Get()
{
return new OkObjectResult(new Item { Id = 123, Name = "Hero" });
}
Notice that
It returns with 200 OK status code (it's an Ok type of ObjectResult)
It does content negotiation, i.e. it'll return based on Accept header in request. If Accept: application/xml is sent in request, it'll return as XML. If nothing is sent, JSON is default.
If it needs to send with specific status code, use ObjectResult or StatusCode instead. Both does the same thing, and supports content negotiation.
return new ObjectResult(new Item { Id = 123, Name = "Hero" }) { StatusCode = 200 };
return StatusCode( 200, new Item { Id = 123, Name = "Hero" });
or even more fine grained with ObjectResult:
Microsoft.AspNetCore.Mvc.Formatters.MediaTypeCollection myContentTypes = new Microsoft.AspNetCore.Mvc.Formatters.MediaTypeCollection { System.Net.Mime.MediaTypeNames.Application.Json };
String hardCodedJson = "{\"Id\":\"123\",\"DateOfRegistration\":\"2012-10-21T00:00:00+05:30\",\"Status\":0}";
return new ObjectResult(hardCodedJson) { StatusCode = 200, ContentTypes = myContentTypes };
If you specifically want to return as JSON, there are couple of ways
//GET http://example.com/api/test/asjson
[HttpGet("AsJson")]
public JsonResult GetAsJson()
{
return Json(new Item { Id = 123, Name = "Hero" });
}
//GET http://example.com/api/test/withproduces
[HttpGet("WithProduces")]
[Produces("application/json")]
public Item GetWithProduces()
{
return new Item { Id = 123, Name = "Hero" };
}
Notice that
Both enforces JSON in two different ways.
Both ignores content negotiation.
First method enforces JSON with specific serializer Json(object).
Second method does the same by using Produces() attribute (which is a ResultFilter) with contentType = application/json
Read more about them in the official docs. Learn about filters here.
The simple model class that is used in the samples
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
The easiest way I came up with is :
var result = new Item { Id = 123, Name = "Hero" };
return new JsonResult(result)
{
StatusCode = StatusCodes.Status201Created // Status code here
};
This is my easiest solution:
public IActionResult InfoTag()
{
return Ok(new {name = "Fabio", age = 42, gender = "M"});
}
or
public IActionResult InfoTag()
{
return Json(new {name = "Fabio", age = 42, gender = "M"});
}
Awesome answers I found here and I also tried this return statement see StatusCode(whatever code you wish) and it worked!!!
return Ok(new {
Token = new JwtSecurityTokenHandler().WriteToken(token),
Expiration = token.ValidTo,
username = user.FullName,
StatusCode = StatusCode(200)
});
Instead of using 404/201 status codes using enum
public async Task<IActionResult> Login(string email, string password)
{
if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password))
{
return StatusCode((int)HttpStatusCode.BadRequest, Json("email or password is null"));
}
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
{
return StatusCode((int)HttpStatusCode.BadRequest, Json("Invalid Login and/or password"));
}
var passwordSignInResult = await _signInManager.PasswordSignInAsync(user, password, isPersistent: true, lockoutOnFailure: false);
if (!passwordSignInResult.Succeeded)
{
return StatusCode((int)HttpStatusCode.BadRequest, Json("Invalid Login and/or password"));
}
return StatusCode((int)HttpStatusCode.OK, Json("Sucess !!!"));
}
Controller action return types in ASP.NET Core web API
02/03/2020
6 minutes to read
+2
By Scott Addie Link
Synchronous action
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById(int id)
{
if (!_repository.TryGetProduct(id, out var product))
{
return NotFound();
}
return product;
}
Asynchronous action
[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Product>> CreateAsync(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return BadRequest();
}
await _repository.AddProductAsync(product);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
Please refer below code, You can manage multiple status code with different type JSON
public async Task<HttpResponseMessage> GetAsync()
{
try
{
using (var entities = new DbEntities())
{
var resourceModelList = entities.Resources.Select(r=> new ResourceModel{Build Your Resource Model}).ToList();
if (resourceModelList.Count == 0)
{
return this.Request.CreateResponse<string>(HttpStatusCode.NotFound, "No resources found.");
}
return this.Request.CreateResponse<List<ResourceModel>>(HttpStatusCode.OK, resourceModelList, "application/json");
}
}
catch (Exception ex)
{
return this.Request.CreateResponse<string>(HttpStatusCode.InternalServerError, "Something went wrong.");
}
}
What I do in my Asp Net Core Api applications it is to create a class that extends from ObjectResult and provide many constructors to customize the content and the status code.
Then all my Controller actions use one of the costructors as appropiate.
You can take a look at my implementation at:
https://github.com/melardev/AspNetCoreApiPaginatedCrud
and
https://github.com/melardev/ApiAspCoreEcommerce
here is how the class looks like(go to my repo for full code):
public class StatusCodeAndDtoWrapper : ObjectResult
{
public StatusCodeAndDtoWrapper(AppResponse dto, int statusCode = 200) : base(dto)
{
StatusCode = statusCode;
}
private StatusCodeAndDtoWrapper(AppResponse dto, int statusCode, string message) : base(dto)
{
StatusCode = statusCode;
if (dto.FullMessages == null)
dto.FullMessages = new List<string>(1);
dto.FullMessages.Add(message);
}
private StatusCodeAndDtoWrapper(AppResponse dto, int statusCode, ICollection<string> messages) : base(dto)
{
StatusCode = statusCode;
dto.FullMessages = messages;
}
}
Notice the base(dto) you replace dto by your object and you should be good to go.
I got this to work. My big issue was my json was a string (in my database...and not a specific/known Type).
Ok, I finally got this to work.
////[Route("api/[controller]")]
////[ApiController]
////public class MyController: Microsoft.AspNetCore.Mvc.ControllerBase
////{
//// public IActionResult MyMethod(string myParam) {
string hardCodedJson = "{}";
int hardCodedStatusCode = 200;
Newtonsoft.Json.Linq.JObject job = Newtonsoft.Json.Linq.JObject.Parse(hardCodedJson);
/* "this" comes from your class being a subclass of Microsoft.AspNetCore.Mvc.ControllerBase */
Microsoft.AspNetCore.Mvc.ContentResult contRes = this.Content(job.ToString());
contRes.StatusCode = hardCodedStatusCode;
return contRes;
//// } ////end MyMethod
//// } ////end class
I happen to be on asp.net core 3.1
#region Assembly Microsoft.AspNetCore.Mvc.Core, Version=3.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
//C:\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\3.1.0\ref\netcoreapp3.1\Microsoft.AspNetCore.Mvc.Core.dll
I got the hint from here :: https://www.jianshu.com/p/7b3e92c42b61
The cleanest solution I have found is to set the following in my ConfigureServices method in Startup.cs (In my case I want the TZ info stripped. I always want to see the date time as the user saw it).
services.AddControllers()
.AddNewtonsoftJson(o =>
{
o.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Unspecified;
});
The DateTimeZoneHandling options are Utc, Unspecified, Local or RoundtripKind
I would still like to find a way to be able to request this on a per-call bases.
something like
static readonly JsonMediaTypeFormatter _jsonFormatter = new JsonMediaTypeFormatter();
_jsonFormatter.SerializerSettings = new JsonSerializerSettings()
{DateTimeZoneHandling = DateTimeZoneHandling.Unspecified};
return Ok("Hello World", _jsonFormatter );
I am converting from ASP.NET and there I used the following helper method
public static ActionResult<T> Ok<T>(T result, HttpContext context)
{
var responseMessage = context.GetHttpRequestMessage().CreateResponse(HttpStatusCode.OK, result, _jsonFormatter);
return new ResponseMessageResult(responseMessage);
}
AngularJS:
$http.defaults.headers.post["Content-Type"]= "application/x-www-form-urlencoded";
$http({
url: 'http://localhost:17438/api/people/PostPerson/',
method: "POST",
data: { name: vm.parent[i].name, dob: '01/15/2001', email: vm.parent[i].email, phone: vm.parent[i].cell, carrierName: vm.parent[i].carrier, personTypeID: 1 }
})
.then(function (response) {
// success
alert('sucess : ' + response);
},
function (response) { // optional
// failed
alert('failure : ' + response);
});
I've also tried this variation:
var data = { name: vm.parent[i].name, dob: '01/15/2001', email: vm.parent[i].email, phone: vm.parent[i].cell, carrierName: vm.parent[i].carrier, personTypeID: 1 };
$http.post('http://localhost:17438/api/people/PostPerson/', data);
Parameters being passed:
{"name":"jv","dob":"01/15/2001","email":"j#live.com","phone":"5551212","carrierName":"Sprint","personTypeID":1}:
webAPI:
[HttpPost]
[HttpOptions]
public string PostPerson(newUserRegistration newReg)
{
var json = JsonConvert.SerializeObject(0);
person myPerson = new person();
myPerson.personName = newReg.name;
myPerson.personEmail = newReg.email;
myPerson.personPhone = newReg.phone;
myPerson.personPhoneCarrier = newReg.carrierName;
myPerson.personDOB = newReg.dob;
myPerson.familyID = newReg.familyID;
myPerson.personTypeID = newReg.personTypeID;
db.people.Add(myPerson);
db.SaveChanges();
return "got here";
}
public class newUserRegistration
{
public string name { get; set; }
public string email { get; set; }
public string phone { get; set; }
public string carrierName { get; set; }
public DateTime dob { get; set; }
public string registrationID { get; set; }
public int familyID { get; set; }
public int personTypeID { get; set; }
}
Parameter population:
I know it is hard to read but you can see the values I'm passing in are NOT being passed into my newUserRegistration object
I've looked at several questions on Stack that seems to reference this type of issue.
Angular POST to Web API doesn't pass data
issue in Angularjs $http.post to webapi
This project is currently using 1.3.15 - I'm not sure if upgrading to 1.5 help?
What am I missing on this?
UPDATE:
There was a comment that is now gone, but I stringified the data as suggested:
var data = JSON.stringify({ name: vm.parent[i].name, dob: '01/15/2001', email: vm.parent[i].email, phone: vm.parent[i].cell, carrierName: vm.parent[i].carrier, personTypeID: 1 });
$http.post('http://localhost:17438/api/people/PostPerson/', data);
I noticed something strange though. It is calling the API method 2 times, the 1st time has null data (as witnessed originally), but it calls it a 2nd time and the data is there!
I'm not sure why it is being called twice though? Is there anything I'm doing incorrectly now that I'm stringifying the data?
Update to double call:
I noticed the following:
You will notice one says OPTIONS and the other says POST. Now the webAPI also has the following tags:
[HttpPost]
[HttpOptions]
If I removed the Options, it fails (can't find 404). Do these tags have something to do with this?
Use JSON.stringify() to wrap your json
var url = 'http://localhost:17438/api/people/PostPerson/';
var data = JSON.stringify({ name: vm.parent[i].name, dob: '01/15/2001', email: vm.parent[i].email, phone: vm.parent[i].cell, carrierName: vm.parent[i].carrier, personTypeID: 1 });
$http.post(url, data);
As you're finding out, this is a web server issue more than an Angular one.
If your angular app is delivered on the same server:port as your service endpoints, try using a relative hyperlink and see if the OPTIONS request disappears. The presence of the domain name in a XmlHttpRequest for the application/json content-type is usually enough to trigger the CORS check.
I will say that I've seen this much more frequently when connecting to IIS, but it's not exclusive. A lot depends on the underlying server config. The OPTIONS request is like the handshake for SSL: the angular request is trying to figure out what the system will allow, then sending the payload once permissions are granted.
MDN - Access Control with CORS
Remove this:
$http.defaults.headers.post["Content-Type"]= "application/x-www-form-urlencoded";
You are telling the api server you are going to send it a form encoded body and you are instead sending it a JSON body and so when the api server goes to parse the body of the request it is null.
NOTE: If you are using Asp.Net Web Api's built in OAuth provider then you will need to post to the /token method using the application/x-www-form-urlencoded data type but for all other calls you can use JSON.
As for the duplicate requests that is caused by your browser making a CORS check. That is perfectly normal if your API hostname is different from you angular hostname.
I have created POST/GET request in MVC before.
In my HomeController
[HttpPost]
public string Index(int Value)
{
return Value.ToString();
}
And setting chrome extension POSTMAN with a form-data
I can call http://localhost/mvcApp/ with a variable 'Value' with value '1' and get a string '1' in return
But when I create a surveyController : ApiController doesn't work when I call http://localhost/mvcApp/api/survey/
public string Post(int Value)
{
return Value.ToString();
}
"Message": "No HTTP resource was found that matches the request URI 'http://localhost/mvcApp/api/survey/'.",
"MessageDetail": "No action was found on the controller 'survey' that matches the request."
I'm not sure if the error is in the way the api is created, or in the way the POSTMAN is trying to call the api. Because that '.'
Also try in my HomeControler Index
client.BaseAddress = new Uri("http://localhost/mvcApp");
var result = client.PostAsync("/api/survey", new
{
Value = 1
}, new JsonMediaTypeFormatter()).Result;
if (result.IsSuccessStatusCode) // here return Not found
The WebApi controllers' conventions are not the same as those of plain ol' MVC controllers.
Basically the problem is that you can't specify the int parameter the way you did.
Try this in you WebApi controller:
// nested helper class
public class PostParams {
public int Value { get; set; }
}
public string Post(PostParams parameters) {
return parameters.Value.ToString();
}
and see how that works.
Here's a thorough article on passing parameters within POST requests to WebAPI controllers:
Passing-multiple-POST-parameters-to-Web-API-Controller-Methods
Long story short, these are the conventions, roughly speaking:
you can't capture POST form name-value pairs in parameters
you can capture them inside the properties of a class if that class is the parameter type of one of your method's parameters
you can capture query parameters in method parameters
EDIT
If you wish to test your WebAPI server using C# you could follow these steps:
Create a nice Console Application (preferably within the same solution)
Add the Web API Client NuGet package to this Console Application
Make your Program.cs do something like this.
The following code uses the C# 5.0 async and await operators.
It also uses the Task class and anonymous types.
I've pointed out official MSDN articles (click on the links) should you be interested in what those things are.
using System.Net.Http;
using System.Threading.Tasks;
namespace ConsoleApplication1 {
class Program {
public static void Main(string[] args) {
Test().Wait();
}
private static async Task Test() {
HttpClient client = new HttpClient();
await client.PostAsJsonAsync(
"http://localhost/mvcApp/api/survey/",
new {
value = 10
}
);
}
}
}
This wasnt easy. After lot of reading I solve it like this.
First the api controler need to define the input parameter with the [FromBody] attribute
// POST api/survey
public void Post([FromBody]string value)
{
}
For testing I put a button in the view and use an Ajax / Post, the variable name need to be an empty string before the variable value.
$(document).ready(
$('#post').click(function () {
var url = 'http://localhost/mvcApi/api/survey';
var data = { "": 'Hola' }; // Define a simple variable this way
$.ajax({
type: "POST",
url: url,
data: data,
success: sucess
}
});
})
Or if you want send mutliple values
data = { "": ["update one", "update two", "update three"] };
But if you want receive an object
public void Post(Survey data)
{
string value = data.Value.ToString();
}
$('#post').click(function () {
....
var data = { value: 25 }
More info here Sending Data and here Binding