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

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" })

Related

How to route Overidden Get methods in ASP.Net

there is a TaskController : ApiController
which contains 2 Get methods
public string Get(string cNumber){...}
public string Get(string task, string eNumber, string cNumber){...}
Configs are by defualt
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new MediaTypeHeaderValue("text/html"));
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
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 }
);
}
}
The first GET should be called like
http://localhost:50159/api/task?cnumber=123456
The second GET should be called like
http://localhost:50159/api/task?enumber=42&cnumber=123456
The issue is that always the first GET called.
Could somebody explain me why and how to fix it?
P.s. it is basically the first time when I work with asp.net MVC so remember that fact please when you will answer or asked me additional questions.
try like this ,it will fix your issue
[HttpGet("cnumber")]
public string Get(string cNumber){...}
[HttpGet("eNumber")]
public string Get(string task, string eNumber, string cNumber){...}
and while calling that api from postman use api/Task/cnumber and api/Task/enumber respectively.
By using this way ,you can create as many get() method you want.
just provide route to that get() method as per above code

can we pass null in the url parameter?

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.
}
}

Why isn't my ASP.NET API route being called, is my URL not correct?

I have a new ASP.NET MVC 5 application.
I added an /api folder in my controllers folder and added a MVC2 API controller.
My global.asax has:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
My controller looks like:
public class UsersController : ApiController
{
[HttpGet]
[ActionName("User")]
public IToken GetUser()
{
return new User();
}
}
Now I get a 404 resource cannot be found error when I go to:
http://localhost:53323/api/users/user
http://localhost:53323/api/users/getuser
What could the problem be?
Update
My MVC route config:
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 }
);
}
My API route config:
config.MapHttpAttributeRoutes();
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Seems like you are missing correct registration in your Application_Start().
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration); // This should be above the default route registration.
RouteConfig.RegisterRoutes(RouteTable.Routes);
//GlobalConfiguration.Configure(WebApiConfig.Register); // Remove this line.
}
Try using attribute routing on your controller and action methods.
Example
[RoutePrefix("api/users")]
public class UsersController : ApiController
{
[HttpGet]
[Route("user")]
public IToken GetUser()
{
return new User();
}
}

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)
{
}
}

Multiple IQueryable in one controller?

I have a controller for my entire database, the code is below:
public class YogaController : DbDataController<Yoga.Models.YOGAEntities>
{
public YogaController()
{
}
public IQueryable<Yoga.Models.Action> GetActions(int BugId)
//GetActions retrieves "actions" table from the db, not Actions in MVC term
{
return DbContext.Actions.Where(x => x.FK_BugsID == BugId);
}
public IQueryable<Yoga.Models.Label> GetRequiredLabels()
{
return DbContext.Labels.Where(x => x.IsRequired == true);
}
public IQueryable<Yoga.Models.Role> GetRoles()
{
return DbContext.Roles;
}
public IQueryable<Role> GetRoles2() //TODO: finish this
{
return DbContext.Roles.Where(x => x.RoleID == 1);
}
public IQueryable<Tag> GetTags(int actionid)
{
return DbContext.Tags.Where(x => x.J_Tags.Any(y => y.FK_ActionID == actionid));
}
}
As you can see I have multiple IQueryable in one controller, each querying a different table. Is it something that's forbidden? Because when I go to localhost/api/Yoga/GetActions or localhost/api/Yoga/GetRequiredLabels I get the error message:
Multiple actions were found that match the request:
System.Linq.IQueryable`1[Yoga.Models.Label] GetRequiredLabels() on type Yoga.Controllers.YogaController
System.Linq.IQueryable`1[Yoga.Models.Role] GetRoles() on type Yoga.Controllers.YogaController
System.Linq.IQueryable`1[Yoga.Models.Role] GetRoles2() on type Yoga.Controllers.YogaController
When I disable all but one IQueryable, the results came out fine.
I have googled for similar issues and checked my routing settings, there are no conflicts in controller path and names.
My Routes (default generated):
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//routes.MapRoute(
// name: "Default",
// url: "{controller}/{action}/{id}",
// defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Any ideas?
MVC4 is probably matching your HTTP Verb (Get) against all methods with names starting with 'Get' and no parameters. Try forcing the action name:
[ActionName("GetRequiredLabels")]
public IQueryable<Yoga.Models.Label> GetRequiredLabels()
...
[ActionName("GetActions")]
public IQueryable<Yoga.Models.Action> GetActions(int BugId)
... // etc
EDIT:
Based on the routes you pasted and your controller, I think your routes should be:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
i.e. it should have the {action} in there. The default MVC4 route would work if you only had a single 'Get' method. Since you have multiple, you'll have to force it to pick the action based on the route.

Resources