So I have 2 controller:
[AllowCrossSiteJson]
public class ItemController : ApiController {
[HttpGet]
public LinkedList<Object> FindItem([FromUri]ItemQuery query) {
....
}
}
And
[AllowCrossSiteJson]
public class SubDepController : ApiController
{
[HttpGet]
public LinkedList<Object> FindSubDep(string ID) {
....
}
}
Here is the thing, I try to call both:
http://localhost:43751/api/SubDep
http://localhost:43751/api/Item
And the Item Controller works but the SubDep does not work! Why is that?
Here is my WebApiConfig:
public static void Register(HttpConfiguration config) {
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "withAction",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
The error I get back is this:
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost:43751/api/SubDep'.","MessageDetail":"No action was found on the controller 'SubDep' that matches the request."}
BONUS question:
How does ASP.NET MVC know that I try to hit:
http://localhost:43751/api/Item
It automatically go to the FindItem Action? It's like pure MAGIC to me!!
When you try to call FindSubDep action, your query string should be like belwo:
http://localhost:43751/api/SubDep/1
For the bonus question. It gets to the correct action because of the HTTP verb [GET] in your case, when you make a GET request for
http://localhost:43751/api/Item
it will find an action with [HttpGet] attribute on Item controller.
Related
I have the following routes setup;
RouteTable.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional },
constraints: null,
handler: new WebApiMessageHandler(GlobalConfiguration.Configuration));
and the following controller setup;
public class GetFileController : ApiController
{
[HttpGet]
public HttpResponseMessage Get(string id)
{
return Request.CreateResponse(HttpStatusCode.OK);
}
}
The issue I have here is that this url
/api/GetFile/id_is_a_string
returns this error;
<Error>
<Message>
No HTTP resource was found that matches the request URI /api/GetFile/id_is_a_string.
</Message>
<MessageDetail>
No action was found on the controller 'GetFile' that matches the name 'id_is_a_string'.
</MessageDetail>
</Error>
Is there any way to get around having it not think the string parameter is actually the action name?
I know I could change my request URL to be;
/api/GetFile?id=id_is_a_string
but this routing change affects a lot of other controllers I already have set and don't really wish to go through everything to switch it up to send the request this way.
If I re-order the routes, it seems to work as it did but for my new controller which I would've ideally liked to have multiple endpoints within, I get this error;
ExceptionMessage=Multiple actions were found that match the request:
New Controller
public class GettingThingsController : ApiController
{
[HttpPost]
public IHttpActionResult GetPeople()
{
return Ok();
}
[HttpPost]
public IHttpActionResult GetProducts()
{
return Ok();
}
}
Is there anyway of achieving what I need at all?!
You can try to specify parameters with Regex:
routeTemplate: "api/{controller}/{action:regex([a-z]{1}[a-z0-9_]+)}/{id:regex([0-9]+)}",
routeTemplate: "api/{controller}/{id:regex([0-9]+)}",
These regex works in Route attribute. You can test it in RouteTable mappings.
This is my Register method for routes in my web API project
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "AllRoutes",
routeTemplate: "{*url}",
defaults: new { controller = "IncomingRequest", action = "ProcessRequest" });
I would expect everything to go my ProcessRequest method on my IncomingRequest controller. However all routes result in 404. e.g.
http://localhost/CatCatcher/Cat/3
Can anyone advise what I might have missed?
Try this:
routes.MapRoute(
"AllRoutes",
"{*id}",
new { controller = "IncomingRequest", action = "ProcessRequest", id = "" }
);
Sorry, i've tested it now....
In web API project you cant set routes by different ways like:
config.Routes.MapHttpRoute(
name: "Routes",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
And to achieve URL ("http://localhost/CatCatcher/Cat/3") you can set route prefix on controller and action also Here is example for that:
[RoutePrefix("CatCatcher")]
public class CatCatcherController : ApiController
{
[HttpGet]
[Route("Cat")]
public object Cat(int Id){
//Do something
}
}
And if you want to go on Execution before hitting Action then lets follow the example in which I secure API with IP/Domain here it is:
public class AuthorizeIPAddressAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext filterContext)
{
//Even you can do here what you want
//Get users IP Address
string ipAddress = HttpContext.Current.Request.UserHostAddress;
if (!IsIpAddressValid(ipAddress.Trim()))//check allow ip
{
//Send back a HTTP Status code of 403 Forbidden
filterContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.NotFound);
}
base.OnActionExecuting(filterContext);
}
After Adding this class in project you just have to do this on your controller:
[AuthorizeIPAddress]
[RoutePrefix("CatCatcher")]
public class CatCatcherController : ApiController
{
[HttpGet]
[Route("Cat")]
public object Cat(int Id){
//Do something
}
}
Hopefully this will help you..
I have a Web Api controller which returns 404 when I call it.
public class ValuesController : ApiController
{
[HttpGet]
public static string Test()
{
return "Hola!";
}
}
Heres the Route Config
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
And here's the Route Debugger info.
I get 404 for below requests
http://localhost:8081/api/values/test
http://localhost:8081/api/values/get
Any ideas why its failing?
Your action is defined as a static method. Actions cannot be static.
[HttpGet]
public static string Test()
{
return "Hola!";
}
Make it an instance method and your code will work.
[HttpGet]
public string Test()
{
return "Hola!";
}
I'm fighting issues with routing in an MVC 3 Web API. It seems like it should be pretty simple, but I'm not making any headway.
My error is:
<Error>
<Message>The request is invalid.</Message>
<MessageDetail>
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'Boolean NewViolationsPublished(Int32)' in 'BPA.API.Controllers.CacheManagementController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
</MessageDetail>
</Error>
My RegisterRoutes is such:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "NukeAllItemsFromCache",
routeTemplate: "api/CacheManagement/NukeAllItemsFromCache");
routes.MapHttpRoute(
name: "ControllerAndAction",
routeTemplate: "api/{controller}/{action}"
);
routes.MapHttpRoute(
name: "ControllerAndActionAndId",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional, action = "Get" },
constraints: new { id = #"^\d+$" } // Only integers
);
routes.MapHttpRoute(
name: "ControllerAndId",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = #"^\d+$" } // Only integers
);
}
And my controller is (i took out the code for ease of reading):
public class CacheManagementController : ApiController
{
public CacheManagementController()
[HttpGet]
public bool NewViolationsPublished(int id)
[HttpGet]
public bool IsCached(CachedItemLabels label, int clientId)
[HttpGet]
public void RemoveItemFromCache(int clientId, CachedItemLabels cacheLabel, string test)
[HttpGet]
public string NukeAllItemsFromCache()
}
I get the error when I try to call:
http://localhost/api/CacheManagement/NukeAllItemsFromCache
TIA
Are you sure you're defining your routes in the right place? Web API routes should be configured using System.Web.Http.GlobalConfiguration.Configuration.Routes.MapHttpRoute (normally in a WebApiConfig.cs file in App_Start), as shown on http://www.asp.net/web-api/overview/extensibility/configuring-aspnet-web-api, which is different from the route configuration used by vanilla MVC.
I think you may just be hitting the default Web API route, which is api/{controller}/{id}, with ID optional. The action is determined by the HTTP verb, which in this case is GET, and all of your methods match that by virtue of the [HttpGet].
Edit: example
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalModifiers.ApplyGlobalConfiguration(this, true);
}
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "action-specific",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
I beleave your problem is in this route:
routes.MapHttpRoute(
name: "ControllerAndActionAndId",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional, action = "Get" },
constraints: new { id = #"^\d+$" } // Only integers
);
You specify id as an optional parameter and at the same time constrain it to actually be a non-nullable number. If /api/CacheManagement/NukeAllItemsFromCache is an exception, then add additional route for it, otherwise ease a constraint to something like #"^\d*$" if possible.
You are missing the default action for the route you configured:
routes.MapHttpRoute(
name: "NukeAllItemsFromCache",
routeTemplate: "api/CacheManagement/NukeAllItemsFromCache");
should be
routes.MapHttpRoute(
name: "NukeAllItemsFromCache",
routeTemplate: "api/CacheManagement/NukeAllItemsFromCache",
defaults: new { action = "NukeAllItemsFromCache" }
);
You tried to put parameter id as nullable like:
[HttpGet]
public bool NewViolationsPublished(int? id)
or
[HttpGet]
public bool NewViolationsPublished(Nullable<Int32> id)
Maybe this works...
Double check that your controller extends ApiController rather than Controller
public class CacheManagementController : ApiController
rather than
public class CacheManagementController : Controller
I've got a WebApi Controller and want to add a route.
Here is my Controller ...
public class ExtraInformationController : ApiController
{
private readonly ExtraInformationRepository _extraInfoRepository = new ExtraInformationRepository();
public ExtraInformation Get(int assetId)
{
return _extraInfoRepository.GetByAssetID(assetId).FirstOrDefault();
}
}
Heres my route ...
routes.MapHttpRoute(
"ExtraInformation",
"api/ExtraInformation/{assetId}",
new { controller = "ExtraInformation", action = "Get" }
);
I want to be able to call ...
api/ExtraInformation/4
But I'm getting ...
No HTTP resource was found that matches the request URI 'http://localhost:35188/api/ExtraInformation/4'.No action was found on the controller 'ExtraInformation' that matches the request.
Can anyone assist please?
Using the generic default route should be enough looking at your example. I would swap it for this and give it a try.
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);