WebApi Query String is stripped from RequestURI - c#

I have a WebApi Get action
public HttpResponseMessage Get()
{
try
{
var queryValue = Request.RequestUri.ParseQueryString();
if (queryValue.Count == 0)
{
return Request.CreateResponse(HttpStatusCode.BadRequest, "Query String Filters Required");
}
I call with with this url
api/funds?FundProductGroupCT=favourite&pagesize=10&startindex=8
RequestUri always has the query string stripped.
this is my global.asax
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
System.Web.Http.GlobalConfiguration.Configuration.Routes.MapHttpRoute
("default", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = System.Web.Http.RouteParameter.Optional });

Apologies.
This turned out to be a bit of a red herring. I'm using the web api with in an Ektron app. I've found there is a module which intercepts the request and if it doesnt end with a "/" strips the query string.

Related

C# webAPI restrict route

in a webapi project's WebAPIConfig.cs, 2 routes are added
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 }
);
I try to create an apiController contains below functions
[HttpGet]
public string Get(int id)
{
return "get";
}
[HttpGet]
[ActionName("ByWait")]
public string[] ByWait(int id)
{
return "bywait";
}
I expects that
requesting /api/controllername/1234 returns "get", and
requesting /api/controllername/bywait/1234 returns "bywait".
However, the actual result is
/api/controllername/1234 >> throw exception Multiple actions were found that match the request
/api/controllername/bywait/1234 >> "by wait"
However can fix the issue?
s.t how to restrict the function ByWait only accepts request containing action so that it only response to /api/controllername/bywait/1234 and ignore /api/controllername/1234
Or there is other better solution?
Thanks
First you can change WebApiConfig:
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}"
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Then controller:
[HttpGet]
public string Get()
{
return "get-default";
}
[HttpGet]
public string Get(int id)
{
return "get" + id;
}
[HttpGet]
[Route("api/values/bywait/{id}")]
public string ByWait(int id)
{
return "bywait";
}

Route Config with multiple custom actions in web api

So I have GET-methods in two different controllers that does not seem to work at the same time. My route config looks like this:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "GetGroupsFromSection",
routeTemplate: "api/{controller}/{action}/{sectionId}"
);
config.Routes.MapHttpRoute(
name: "ReturnCountForGroup",
routeTemplate: "api/{controller}/{action}/{groupIdCount}"
);
}
With this config, the first route(GetGroupsFromSection) works, but not the other one. If I switch them up so the ReturnCountForGroup is first, then that one works but not the other.
This is the methods
In the GroupController:
[HttpGet]
public IEnumerable<Group> GetGroupsFromSection(int sectionId)
{
var allGroups = groupRepository.SearchFor(s => s.SectionId == sectionId).ToList();
return (IEnumerable<Group>)allGroups;
}
And here is the other one from the ActivationCode-controller:
[HttpGet]
public int ReturnCountForGroup(int groupIdCount)
{
var count = dataContext.ActivationCode.Count(c => c.GroupId == groupIdCount);
return count;
}
GetGroupsFromSection is getting a 200 ok. But the ReturnCountForGroup get this error-message:
"MessageDetail": "No action was found on the controller 'ActivationCode' that matches the request."
There are conflicting routes which need to be made more specific for a route match to be made. Also the order of how routes are added to the route table is important. More generic routes need to be added after more specific/targeted routes.
config.Routes.MapHttpRoute(
name: "GetGroupsFromSection",
routeTemplate: "api/Group/{action}/{sectionId}",
defaults: new { controller = "Group" }
);
config.Routes.MapHttpRoute(
name: "ReturnCountForGroup",
routeTemplate: "api/ActivationCode/{action}/{groupIdCount}",
defaults: new { controller = "ActivationCode" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

web api routing with action and id

I am new in using web api and I am trying to call a specific method in my controller.
I have
global.asax
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
the WebApiConfig class with these routings
// Web API routes
config.MapHttpAttributeRoutes();
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
{
action="DefaultAction",
id = RouteParameter.Optional
}
);
and my controller
[HttpGet]
public HttpResponseMessage GetPatSummary(string PatId)
{
PatientSummary Pat = new PatientSummary();
HttpResponseMessage Response = new HttpResponseMessage();
string yourJson = Pat.GetPatient(PatId);
Response = this.Request.CreateResponse(HttpStatusCode.OK, yourJson);
return Response;
}
[ActionName("DefaultAction")] //Map Action and you can name your method with any text
public IHttpActionResult GetPatient(int id)
{
Object Obj = new object();
if (Obj!=null)
{
return NotFound();
}
return Ok(Obj);
}
the URL I am using is
http://localhost/mdmwapi/api/MdmwPatientController/GetPatSummary/sgdgdgddhdhd1334254
but I get this error
A path segment cannot contain two consecutive parameters. They must be separated by a '/' or by a literal string.
I am getting nut :-)
Use attribute routing
[HttpGet]
[Route("api/MdmwPatientController/GetPatSummary/{PatId}")]
public HttpResponseMessage GetPatSummary(string PatId)
{
PatientSummary Pat = new PatientSummary();
HttpResponseMessage Response = new HttpResponseMessage();
string yourJson = Pat.GetPatient(PatId);
Response = this.Request.CreateResponse(HttpStatusCode.OK, yourJson);
return Response;
}
then you can request it using
http://localhost/api/MdmwPatientController/GetPatSummary/yourpatid
also you can map any url using attribute routing this way
the solution is a combination of a new route and a mistake in the URL
the new routes are now these ones
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute
(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new
{
id = RouteParameter.Optional
}
);
config.Routes.MapHttpRoute(
name: "ApiMethodCall",
routeTemplate: "api/{controller}/{action}/{PatId}",
defaults: new
{
controller= "MdmwPatient",
action= "GetPatSummary"
}
);
and the error in the URL was that although the controller class name is MdmwPatientController I have to omit the "controller" suffix when calling from the test client, so the correct url is
http://localhost/mdmwapi/api/MdmwPatient/GetPatSummary/sgdgdgddhdhd1334254

