I have below route URL:-
www.domanname.com/subroute/GetInfo?param1=somestring¶m2=somestring
I have function in webapi as:-
public class HomeController : ApiController
{
public object GetInfo(string param1,string param2)
{}
}
To apply route:-
[RoutePrefix("subroute")]
public class HomeController : ApiController
{
[Route("GetInfo?param1={param1:string}¶m2={param2:string}")]
public object GetInfo(string param1,string param2)
{}
}
But after applying above URL:-
www.domanname.com/subroute/GetInfo?param1=somestring¶m2=somestring
It is not able to find that URL
How can I design this particular route?
You need to modify the routes a bit as query string are not normally used in attribute routes. They tend to be used for inline route parameters.
[RoutePrefix("subroute")]
public class HomeController : ApiController {
//Matches GET subroute/GetInfo?param1=somestring¶m2=somestring
[HttpGet]
[Route("GetInfo")]
public IHttpActionResult GetInfo(string param1, string param2) {
//...
}
}
Also
Enabling Attribute Routing
To enable attribute routing, call MapHttpAttributeRoutes during configuration. This extension method is
defined in the System.Web.Http.HttpConfigurationExtensions class.
using System.Web.Http;
namespace WebApplication
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
// Other Web API configuration not shown.
}
}
}
Reference Attribute Routing in ASP.NET Web API 2
[RoutePrefix("subroute")]
public class HomeController : ApiController {
[HttpGet]
[Route("GetInfo/{param1}/{param2}")]
public IHttpActionResult GetInfo(string param1, string param2) {
//...
}
}
Calling
//Matches GET subroute/GetInfo/Hello/World
Related
Typically you call an action of a controller like so http://hostname/MyController/MyAction
I have a requirement for my Web Api to have routes like this one:
http://hostname/MyController?action=MyAction, i.e., pass the action in url parameter.
My controller:
public class MyController : ApiController
{
[HttpGet]
[Route("WHAT SHOULD BE HERE??")]
public IHttpActionResult MyAction()
{
// some code
}
}
Any ideas how I can write such a routing?
You could try the following:
public class MyController : ApiController
{
[HttpGet]
[Route("MyController")]
public IHttpActionResult MyInnerController(String action)
{
switch(action)
{
case "MyAction":
return MyAction();
}
return BadRequest("Invalid action: " + action);
}
public IHttpActionResult MyAction()
{
return Ok();
}
}
Things will get more complicated if you require additional parameters.
After more than a year I can come back to this question and answer it myself.
The solution you can use here is to write your own ActionSelector - this is the class Web Api framework uses to select actions, by default it uses System.Web.Http.Controllers.ApiControllerActionSelector, which you can override.
So lets say your controller looks like this:
public class MyController : ApiController
{
[HttpGet]
public IHttpActionResult MyAction()
{
// some code
}
}
Then you can create your own action selector like this (the code might be improved I wrote it very quickly):
public class QueryParameterActionSelector : ApiControllerActionSelector
{
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
var mapping = GetActionMapping(controllerContext.ControllerDescriptor);
var parameters = controllerContext.Request.GetQueryNameValuePairs();
foreach (var parameter in parameters)
{
if (parameter.Key == "action")
{
if (mapping.Contains(parameter.Value))
{
// Provided that all of your actions have unique names.
// Otherwise mapping[parameter.Value] will return multiple actions and you will have to match by the method parameters.
return mapping[parameter.Value].First();
}
}
}
return null;
}
}
And then finally you have to register this action selector in WebApiConfig.Register method. It will look like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}"
);
config.Services.Replace(typeof(IHttpActionSelector), new QueryParameterActionSelector());
}
}
Now you can call your action like this http://hostname/controller?action=MyAction
I'm trying to implement a REST API in ASP.Net MVC. This is my code:
[Route("api")]
[ApiController]
public class ContactsController : ControllerBase
{
[HttpGet]
[Produces("application/xml")]
[Route("api/areas/{areaName}/contacts/{contactID}")]
public ActionResult<XmlDocument> Get(string areaName, string contactID)
{
return new XmlDocument();
}
}
However, when I surf to /api/areas/foo/contacts/bar, I encounter HTTP 404.
How can I fix my code?
Note that ActionResult<T> is part of asp.net-core and not the previous asp.net-mvc version. This means that you originally tagged the question incorrectly.
That said, the URL being called does not match the route template of the intended action and thus you will get a not found when trying to call the action.
Reference Routing to controller actions in ASP.NET Core
The provided route has [Route("api")] on the controller and [Route("api/areas/{areaName}/contacts/{contactID}")] on the action, which when combined would result in a URL that looks like
api/api/areas/foo/contacts/bar
I believe the intention was to have api only once so I would suggest remove one of them
Either from the action
[Route("api")]
[ApiController]
public class ContactsController : ControllerBase {
[HttpGet]
[Produces("application/xml")]
//GET api/areas/foo/contacts/bar
[Route("areas/{areaName}/contacts/{contactID}")]
public ActionResult<XmlDocument> Get(string areaName, string contactID) {
return new XmlDocument();
}
}
or removing the prefix on the controller
[ApiController]
public class ContactsController : ControllerBase {
[HttpGet]
[Produces("application/xml")]
//GET api/areas/foo/contacts/bar
[Route("api/areas/{areaName}/contacts/{contactID}")]
public ActionResult<XmlDocument> Get(string areaName, string contactID) {
return new XmlDocument();
}
}
I have applied attribute routing on my controller and it'srouting to wrong action. I don't know where I am getting it wrong.
Here is my controller:
using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Description;
using System.Linq;
using System;
namespace Iboo.API.Controllers
{
public class ClientsController : ApiController
{
private readonly IClientRepository _repository;
public ClientsController(IClientRepository repository)
{
_repository = repository;
}
// GET: api/Clients
[Route("api/v1/clients")]
public IEnumerable<Client> Get()
{
//code
}
// GET: api/Clients/5
[HttpGet]
[ResponseType(typeof(Client))]
[Route("api/v1/clients/get/{id}")]
public IHttpActionResult GetClientById(int id)
{
//code
}
// GET: api/Clients/5
[HttpGet]
[ResponseType(typeof(string))]
[Route("api/v1/clients/{id}/emailid")]
public IHttpActionResult GetClientEmailId(int id)
{
//code
}
}
}
I am specifically interested in the GetClientEmailId method. Below is my WebApiConfig
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var container = new UnityContainer();
container.RegisterType<IClientRepository, ClientRepository>(new
HierarchicalLifetimeManager());
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
My Global.asax.cs is as follows
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
In the browser If I type http://localhost:54919/api/v1/clients/?id=1/getemailid it's taking me to http://localhost:54919/api/v1/clients which is not what I want.
If I try http://localhost:54919/api/v1/clients/1/getemailid I am getting a 404 error.
I am not sure as to what I'm getting wrong.
You are calling the wrong URLs according to routes on the actions. you get 404 because the URL you call does not match to any of the route templates you have on your actions
[RoutePrefix("api/v1/clients")]
public class ClientsController : ApiController {
//...other code removed for brevity
[HttpGet]
[Route("")] //Matches GET api/v1/Clients
public IHttpActionResult Get() {
//code
}
[HttpGet]
[ResponseType(typeof(Client))]
[Route("{id:int}")] //Matches GET api/v1/Clients/5
public IHttpActionResult GetClientById(int id) {
//code
}
[HttpGet]
[ResponseType(typeof(string))]
[Route("{id:int}/emailid")] //Matches GET api/v1/Clients/5/emailid
public IHttpActionResult GetClientEmailId(int id) {
//code
}
}
Take note of the expected URLs in the comments
You should also read up on Attribute Routing in ASP.NET Web API 2 to get a better understanding of how to do attribute-routing.
You can try using the route prefix on the controller.
[RoutePrefix("api/v1/clients")]
public class ClientsController : ApiController
{
// GET: api/Clients/5
[ResponseType(typeof(string))]
[Route("{id:int}/emailid"),HttpGet]
public IHttpActionResult GetClientEmailId(int id)
{
//code
}
}
You said:
In the browser If I type http://localhost:54919/api/v1/clients/?id=1/getemailid it's taking me to http://localhost:54919/api/v1/clients which is not what I want.
From the way your routes are set up, it looks like you need to go to http://localhost:54919/api/v1/client/1/emailid to get to the route you want
To explain the difference, when you call http://localhost:54919/api/v1/clients/?id=1/getemailid the route that would match that is something like:
[Route("api/v1/clients")]
public IHttpActionResult GetClientEmailId(string id)
{
//code
}
because you've added the id parameter as a querystring parameter. In this case, the id argument would have a value of 1/getemailid which doesn't make much sense.
by using the route parameters (by replacing ?id=1/getemailid with 1/emailid) you will actually match the route you want to
I Have a problem configuring routes in ASP Core.
In Startup.cs I used default configuration: services.AddMvc() in ConfigureServices() and app.UseMvc() in Configure().
Now I have a simple controller in the same assembly:
[Route("/api/[controller]")]
public class TestController: Controller
{
[HttpGet]
public string Test()
{
return "Hello";
}
}
Request /api/test/test doesn't fire
But if i add [HttpGet("test")] or [Route("test")] it works well.
However I'd like to support convention over configuration in case route attribute is not specified
Try using:
[Route("api/[controller]/[action]")]
When you add [Route("/api/[controller]")] annotation to Controller, the default routing configured in Startup.cs will ignore this Controller.
So you either need to specify URL suffix for each of your actions inside that Controller by adding [Route("")] attribute above them:
[Route("/api/[controller]")]
public class TestController: Controller
{
[Route("test")]
[HttpGet]
public string Test()
{
return "Hello";
}
}
Or specify in Controller annotaion that the routing should use action names as part of URL :
[Route("/api/[controller]/[action]")]
public class TestController: Controller
{
[HttpGet]
public string Test()
{
return "Hello";
}
}
[Route("/api/[controller]")]
public class TestController: Controller
{
[HttpGet(namOf(Test),Name=namOf(Test))]
public string Test()
{
return "Hello";
}
}
I would like to set the route to a method within an ApiController dynamically. The below shows my TokenController:
public class TokenController : ApiController
{
[Route("api/token/{grantType}")]
[RequireHttps]
public IHttpActionResult Post(string grantType)
{}
}
I am thinking of using dependency injection as follows:
public class TokenController : ApiController
{
public TokenController(ITokenService tokenService)
{
//configure route "api/token/{grantType}" using tokenService?
}
[Route("api/token/{grantType}")]
[RequireHttps]
public IHttpActionResult Post(string grantType)
{}
}
Or do I need to do this in App_Start using the HttpConfiguration object?
How would I do this?
Found my answer. I will configure the endpoint route with HttpConfiguration:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "API TokenEndpoint",
routeTemplate: "services/newtoken/{grantType}",
defaults: new { controller = "Token" action="Post"},
constraints: null);
}
}