I am creating a WebApi2 service, and one of the methods I want to implement represents an HTTP GET from an object within an internal tree structure - so the request would be along the lines of:
GET /values/path/path/to/object/in/tree
So I would want my method to receive "path/to/object/in/tree".
However, I just get a 404 when I run this, and it's interesting that I get a 404 that is different looking to the standard IIS 404. It's titled 'Server Error in '/' Application.', whereas the one for a completely invalid resource is titled 'HTTP Error 404.0 - Not Found'.
I am playing around with the default template to try and see if I can get this to work, hence the similarity.
I have this for my RouteConfig
public static void RegisterRoutes(RouteCollection routes)
{
var route = routes.MapRoute(
name: "CatchAllRoute",
url: "values/path/{*pathValue}",
defaults: new { controller = "Values", action = "GetPath" });
}
And this is my ValuesController:
[System.Web.Mvc.AuthorizeAttribute]
[RoutePrefix("values")]
public class ValuesController : ApiController
{
[Route("test/{value}")]
[HttpGet]
public string Test(string value)
{
return value;
}
[HttpGet]
public string GetPath(string pathValue)
{
return pathValue;
}
}
Interestingly, if I derive from Controller rather than ApiController it works OK, but then the normal attribute routing doesn't work.
I tried following the methodology in this post (http://www.tugberkugurlu.com/archive/asp-net-web-api-catch-all-route-parameter-binding) but I couldn't get it to work.
I'm sure I'm missing something stupidly easy, but having spent a few hours on it I thought it prudent to ask what I'm doing wrong.
Thanks
M
Web api routing is not the same as routing MVC. instead of
route.MapRoute
try
public static void Register(HttpConfiguration config) {
config.MapHttpAttributeRoutes
config.Routes.MapHttpRoute(
name: "CatchAll", routeTemplate: "values/path/{*pathvalue}",
defaults: new {id = RouteParameter.Optional });
}
The reason it works from controller is that MapRoute is the correct format for routing an MVC controller, while MapHttpRoute is designed for API controllers.
Related
I have a controller which works perfectly fine:
[Authorize]
[Route("api/Version")]
public class VersionController : ApiController
{
However if I omit the Route attribute in other controllers it doesnt work, when I go to: url/api/User or Users, I get a 404
[Authorize]
public class UserController : ApiController
{
my webappi config
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}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Services.Add(typeof(IExceptionLogger), new AiExceptionLogger());
}
}
my routeconfig
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
User Controller GetUsers
[HttpGet]
public async Task<IHttpActionResult> GetUsers()
{
You seem to be defining two different configuration classes that specify different route schemes in their methods:
In WebApiConfig.Register(...), you have routeTemplate: "api/{controller}/{action}/{id}";
In RouteConfig.RegisterRoutes(...), you specified url: "{controller}/{action}/{id}".
Please note that these routes overlap each other, so you have to be careful when employing these configurations in your application.
Regarding the VersionController and UserController, it seems that it is in fact the Route attribute that is defining your route.
In VersionController, if you specify [Route("api/Version")], you are correctly able to access /api/version. If you remove this, you may be able to access /version instead of /api/version, or are you not? (This may help understanding what configuration - WebApiConfig, RouteConfig or any - is used.
Likewise, in UserController, given that you don't specify [Route("api/User")], you may be able to access /user (without the /api prefix). Can you confirm this, please? On the other hand, if you were defining the Route attribute, then you should be able to access api/user.
I am assuming that you are already mapping your controllers to endpoints, since I understood that you are able to access api/version.
This documentation is pretty good on explaining Routing in MVC projects (in this case, for .NET Core), and it explians the multiple routes approach that perhaps you are trying to achieve with WebApiConfig and RouteConfig.
For the last couple of hours i'm trying to execute web api action hosted in asp.net webforms website.
I know its wired but due to old project design i have to do this.each time i call the action in Controller i got
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost:3049/api/chart/test?id=58'.","MessageDetail":"No action was found on the controller 'Chart' that matches the request."}
My Project structure as follows:-
My Classes code looks very simple:-
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.EnableCors();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new {id = RouteParameter.Optional }
);
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}
}
My Controller:-
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class ChartController : ApiController
{
[HttpGet]
public static string test(string id)
{
return id;
}
}
What i miss ?
Make your action method non-static. In Microsoft's documentation, they say this:
Which methods on the controller are considered "actions"? When selecting an action, the framework only looks at public instance methods on the controller.
Also, your routing is in the form of api/{controller}/{id} but the URL you're accessing is in the form of /api/controller/action?id=string. Notice the mismatch? You can change your action method to match your route.
[HttpGet]
public string Get(string id)
{
return id;
}
And then access it at /api/chart/58.
With the default routing structure in Web API, your route tells it what controller, the selected action method is based on the HTTP Method (GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH) and the parameters, and then other segments of the URL become the parameters.
Learn more detail about Web API Routing on MSDN.
I have looked all over for some kind of soultion for this and it seems I have it setup correctly and followed all corrections in other questions.
When calling "http://localhost/en/api/cart/get" I get:
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost/en/api/cart/get'.","MessageDetail":"No type was found that matches the controller named 'cart'."}
...when trying to access a ApiController setup in an EPiServer CMS/Commerce 7.5+ solution.
The Controller looks like this:
public class CartController : ApiController
{
[HttpGet]
public string Get()
{
return "OK";
}
}
In Global.asax.cs i have this:
protected void Application_Start()
{
RegisterApis(GlobalConfiguration.Configuration);
And the RegisterAPis looks like this:
public static void RegisterApis(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
"Api", // Route name
"api/{controller}/{action}/{id}", // URL with parameters
new { id = RouteParameter.Optional } // Parameter defaults
);
config.Routes.MapHttpRoute(
"LanguageAwareApi", // Route name
"{language}/api/{controller}/{action}/{id}", // URL with parameters
new { id = RouteParameter.Optional } // Parameter defaults
);
// We only support JSON
var appXmlType = GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
}
On the same machine I have the EPiServer Commerce starterkit running i IIS and the code for registering the api controllers is the same. That site runs fine and the api calls can be made correctly but on my site all I get is 404.
So I am probably missing some configuration but I can't for my life figure out what it is. The weird part is that on my site I'm running the EPiServer ServiceApi which creates the /episerverapi Web Api mapping and that works just fine.
Anyone got any clues on why I can't get my APiControllers to work?
In Web API the http verb help the framework to find the right action to be executed and return a result. For sample, in a case of a get method, you just call the controller by get http verb:
http://localhost/en/api/cart
It will bind a Get action method in the Cart controller class. It is valid for a Post, Put, Delete methods too. Keep the default route of asp.net web api
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Try calling just
http://localhost/en/api/cart
In WebAPI if the name of the method matches a HTTP verb then it calls that method when that verb is used on that controller.
I am getting to following exception when i am trying to call a GET function in MVC WebAPI
{"$id":"1","Message":"An error has occurred.",
"ExceptionMessage":"Multiple actions were found that match the request:
\r\nSystem.Xml.XmlNode Get(Int32, System.String)
I think the problem is cause due to two get function
I have defined two functions:
One:
[HttpGet]
public XmlNode Get(int id, string Tokken)
{
//Do something
}
Second One
[HttpGet]
public List<UsersAnswers> GetUsersInteractions(int? activityID, string Tokken)
{
// Do Something
}
The route configuration
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Now i am getting the exception when i try to call to the second function:
{SiteURL}/api/Activities/GetUsersInteractions?activityID=32&Tokken=r54e54353
As you can see the route engine sent the request to the first function instead of the second.
How can i define two get operation and to call each one separately?
With the default routing template, Web API uses the HTTP method to select the action. However, you can also create a route where the action name is included in the URI:
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
In this route template, the {action} parameter names the action method on the controller. With this style of routing, use attributes to specify the allowed HTTP methods. For example, suppose your controller has the following method:
public class ProductsController : ApiController
{
[HttpGet]
public string Details(int id);
}
In this case, a GET request for “api/products/details/1” would map to the Details method. This style of routing is similar to ASP.NET MVC, and may be appropriate for an RPC-style API.
You can override the action name by using the ActionName attribute. In the following example, there are two actions that map to "api/products/thumbnail/id. One supports GET and the other supports POST:
public class ProductsController : ApiController
{
[HttpGet]
[ActionName("Thumbnail")]
public HttpResponseMessage GetThumbnailImage(int id);
[HttpPost]
[ActionName("Thumbnail")]
public void AddThumbnailImage(int id);
}
You are not calling the second function - the second function is named InsertUserRecord and is a POST method. The function you're calling via GET is GetUserInteractions. As there's no such function for GET, the engine may map this to the only GET function there is, but actually it should throw a "no such function" error.
Using the new Api Controller in MVC4, and I've found a problem. If I have the following methods:
public IEnumberable<string> GetAll()
public IEnumberable<string> GetSpecific(int i)
This will work. However, if I want to retrieve some different data of a different type, it defaults to the GetAll method, even though the $.getJSON is set to the GetAllIntegers method:
public IEnumberable<int> GetAllIntergers()
(bad naming conventions)
Is it possible for me to be able to do this?
Can I only have a single GetAll method in the Web API controller?
I think it's easier to visualise what I'm trying to achieve. Here is a snippet of code to show what I'd like to be able to do, in a single ApiController:
public IEnumerable<string> GetClients()
{ // Get data
}
public IEnumerable<string> GetClient(int id)
{ // Get data
}
public IEnumerable<string> GetStaffMember(int id)
{ // Get data
}
public IEnumerable<string> GetStaffMembers()
{ // Get data
}
This is all in the routing. The default Web API route looks like this:
config.Routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
With the default routing template, Web API uses the HTTP method to select the action. In result it will map a GET request with no parameters to first GetAll it can find. To work around this you need to define a route where the action name is included:
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
After that you can star making requests with following URL's:
api/yourapicontroller/GetClients
api/yourapicontroller/GetStaffMembers
This way you can have multiple GetAll in Controller.
One more important thing here is that with this style of routing, you must use attributes to specify the allowed HTTP methods (like [HttpGet]).
There is also an option of mixing the default Web API verb based routing with traditional approach, it is very well described here:
Web API: Mixing Traditional & Verb-Based Routing
In case someone else faces this problem. Here's how I solved this. Use the [Route] attribute on your controller to route to a specific url.
[Route("api/getClient")]
public ClientViewModel GetClient(int id)
[Route("api/getAllClients")]
public IEnumerable<ClientViewModel> GetClients()