can we pass null in the url parameter? - asp.net

I have a Asp.Net webApi controller as below:
[RoutePrefix("business/api/v1")]
public class BusinessController : ApiController
{
[Route("GetDetails/{id}")]
public HttpResponseMessage Get(string id)
{
// get business details code.
}
}
Is there anyway that client can hit this api with id null??

It depends on your configuration of Web API routes in App_Start/WebApiConfig.cs.
If route is something like:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "business/api/v1/GetDetails/{id}",
defaults: new { id = RouteParameter.Optional }
);
then user can reach resource use http://localhost.business/api/v1/GetDetails or http://localhost.business/api/v1/GetDetails/1.
When you remove defaults: new { id = RouteParameter.Optional } then user have to pass an id otherwise, it will return 404

Please try:
[RoutePrefix("business/api/v1")]
public class BusinessController : ApiController
{
[Route("GetDetails/{id:int?}")]
public HttpResponseMessage Get(int id)
{
// get business details code.
}
}

Related

Disable Session state per-request in ASP.Net Web Api (ApiController)

I have ApiControllers that access the session and by default has SessionState required. Therefore I am getting the requests serialized and would like to disable session state for specific requests.
In this post I have seen a solution for normal Controllers but I have no idea how to do it on ApiControllers.
This is my WebApiConfig
public static void Register(HttpConfiguration config)
{
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
).RouteHandler = new SessionRouteHandler();
config.Routes.MapHttpRoute(
name: "Default2",
routeTemplate: "api/{controller}"
);
}
And this is the SessionControllerHandler
public class SessionControllerHandler : HttpControllerHandler, IRequiresSessionState
{
public SessionControllerHandler(RouteData routeData)
: base(routeData)
{ }
}
public class SessionRouteHandler : IRouteHandler
{
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return new SessionControllerHandler(requestContext.RouteData);
}
}
Any help will be appreciated. Thank you
In order to not get the requests serialized, generate a new SessionControllerHandler for SessionState in ReadOnly mode
public class SessionControllerHandlerReadOnly : HttpControllerHandler, IReadOnlySessionState
{
public SessionControllerHandlerReadOnly(RouteData routeData)
: base(routeData)
{ }
}
public class SessionRouteHandlerReadOnly : IRouteHandler
{
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return new SessionControllerHandlerReadOnly(requestContext.RouteData);
}
}
Then in the WebApiConfig add a new route that uses that handler
RouteTable.Routes.MapHttpRoute(
name: "DefaultApiReadOnly",
routeTemplate: "apireadonly/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
).RouteHandler = new SessionRouteHandlerReadOnly();
Done, when you need a specific request going through that handler you specify it in the RouteUrl when making the request
#Url.RouteUrl("DefaultApiReadOnly", new { httproute = true, controller = "controller", action = "action" })

Route is not triggered with trailing slash in web api 2

This is my route configuration:
config.Routes.MapHttpRoute(
name: "Public",
routeTemplate: "{dept}/{unit}/",
defaults: new
{
controller = "Home",
action = "Index"
},
constraints: new { constraint = new MyConstraint() }
);
When I type into the url:
mysite.com/XYZ/123
then my constraint class is triggered
but when I use:
mysite.com/XYZ/123/ with the appended slash the constraint class is not triggered.
I use Web Api 2.
In the routeTemplate I can use the "/" at the end or not that doesnt make difference.
Why does it not work?
UPDATE
public class HomeController : ApiController
{
[HttpGet]
public HttpResponseMessage Index()
{
}
}
I've updated my answer:
Try attribute routing:
[RoutePrefix("dept")]
public class DepartmentController : ApiController
{
[Route("unit:int:min(1)"}]
public object Unit() {}
}
Constraints can be setup like above. More:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2#constraints

Routing in ASP .NET Web API

I created a web service using WEB API.
I'm using this routing configuration
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
And my solution include two controller (ProductController and DetailController)
So when I want to call a WS that refers to the GetDetails method(is located inside DetailController) I have to use a URL like this:
http://localhost/api/Details/GetDetails/?id=4
Is there a way for use, for the same request, this URL instead:
http://localhost/api/Product/GetDetails/?id=4
letting the GetDetails method inside the DetailController?
Actually your urls should be:
http://localhost/api/Details/4
http://localhost/api/Products/4
and your controllers:
public class DetailsController: ApiController
{
public HttpResponseMessage Get(int id)
{
...
}
}
and:
public class ProductsController: ApiController
{
public HttpResponseMessage Get(int id)
{
...
}
}
Now that's RESTful.

ASP.Net Web Api routing issue with ActionName

