404 Not Found when accessing a Web API method - asp.net

I need this method to return an integer value:
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpPost("ByPayment")]
public int Payment(string accountId, string mount, string shenase)
{
return 21;
}
}
When I go to the following address:
http://localhost:1070/api/values/Payment/ByPayment?accountId=258965&mount=85694&shenase=85456
I get the following error:
What's the problem? And how can I solve it?

I thing you wanted to send Get request with query string parameters.
1. Change the 'HttpPost' to 'HttpGet'
[HttpPost("ByPayment")] to [HttpGet("ByPayment")]
2. Also change your request url, Its not correct.
http://localhost:1070/api/values/Payment/ByPayment?accountId=258965&mount=85694&shenase=85456
to
http://localhost:1070/api/Values/ByPayment?accountId=258965&mount=85694&shenase=85456
Updated code
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet("ByPayment")]
public int Payment(string accountId, string mount, string shenase)
{
return 21;
}
}
I suggest please read this tutorial to understand the basic of webapi.

There could be more reasons why you get the 404. But there is one thing that's definitely wrong - you are sending GET requests to a method that's marked with [HttpPost("ByPayment")] (which means it only responds to POST requests.
I don't know what you intended to do but you either have to change it to [HttpGet("ByPayment")] or use a REST client that can make POST requests (e.g. REST Easy.
Other reason could be that your controller has a wrong name. It should be called PaymentController.

Related

OData + Swagger. URL generation

In my Net 6 Web-API project I'm using OData and Swagger (it was added automatically when project was created).
It works out of the box, but there is an issue with some URLs generated by Swagger.
Here is my OData controller:
public class UsersController : ODataController
{
// skipped for brevity
[EnableQuery]
public IActionResult Get()
{
return Ok(_dbContextRepo.Select<DbModel.User>());
}
[EnableQuery]
public SingleResult<User> Get([FromODataUri] int key)
{
return SingleResult.Create(_dbContextRepo.Select<User>().Where(u => u.Id == key));
}
}
SwaggerUI output:
When I try to run query that gets entity by Id from Swagger it fails because of wrong url.
By some reason Swagger generates query parameter and URL like on picture above. For OData URL has to be like this (path parameter, https://swagger.io/docs/specification/describing-parameters/):
https://localhost:7250/api/Users/1
In swagger.json parameter described as
Spent all day trying to figure this out. Will appreciate any help.
Found solution myself. I'm using OData 8 and it seems there is no need to mark method parameter as [FromODataUri].
[EnableQuery]
public SingleResult<User> Get(int key)
{
//...
}
Whithout it Swagger generates correct links.

ASP.NET Core 2.1 CreatedAtRoute Returns no Response

I was searching around but I couldn't find a working answer for my issue. I saw a similar question but we had different results. My issue is I have 2 controllers. The first controller has a POST action that I want to return a CreatedAtRoute to a GET action inside a different controller. I tested the GET action in Postman and it works so my only issue is getting the CreatedAtRoute to work.
My first controller:
[HttpPost]
public async Task<IActionResult> Submit(AssessmentAttemptVM attempt)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
//Do database related stuff
await _context.SaveChangesAsync();
return CreatedAtRoute("GetAssessmentResult", new { id = studentAttempt.Id }, studentAttempt);
}
My second controller:
[HttpGet("{id}", Name = "GetAssessmentResult")]
public async Task<ActionResult<AssessmentResultVM>> GetById(int id)
{
//Get my ViewModel -- This works if I try to access it without using the CreatedAtRoute method
return resultVM;
}
The picture below shows what Postman responds with when I try to Post. I verified that the data gets added to the database so only the CreatedAtRoute method is the only I can think of that isn't making this work for me..
EDIT
Controller Route Attributes:
[ApiController]
[Route("api/view/assessmentresult/")]
public class AssessmentResultsController: ControllerBase
{
[ApiController]
[Route("api/take/assessment")]
public class StudentAssessmentController : ControllerBase
{
I found the cause. The last parameter for CreatedAtRoute and CreatedAtAction required an object similar to the destination controller. It went over my head because I was sending models prior to what I did now which used a ViewModel.
Well That wasn't the main reason I couldn't get a response though. It was because of an execption where the object I'm passing ended up having recursive references because I was sending a model that wasn't properly formatted to be sent over as JSON.
I used this to make it work, taken from the MS Docs site:
CreatedAtAction(String, String, Object, Object) Where the last parameter should be the object you want to the api to send over.
PS: I also didn't notice immediately because when I debugged the project, it didn't crash and had to read the logs. I'm a noob so I really didn't know that it's possible for an exception to occur without the project crashing in debug mode.

Get url from java class

I have this singleton class which will start when the application starts and the method invokes itself for every 30 seconds.
#Singleton
#Startup
public class myClass{
#Schedule(second="*/30", minute="*", hour="*")
public void serviceRequest(){
String url = "";
//send request
}
}
the url will be something like http://localhost:7001/webapp/rest/tasks/mytask. I don't want to hardcode the url. Instead, I want to somehow get that from the system (or somewhere). I've tried injecting resource like HttpServletRequest but that didn't work.
Thanks in advance.
In case you're using JAX-RS, then this will work:
#RequestScoped #Path("tasks")
public class TaskResource {
#GET #Path("{id}")
public Response getTask(#PathParam("id") String id) {
/* whatever */
}
}
URI uri = UriBuilder.fromResource(TaskResource.class)
.segment("{id}").build("mytask");
The url will be provided by an external service so I dont need to worry about host and port number since ill get full url to that rest service. Because the service isn't available so I made an in house rest service to test my functionality. I guess I will harcode the url for now.

consuming web api method manually in url

This is the most dumb question you might come across regarding Web Api but being a newbie i am struggling to find an answer to this simple question.
In the codebelow if i can easily call the one that returns "number" but the other one with the Add method i just cant find the right way to call it as everytime i try i get the 404 error
Could anyone please tell me how can i call that method "Add" with appropriate parameter?
namespace WebAPIServices.Controllers
{
public class ValuesController : ApiController
{
// GET api/values
public string Get()
{
return "number";
}
//how can i call this one?
public int Add(int num1,int num2)
{
return num1+num2;
}
}
}
You should be able to call it at http"//<hostname>/api/values/add?num1=1&num2=2
And you need to add the [HttpGet] attribute because otherwise it defaults to [HttpPost]... You may need to add a route as well.
//how can i call this one?
[HttpGet]
[Route("api/values/add")]
public int Add(int num1, int num2)
{
return num1 + num2;
}
If you are using Web API 2 , you can use Attribute Routing (Web Api 2 Attribute Routing
as follows:
and then invoke it from the browser or a console app :
http:///api/values/add?num1=11&num2=12
Thanks

How can I MapHttpRoute a POST to a custom action using the WebApi?

I'm trying to figure out the madness behind the Web API routing.
When I try to post data like this:
curl -v -d "test" http://localhost:8088/services/SendData
I get a 404, and the following error message:
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost:8088/services/SendData'.","MessageDetail":"No action was found on the controller 'Test' that matches the request."}
Here is the code for my test server.
public class TestController : ApiController
{
[HttpPost]
public void SendData(string data)
{
Console.WriteLine(data);
}
}
class Program
{
static void Main(string[] args)
{
var config = new HttpSelfHostConfiguration("http://localhost:8088");
config.Routes.MapHttpRoute(
name: "API Default",
routeTemplate:"services/SendData",
defaults: new { controller = "Test", action = "SendData"},
constraints: null);
using (var server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}
}
More generally, why has the ASP.NET team decided to make the MapHttpRoute method so confusing. Why does it take two anonymous objects....how is anyone supposed to know what properties these objects actually need?
MSDN gives no help: http://msdn.microsoft.com/en-us/library/hh835483(v=vs.108).aspx
All the pain of a dynamically typed language without any of the benefit if you ask me...
Agree with you, it's a hell of a madness, you need to specify that the data parameter should be bound from the POST payload, since the Web API automatically assumes that it should be part of the query string (because it is a simple type):
public void SendData([FromBody] string data)
And to make the madness even worse you need to prepend the POST payload with = (yeah, that's not a typo, it's the equal sign):
curl -v -d "=test" http://localhost:8088/services/SendData
You could read more about the madness in this article.
Or stop the madness and try ServiceStack.
Use this signature and it will work every time.
public class TestController : ApiController
{
[HttpPost]
[ActionName("SendData")]
public HttpResponseMessage SendData(HttpRequestMessage request)
{
var data = request.Content.ReadAsStringAsync().Result;
Console.WriteLine(data);
}
}
Try with the following change,
public class TestController : ApiController
{
[HttpPost]
[ActionName("SendData")]
public void SendData(string data)
{
Console.WriteLine(data);
}
}
The ActionName attribute might fix the issue. Otherwise, you can also the name convention "Post"
public void Post(string data)
{
Console.WriteLine(data);
}
And send an Http Post directly to "services" without SendData.

Resources