Multiple POST-request in web api

I need to use multiple POST-requests in web API but get an error: "Multiple actions were found that match the request..."
I have 2 POST-requests in my controller:
public void PostStart([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
public void PostLogin([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
My route file looks like this currently:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "apistart",
routeTemplate: "Home/api/values/start/{id}",
defaults: new { action = "PostStart", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "apilogin",
routeTemplate: "Home/api/values/login/{id}",
defaults: new { action = "PostLogin", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
If I remove on of the requests from the controller, everything works fine, so my routes seem valid, but when both of requests are present, router can't find the right one.
Any thoughts?
I've tried alredy to use another default route but it changes nothing:
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
You can use [HttpPost] attribute to specify request method:
[HttpPost]
public void Start([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
[HttpPost]
public void Login([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
That will allows you to use as many post actions as you want with using default action-based route rule.
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
You should use RouteAttribute to make it work:
[Route("start")]
public void PostStart([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
[Route("login")]
public void PostLogin([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
WebApi doesn't take into consideration method name, only first word to resolve http method. Thats why you have error which says about "Multiple actions..." - there are two actions which can handle POST request.

MVC Web Api Route with default action not working

In my TestController I have the following:
[HttpGet]
public IEnumerable<String> Active()
{
var result = new List<string> { "active1", "active2" };
return result;
}
[HttpGet]
public String Active(int id)
{
var result = new List<string> { "active1", "active2" };
return result[id];
}
In RouteConfig the mapping is:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "", id = RouteParameter.Optional });
In a browser the following request works:
api/test/active/1
But this returns a Internal Server Error:
api/test/active
What do you have to do to return a action that may or maynot have a parameter in a similar manner to the default Get?
Update 1
As Cuong Le suggested, changing the ordering of routes helped, the routes are now:
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
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 }
);
I had to remove action = "" from the ActionApi route otherwise the standard Get on the other controllers stopped working (i.e. api/values)
api/test/active is now resolving, but I now get a 500 Internal Server Error for /api/test is it possile to have both resolves, so api/test would return "all" and /test/active only return "some"?
It is probably getting confused since you have two methods named action. Try deleting or renaming one of them and see if that works.
One way to do it is to provide a default value for the parameter,
[HttpGet]
public String Active(int id = 0)
{
var result = new List<string> { "active1", "active2" };
if (id == 0) {
return result;
} else {
return result[id];
}
}

Categories

Resources