I'm setting up an ASP.net web API, but i keep getting 404 from all Http routes.
This is running on http://localhost:52011/ since that is the default location that VS2013 uses. I've added a simple test HttpRoute that just returns a string if it's called with a GET to test connectivity.
Directory browsing is enabled for feedback that the web API is in fact on localhost, and all directories of the project are visible.
I've tried setting the controller name fixed in the routes in WebApiConfig.cs and read a lot about the HttpRoute mappings, but i keep getting either a 404 or a "No Type was found that matches the controller named controllername".
I'm using Postman to test since that was recommended and easy to use.
Any tips are welcome!
WebApiConfig.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace BadgePrinter
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
//route to print badge.
config.Routes.MapHttpRoute(
name: "apiPrint",
routeTemplate: "api/{controller}/{action}/{Bedrijf}/{Aanspreektitel}/{Voornaam}/{Achternaam}/{Jobtitle}/{Kopies}/{Rijksregisternummer}/{BadgeAfdruk}/{printer}/{Image}",
defaults: new { Image = RouteParameter.Optional}
);
//test route to get string back
config.Routes.MapHttpRoute(
name: "apiTest",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
BadgeController.cs(the only controller in the project)
The first method is the one i'm going to have to use eventually, but the testmethod is the one i use for testing.
using BadgePrinter.CardTemplates;
using BadgePrinter.Interfaces;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
namespace BadgePrinter.Controllers
{
public class BadgeController : ApiController
{
//removed the first method since it was big and distracting.
// test method
[HttpGet]
public IHttpActionResult GetAllProducts()
{
return Ok("some product");
}
}
}
link for the testmethod that i'm using:
http://localhost:52011/api/BadgeController/Products/1
I also tried this link, even though that shouldn't matter:
http://localhost:52011/api/BadgeController/Products/1
Result:
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:52011/api/BadgeController/Products/1'.",
"MessageDetail": "No type was found that matches the controller named 'BadgeController.cs'."
}
For the other HttpRoute, i keep getting 404, but i'll be in heaven if i can get the test to work :)
PS: i'm new to this kind of thing(ASP.net and API's) so i'm sorry if i'm being an idiot.
You have 2 issues here:
1) Your controller name BadgeController but in your API it should be Badge only. The correct URL should be:
http://localhost:52011/api/Badge/xxx
2) I can't see method name Products or something like that in your code.
3) If it is a POST method, it must have [FromBody] in parameter input.
There are some problems with your URL:
http://localhost:52011/api/BadgeController/Products/1
As far as I can see you don't have any GET method which would map to an ID parameter. All you have in your controller is
[HttpGet]
public IHttpActionResult GetAllProducts()
which doesn't accept any inputs.
2) The documented Web API convention is that you don't write "Controller" explicitly in the URL. Just the first part which is unique to the controller (Badge) in this case is required.
3) I can't see where you are getting the "Products" part of the URL from. There's no custom route definition or attribute which would make that part of the route. Again the convention is that you define an action method whose name starts with "Get" and that will map to a GET request to the controller name, with no further bits and pieces on the end. The rest of the method's name is irrelevant - and in your case AllProducts doesn't match to /Products anyway...so even if that was necessary it would still be incorrect.
In conclusion, the correct URL to access your GET action should be:
http://localhost:52011/api/Badge/
N.B. If you were to either change your existing GetAllProducts method, or add a second method like this:
[HttpGet]
public IHttpActionResult Get(int id)
{
return Ok("Product" + id);
}
Then you could use the ID in your URL, e.g.
http://localhost:52011/api/Badge/1
and it should route to this method.
Try dropping the controller part of the url:
http://localhost:52011/api/Badge/Products/1
Related
I am trying to refactor an old setup, the end goal will be that I will have a functional REST API. I am getting rid of an old NuGet service and I sort of have to rebuild everything now. I am trying to set it up using ASP.NET Web API. This will include 60+ routes (like "www.website.com/cars/{id}/engine" "www.website.com/inventory/{id}" etc..)
I have tried attribute routing and conventional routing, and nothing seems to work. I get 404's no matter what I seem to try. I am probably just not doing either of them correctly.
Here is how I am setting up configuration (I am using a self hosting package btw but this is the main configuration point):
public class SomeHostClass
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
//If I am trying attribute based routing, uncomment this
//config.MapHttpAttributeRoutes();
Register(config.Routes);
// I think I need this at all times?
app.UseWebApi(config);
}
public void Register(HttpRouteCollection routes)
{
// One of many other routes.MapHttpRoute() calls
routes.MapHttpRoute(
name: "Cars",
routeTemplate: "cars/{id}/engine",
defaults: new
{
controller = "CarController",
action = "Get"
},
constraints: null);
}
}
Then here is my Car Controller:
public class CarController : ApiController
{
[HttpGet]
public object Get([FromUri] CarDTO carObject)
{
// Some code calling a private worker method
return WorkerMethod();
}
private object WorkerMethod()
{
// Worker method do stuff, return
}
}
This Get() method is never called and a 404 is returned.
Another note: I have tried using reflection to register all the routes, which slims down the code. I'll debug it and it looks like all the routes have been configured correctly within the HttpConfiguration.routes but I will get 404's still. Even without reflection doing it the way shown above- if I debug and look at the values they all seem correct, but don't work.
Another Note: I should also mention that this is the error I usually get along with the 404.
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost:8000/cars/1/engine'.","MessageDetail":"No type was found that matches the controller named 'CarController'."}
How do I get these routes recognized and stop returning 404's and start returning my data?
If this is a bad way of going about this- what's the best way?
I have a case where I can't get a default route to work via Config.Routes.MapHttpRoute(), but if I put the route as a route attribute in the controller it works fine.
Global.asax
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
//RouteConfig.RegisterRoutes(RouteTable.Routes);
//BundleConfig.RegisterBundles(BundleTable.Bundles);
}
(removed last two as they're non-WebAPI requirements (right?) same result even if I leave them in)
WebApiConfig.cs
public static void Register(HttpConfiguration config) {
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "v1/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Controller
public class ErrorsController : ApiController
{
[HttpGet]
[Route("v1/Errors/Get")]
public IHttpActionResult Get(int id) {
return Ok();
}
[HttpPost]
[Route("v1/Errors/Submit")]
public IHttpActionResult Submit()
{
// do stuff
return Ok();
}
}
If I have the attribute routes in there, everything works fine. If I don't, I get 404s. For example, the following two report a 404 error:
localhost:myport/v1/Errors/Get?id=5
localhost:myport/v1/Errors/Submit
Yet, if I submit this:
localhost:myport/v1/Errors
I get the following response:
No HTTP resource was found that matches the request URI
'http://localhost:59498/v1/Errors/'.
No type was found that matches the controller named 'v1'.
Obviously my route configuration isn't kicking in, but for the life of my I can't tell why. I even tried changing the route name to Default instead of DefaultApi, thinking that perhaps Default had some internal significance.
"Normal" routing doesn't support this kind of routes with prefix "v1" in it. In a way or another this kind of rounting follows the old MVC routing, where the first part of the address must be the controller; so when you set the address localhost:myport/v1/Errors the system is currently looking for a controller named "v1".
If you want to use a route with a prefix before you have to stick with the attribute routing; that's why it works perfectly with attributes and it doesn't without.
May I suggest you to use a "global" prefix for the v1 thing? That would allow you to avoid repeating the same part of the URL over and over again on different resources. I suggest you to check this article for a couple of implementation details.
I am coding a web api in c# and I have a question in regards to the correct route to access a function called test.
Here is the class definition:
[RoutePrefix("api")]
public class ItemsWebApiController : ApiController
I have a RoutePrefix as follows:
[Route("test")]
Here is the function called test:
[Route("test")]
[System.Web.Http.AcceptVerbs("GET")]
[System.Web.Http.HttpGet]
public String test()
{
return "test";
}
I am trying to access the following url:
http://localhost/api/test
The above url is displaying the following exception:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its
dependencies) could have been removed, had its name changed, or is
temporarily unavailable. Please review the following URL and make
sure that it is spelled correctly.
Requested URL: /api/test
How can I access the test function, such that the string "test" is displayed in my browser?
EDIT
I have deployed to my local IIS, and the database connection strings are working correctly.
The address for the local IIS is http://localhost/
These are the urls that I have tried:
http://localhost/test
http://localhost/api/test
http://localhost/api/test/test
http://localhost/ItemsWebApiController/test
http://localhost/ItemsWebApi/test
All of the above return the error page.
Thanks
If you a putting [Route("test")] your url will be http://address/test
if you need url like http://address/api/test, change your route like [Route("api/test")]
Note: you need to add [HttpGet] as well
You have to activate Attribute Routing in WebAPI Controllers
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
and in your application start
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
And then your URL is http://localhost/test, because the default route would not match here.
The route based on your configuration will be: http://address/api/test/test
the first test is the route prefix from the attribute [Route("test")];
the scond test is the action in the controller from the attribute defined on the method
[Route("test")]
public String test()
{
Web api infers the http method based on your action name. It won't know from "Test" what to use.
See the docs
HTTP Methods
Web API also selects actions based on the HTTP method of the request (GET, POST, etc). By default, Web API looks for a case-insensitive match with the start of the controller method name. For example, a controller method named PutCustomers matches an HTTP PUT request.
You can override this convention by decorating the mathod with any the following attributes:
[HttpDelete]
[HttpGet]
[HttpHead]
[HttpOptions]
[HttpPatch]
[HttpPost]
[HttpPut]
The following example maps the CreateBook method to HTTP POST requests.
[Route("api/books")]
[HttpPost]
public HttpResponseMessage CreateBook(Book book) { ... }
I cannot get MVC 5 Attribute Routing to work for the Controller. I'm getting a 404 and I'm really not sure what I am missing. I have looked up a heap of examples online and as far as I can see I have followed them 100%
I would like a controller called 'CustomerServicePolicyController' to work against the route http://[site]/customer-service-policy/.
I'm using MVC 5. Here's what I have done:
Opened up RouteConfig.cs
Modified it to the following:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//enabling attribute routing
routes.MapMvcAttributeRoutes();
//convention-based routing
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "TTTA.Controllers" }
);
}
Created a Controller called CustomerServicePolicyController.cs
Ensured it was as below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace TTTA.Controllers
{
[RoutePrefix("customer-service-policy")]
[Route("{action=index}")] //default action
public class CustomerServicePolicyController : Controller
{
public ActionResult Index()
{
return View();
}
}
}
Ensured my View folder was there and named appropriately as "CustomerServicePolicy". Note, when this didn't work I also tried renaming this folder to "customer-service-policy" but same 404!
Ensured I had an index.cshtml file in the View folder.
I thought that should do it but I'm just getting the 404 each time when I visit http://[site]/customer-service-policy/.
I can confirm that http://[site]/CustomerServicePolicy/ also no longer works but does work again if I remove the attributes above the Controller declaration.
What am I missing? Something obvious I bet...
I'm using Visual Studio Express 2013 for web and the incumbent web server - IIS Express.
Many thanks in advance.
I'm trying to create a REST api based on the Asp.Net MVC4 web api framework. The GET requests are working just fine. All other verbs are getting ignored by the server.
It just says the following:
"No action was found on the controller 'Track' that matches the request."
Though the example error is from the Track controller all other controllers have the same problem.
This is the method on the controller Track I'm trying to call:
[HttpPost]
public Object Index(string token, string juke, string track)
{
}
I'v tried it using a JSON object like so:
{ "track": "0000", "juke": "0000" }
And I tried to use the "normal" way:
track=0000&juke=0000
The '0000' in the examples above are stand-ins for the real id's.
To be sure I'm also posting the Register() from WebApiConfig.cs:
public static void Register(HttpConfiguration config)
{
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
config.Routes.MapHttpRoute(
name: "DefaultIndexBackEnd",
routeTemplate: "back-end/{controller}/{token}",
defaults: new { action = "Index", token = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultBackEnd",
routeTemplate: "back-end/{controller}/{action}/{token}",
defaults: new { token = RouteParameter.Optional }
);
}
Try this in your TrackController. Because you are using multiple parameters, they must be declared as optional.
[HttpPost]
public Object Index(string token="", string juke="", string track="")
{
}
You can make parameter token mandatory because token is declared as optional in routing configuration DefaultIndexBackEnd. I think using [FromBody] attribute is a good idea when there is more than one parameter for POST actions.
First, it's important to understand how a typical REST Web API is supposed to work. Typically, it uses different HTTP verbs (GET, POST, PUT, DELETE) for specific actions.
GET: get an entity (or a collection) from the server
POST: create a new entity
PUT: update an existing entity
DELETE: delete an existing entity
So when I see [HttpPost] on your Index action, it seems to me that the REST API pattern is broken.
Instead, in your controller you should have a Entity Get(int id) action (to get data) and a void Post(Entity entity) action to create new records.
No need to decorate your actions with HttpGet or HttpPost, the MVC Api framework will route the request to your action based on their names.
You can take a look at an example here.
After several hours of trying and researching articles I finally found an article that precisely described my problem! If you're having the same problems, check out the article.
The problem was that I had to use the [FromBody] attribute on one parameter of the of the action. After moving juke and track into a model it finally worked as I had hoped.
Thanks everyone for the help, you all set me on the right track!