I am working with an ASP.Net Web Api project on Web Developer Express 2010. The routing config is defined in WebApiConfig.cs as:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi3",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = RouteParameter.Optional,
id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi4",
routeTemplate: "api/{controller}/{action}",
defaults: new { action = RouteParameter.Optional }
);
}
An API Controller called "GCURObservationController" has an action as:
[HttpGet, ActionName("retrieveCuringMaps")]
public IList<SimpleCuringMapsModel> retrieveCuringMaps()
{
... ...
return jsonCuringMapModels;
}
The project was compiled and run successfully. However, I had to go to
http://localhost:2061/api/GCURObservation/retrieveCuringMaps/0
to get the action triggered (action name followed by any integer), rather than what I expected to be
http://localhost:2061/api/GCURObservation/retrieveCuringMaps
That means an arbitrary integer had to follow the action name to get it right. Otherwise, the error was returned. I don't want this action to be triggered with any param.
{"Message":"The request is invalid."}
How to get the second URL to work? Thanks
Cheers,
Alex
If you are using Web API 2, following is one solution you could use. In the below example, I am using attribute routing and conventional routing together in one controller. Here all the actions except GetCustomerOrders are reached via conventional route "DefaultApi".
In general the idea here is not new, that is...even without Web API 2's attribute routing, you could define routes for each individual action of a controller in the global route table, but attribute routing makes this process easier as you can define routes directly and near to the action.
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
[RoutePrefix("api/customers")]
public class CustomersController : ApiController
{
public IEnumerable<Customer> GetAll()
{
}
public Customer GetSingle(int id)
{
}
public void Post(Customer customer)
{
}
public void Put(int id, Customer updatedCustomer)
{
}
public void Delete(int id)
{
}
[Route("{id}/orders")]
public IEnumerable<Order> GetCustomerOrders(int id)
{
}
}

Web API Routing - api/{controller}/{action}/{id} "dysfunctions" api/{controller}/{id}

I have the default Route in Global.asax:
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
I wanted to be able to target a specific function, so I created another route:
RouteTable.Routes.MapHttpRoute(
name: "WithActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
So, in my controller, I have:
public string Get(int id)
{
return "object of id id";
}
[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
return new string[] { "byCategory1", "byCategory2" };
}
Calling .../api/records/bycategoryid/5 will give me what I want.
However, calling .../api/records/1 will give me the error
Multiple actions were found that match the request: ...
I understand why that is - the routes just define what URLs are valid, but when it comes to function matching, both Get(int id) and ByCategoryId(int id) match api/{controller}/{id}, which is what confuses the framework.
What do I need to do to get the default API route to work again, and keep the one with {action}? I thought of creating a different controller named RecordByCategoryIdController to match the default API route, for which I would request .../api/recordbycategoryid/5. However, I find that to be a "dirty" (thus unsatisfactory) solution. I've looked for answers on this and no tutorial out there on using a route with {action} even mentions this issue.
The route engine uses the same sequence as you add rules into it. Once it gets the first matched rule, it will stop checking other rules and take this to search for controller and action.
So, you should:
Put your specific rules ahead of your general rules(like default), which means use RouteTable.Routes.MapHttpRoute to map "WithActionApi" first, then "DefaultApi".
Remove the defaults: new { id = System.Web.Http.RouteParameter.Optional } parameter of your "WithActionApi" rule because once id is optional, url like "/api/{part1}/{part2}" will never goes into "DefaultApi".
Add an named action to your "DefaultApi" to tell the route engine which action to enter. Otherwise once you have more than one actions in your controller, the engine won't know which one to use and throws "Multiple actions were found that match the request: ...". Then to make it matches your Get method, use an ActionNameAttribute.
So your route should like this:
// Map this rule first
RouteTable.Routes.MapRoute(
"WithActionApi",
"api/{controller}/{action}/{id}"
);
RouteTable.Routes.MapRoute(
"DefaultApi",
"api/{controller}/{id}",
new { action="DefaultAction", id = System.Web.Http.RouteParameter.Optional }
);
And your controller:
[ActionName("DefaultAction")] //Map Action and you can name your method with any text
public string Get(int id)
{
return "object of id id";
}
[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
return new string[] { "byCategory1", "byCategory2" };
}
You can solve your problem with help of Attribute routing
Controller
[Route("api/category/{categoryId}")]
public IEnumerable<Order> GetCategoryId(int categoryId) { ... }
URI in jquery
api/category/1
Route Configuration
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.
}
}
}
and your default routing is working as default convention-based routing
Controller
public string Get(int id)
{
return "object of id id";
}
URI in Jquery
/api/records/1
Route Configuration
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Attribute routing.
config.MapHttpAttributeRoutes();
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Review article for more information Attribute routing and onvention-based routing here & this
Try this.
public class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var json = config.Formatters.JsonFormatter;
json.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
config.Formatters.Remove(config.Formatters.XmlFormatter);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional , Action =RouteParameter.Optional }
);
}
}
The possible reason can also be that you have not inherited Controller from ApiController.
Happened with me took a while to understand the same.
To differentiate the routes, try adding a constraint that id must be numeric:
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
constraints: new { id = #"\d+" }, // Only matches if "id" is one or more digits.
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);

Resources