nohttp resource was found that matches the request uri - asp.net-web-api

I'm trying to develop an api that allows both get and post requests at the same address.
public class DataController : ApiController
{
[HttpGet]
public DataResponse Foo()
{
return GetNext();
}
[HttpPost]
public void Foo(long p1, string p2)
{
SaveValue(p1,p2);
}
}
GET works fine. When calling the POST method, I get the following error:
the requested resource does not support http method 'POST'
My WebApiConfig looks like the following:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.EnableCors();
config.MapHttpAttributeRoutes();
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{action}");
}
}
Any idea what I need to change to get this working?

You can do this in two ways-
1- Change the way you are calling API i.e - pass values in url like <url>?p1=value&p2=value
2- Change the signature of the Action in Web API to
public void Foo([FromBody] MyContract data)
where MyContract is a class with two properties
public class MyContract
{
public long p1 { get; set; }
public string p2 { get; set; }
}
This is because by default parameter binding is done through URL and you are passing them through body.

Related

How do I route to a method in ASP.NET Web API?

According to the documentation, if I have this in my WebApiConfig.cs:
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I should be able to route to a method in my API controller using a URL like this:
http://localhost:55601/api/Customers/Search
Here is my method:
[ResponseType(typeof(int))]
[HttpPost]
public IHttpActionResult Search([FromBody]CustomerDTO SearchTerm)
{
string Name = SearchTerm.Name;
string Email = SearchTerm.Email;
string PhoneNumber = SearchTerm.Phone;
var customer = db.Customers.Single(c => c.Name == Name && c.EmailAddress == Email && c.PhoneNumber == PhoneNumber);
return Ok(customer.id);
}
I'm sending the search data as a JSON object (using HTTP POST method) in the request body.
However, I get an error saying:
Multiple actions were found that match the request
I only have one method in this controller called Search.
I would have thought this should be pretty straightforward, and work the same way it does with MVC controllers. But I think I'm missing something obvious. Can anyone tell me what it is?
EDIT: As per #KevinLaw's request, adding code for controller showing upblic methods. Also, for further information the following request (HTTP GET) works as expected:
http://localhost:55601/api/Customers?email=[recipient#domain]
public class CustomersController : ApiController
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: api/Customers
public IQueryable<Customer> GetCustomers()
{
//...
}
// GET: api/Customers/5
[ResponseType(typeof(Customer))]
public IHttpActionResult GetCustomer(int id)
{
//...
}
// GET: api/Customers/5
[ResponseType(typeof(Customer))]
public IHttpActionResult GetCustomerByEmail(string email)
{
//...
}
// PUT: api/Customers/5
[ResponseType(typeof(void))]
public IHttpActionResult PutCustomer(int id, Customer customer)
{
//...
}
// POST: api/Customers
[ResponseType(typeof(Customer))]
public IHttpActionResult PostCustomer(Customer customer)
{
//...
}
[ResponseType(typeof(int))]
[HttpPost]
public IHttpActionResult SearchCustomer([FromBody]CustomerDTO SearchTerm)
{
//...
}
// DELETE: api/Customers/5
[ResponseType(typeof(Customer))]
public IHttpActionResult DeleteCustomer(int id)
{
//...
}
}
The problem here is that the WebApiController uses the REST API specs.
Which state that in a Web Api Controller there can be Zero - One Http Verb.
What i mean by that is that you can have one GET,PUT,POST,DELETE,PATCH
The reason you don't have any problem with the GET is because you have them correctly overloaded. () (int) (string).
But your Posts is (Customer) (CustomerDTO) They are both complex objects and the Binder cannot identify which is which when binding to the complex object.
For this to work you need to use Route Attributes or explicit route.
Attribute Routing
Explicit Routing pt1
Explicit Routing pt2
I think the links are enough to get you started.
If you still want to see some code on your specific case leave a comment below and i will give you some examples.
Thanks
EDIT: Added Examples
Attribute Routing
On WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
}
On Controller
[RoutePrefix("api/test")]
public class TestingController : ApiController
{
[HttpGet]
[Route("")]
public IEnumerable<string> Get()
{
return new[] { "value1", "value2" };
}
[HttpPost]
[Route("search")]
public IHttpActionResult Post([FromBody]SearchCriteria criteria)
{
return Ok(criteria);
}
}
public class SearchCriteria
{
public string Name { get; set; }
}
Explicit Routing
On WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes config.Routes.MapHttpRoute(
name: "SearchTest",
routeTemplate: "api/test/search",
defaults: new { controller = "Testing", action = "Search" }
);
config.Routes.MapHttpRoute(
name: "TestingController",
routeTemplate: "api/test/{id}",
defaults: new { controller = "Testing", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
On Controller
public class TestingController : ApiController
{
[HttpGet]
public IEnumerable<string> Get()
{
return new[] { "value1", "value2" };
}
[HttpPost]
public IHttpActionResult Search([FromBody]SearchCriteria criteria)
{
return Ok(criteria);
}
}
public class SearchCriteria
{
public string Name { get; set; }
}

Post data through Url to webapi

Hej,
I am unable to post data to the action method through querystring to the action method which is located in the controller class below is my code.
I type a url "http://localhost:53459/api/esb/post/test" to post value and nothing happens
Any help would be appreciated.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{value}",
defaults: new { value = RouteParameter.Optional }
);
}
}
[RoutePrefix("api/esb")]
public class EsbController : ApiController
{
[Route("get")]
[HttpGet]
public string Get()
{
return "Hello there!";
}
[Route("post")]
[HttpPost]
[AcceptVerbs("POST")]
public string Post([FromUri]string value)
{
return string.Format("{0} is posted successfully ", value);
}
[Route("put")]
[HttpPut]
public string Put([FromUri] string value)
{
return string.Format("{0} is updated successfully ", value);
}
[Route("delete")]
[HttpDelete]
public string Delete(string value)
{
return string.Format("{0} is deleted successfully ", value);
}
}
If you are typing the url into a browser you are constructing a GET request so it will never reach your Post action. You can confirm this by adding "GET" to the allowed verbs on the action (note: remove the [HttpPost] attribute).
[Route("post")]
[AcceptVerbs("POST", "GET")]
public string Post([FromUri]string value)
{
return string.Format("{0} is posted successfully ", value);
}
remove parameter binding [FromUri] and update the Route like
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{value}",
defaults: new { value = RouteParameter.Optional }
);
}
}
Controller
[RoutePrefix("api/esb")]
public class EsbController : ApiController
{
[Route("get")]
[HttpGet]
public string Get()
{
return "Hello there!";
}
[Route("post/{value}")]
[HttpPost]
[AcceptVerbs("POST")]
public string Post(string value)
{
return string.Format("{0} is posted successfully ", value);
}
}
This is working for me, try to use Postman in chrome or fiddler.
POST http://localhost:XXXXX/api/esb/post/test HTTP/1.1
For dot.Net Core (I'm using v2.0), use FromRoute
[AllowAnonymous]
[HttpPost]
[Route("validateEmail/{validationCode}")]
public async Task<IActionResult> ValidateEmail(
[FromRoute] Guid validationCode)
{
await authService.ValidateEmailAsync(validationCode);
return Ok();
}
Then post like this:

ASP.NET Core WebAPI 404 error

I create a Web Api in asp.net core this the content of Api:
[Route("api/[controller]")]
public class BlogController : Controller
{
public IContext _context { get; set; }
public BlogController(IContext ctx)
{
_context = ctx;
}
[HttpGet]
[Route("api/Blog/GetAllBlog")]
public List<Blog> GetAllBlog()
{
return _context.Blogs.ToList();
}
}
as i know in ASp.net Core (WebApi Template) we don't need any configuration like registration Route, which we need in Asp.net Mvc 5.3 and older.
So when i try to call the GetAllBlog by browser or Postman, by this url http://localhost:14742/api/Blog/GetAllBlog , it gets me 404 error, what is problem?
You have already included the api/[controller] route at the top of the controller class so you don't need to include it again while defining route for accessing method.
In essence, change the Route to api/Blog/GetAllBlog to GetAllBlog. Your code should look like this:
[Route("api/[controller]")]
public class BlogController : Controller
{
public IContext _context { get; set; }
public BlogController(IContext ctx)
{
_context = ctx;
}
[HttpGet]
[Route("GetAllBlog")]
public List<Blog> GetAllBlog()
{
return _context.Blogs.ToList();
}
[HttpGet]
[Route("GetOldBlogs")]
public List<Blog> GetOldBlogs()
{
return _context.Blogs.Where(x => x.CreationDate <= DateTime.Now.AddYears(-2)).ToList();
}
}
You also need to have different route names for methods.
Hope this helps.

Two GET in MVC C#

public class EmployeesController : ApiController
{
public IEnumerable<Employee> GetAllEmployees()
{
return (new EmployeeData()).GetEmployeeRecords();
}
public Employee GetSingleEmployee(int id)
{
return (new EmployeeData()).GetSingleEmployeeRecord(id);
}
public void Delete(int id)
{
(new EmployeeData()).DeleteEmployeeRecord(id);
}
}
This is what I have now. I'm trying to make the app call the first function with a get call api/employee and the second one with a get call api/employee/(an ID number) eg api/employee/75. The get call always goes to the first one. How do I solve this?
This is my routing:
namespace EmployeeApp
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id=UrlParameter.Optional }
);
}
}
}
After a brief discussion in chat, we discovered that the issue here is that you have two different route configuration files, one for MVC and one for WebAPI. While you could change the name of your actions to match the convention of the WebAPI route configuration (i.e. change GetSingleEmployee to GetEmployeeById), there is another way which would allow you to keep the actions named the same, and have more control over your desired routes. My recommendation is to use the newer Attribute Routing syntax.
First, change your configuration class like so:
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
// Other Web API configuration not shown.
}
next, change your class signature to define the routes through attributes:
[RoutePrefix("api/employee")]
public class EmployeesController : ApiController
{
// http://example.com/api/employee/
[Route("")]
public IEnumerable<Employee> GetAllEmployees()
{
return (new EmployeeData()).GetEmployeeRecords();
}
// http://example.com/api/employee/75
[Route("{id:int}"]
public Employee GetSingleEmployee(int id)
{
return (new EmployeeData()).GetSingleEmployeeRecord(id);
}
// http://example.com/api/employee/Delete/75
[Route("Delete/{id:int}")]
public void Delete(int id)
{
(new EmployeeData()).DeleteEmployeeRecord(id);
}
}
This controller now clearly shows it's routes, rather than the routes being defined somewhere else, or being defined by an obscure name matching convention.

How to ensure ASP.net Web API controller's parameter is not null?

I created a ASP.net Web API controller like that:
public class UsersController : ApiController
{
//...
public void Put([FromBody]User_API user, long UpdateTicks)
{
user.UpdateTicks = UpdateTicks;
//...
}
}
The "user" parameter will be null if the client does not provide correct arguments. Can I make a global filter to check every parameter like this, and will return a 400 message if any error occurs.
Finally, I got the solution:
public class ModelValidateFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ActionArguments.Any(v => v.Value==null))
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
}
And...
//In Application_Start()
GlobalConfiguration.Configuration.Filters.Add(new ModelValidateFilterAttribute());

Resources