I've created a restful webservice with Web-Api.
I'm trying to do a post at this url
../api/AAEAAAD_____AQAAAAAAAAAMAgAAAEVPYmplY3RUb0Jhc2U2NCwgVmVyc2lvbj0xLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABlPYmplY3RUb0Jhc2U2NC5DcmVkZW50aWFsAgAAABk8VXNlcm5hbWU-a19fQmFja2luZ0ZpZWxkGTxQYXNRmllbGQBAQIAAAAGAwAAAA5hd2NhQGF0ZWEtYW5jdAYEAAAAC0czcnRtNG5zMGZ0CwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2/say
The base64 is encoded with
HttpServerUtility.UrlTokenEncode();
I get a "HTTP Error 400. The request URL is invalid." when trying to do a post.
I've tried setting maxUrlLength as I've seen a few others with the same type of problem, alas, this did not help.
So far, I've tried
changing maxUrlLength in web.config.
Setting UrlSegmentMaxLength in Registry
nothing has worked so far.
I've found the magic number to be 294 allowed chars in the full url meaning -> If I cut of some of the characters from the long string until i get to 294 characters, everything works as intented, as to why certain it's not a routing problem nor a problem with my post method
Any good ideas as to what can be the issue?
For anyone trying to achieve the same thing I'm trying -
Heres my route
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{key}/{controller}/{id}",
defaults: new { key=RouteParameter.Optional,id = RouteParameter.Optional }
);
and my Post method
public string Post(string key)
{
if(ConvertFromBase64(key))
{
//Do stuff
}
}
Try with the key in the query string instead?
public class SomeController : Controller
[Route("api/say")]
public ActionResult Say(string key) {
}
With a url like
../api/say?key=AAEAAAD_____AQAAAAAAAAAMAgAAAEVPYmplY3RUb0Jhc2U2NCwgVmVyc2lvbj0xLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABlPYmplY3RUb0Jhc2U2NC5DcmVkZW50aWFsAgAAABk8VXNlcm5hbWU-a19fQmFja2luZ0ZpZWxkGTxQYXNRmllbGQBAQIAAAAGAwAAAA5hd2NhQGF0ZWEtYW5jdAYEAAAAC0czcnRtNG5zMGZ0CwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2
I know you tried through the web.config file, but can you try to increase the maxLength of the key parameter, like such ?
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{key:maxlength(500)}/{controller}/{id}", //whatever is the max length of your parameter...
defaults: new { key=RouteParameter.Optional,id = RouteParameter.Optional }
);
Related
I have been having issues setting up my custom WebApi route in C#. I am setting up a custom route that uses a company name a parameter. The route works fine, unless the company name ends with a "." I have tried setting double escape but keep getting a 404 error.
Route
config.Routes.MapHttpRoute(
name: "Contracts",
routeTemplate:"{company}/Contracts/{action}/{id}",
defaults: new {controller= "Contracts", id= RouteParameter.Optional}
);
Controller
public class ContractsController : ApiController
{
[HttpGet, ActionName("PrivacyStatements")]
public HttpResponseMessage GetPrivacyStatements(string Company)
{
//code for privacy statements
}
These will work:
http://localhost/Company%20Name/Contracts/PrivacyStatements
http://localhost/Company.%20Name/Contracts/PrivacyStatements
http://localhost/Contracts/PrivacyStatements?Company=Company%20Name%20Inc.
This does not work:
http://localhost/Company%20Name%20Inc./Contracts/PrivacyStatements
the "." before the "/" in "/Company Name Inc./" always gives me a 404.
Any help is appreciated.
I am currently playing around with some things...According to this link, I need to construct a route that is open to the following format
webServiceURL/version/devices/deviceLibraryIdentifier/registrations/passTypeIdentifier?passesUpdatedSince=tag
so I defined the route like so
config.Routes.MapHttpRoute(
name: "DefaultApi3",
routeTemplate: "{version}/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}/{passesUpdatedSince}",
defaults: new { controller = "SerialNumbers", action = "GET", passesUpdatedSince = RouteParameter.Optional }
);
However, the following route fails for the url
http://localhost/v1/devices/24358235235loji200/registrations/pass.com.mypass?passesUpdatedSince=12a512
How can I configure the route so that the above url can reach my controller?
My controller looks like
[HttpGet]
public HttpResponseMessage Get(string passesUpdatedSince ="")
{
//do stuff
}
UPDATE
Thanks to the comments, I've made the following changes.
the route
config.Routes.MapHttpRoute(
name: "DefaultApi3",
routeTemplate: "v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}",
defaults: new { controller = "SerialNumbers", action = "GET" }
);
My controller is as follows
public HttpResponseMessage Get(string deviceLibraryIdentifier,
string passTypeIdentifier,
string passesUpdatedSince = "")
{
//do stuff
}
According to the Apple docs, is it right to assume the following the webservice calls could look like
http://localhost:31472/v1/devices/23lk5235232oijlk/registrations/pass.com.mypass
http://localhost:31472/v1/devices/23lk5235232oijlk/registrations/pass.com.mypass?passesUpdatedSince=159025
as these are returning 404.
These, however, do work.
http://localhost:31472/v1/devices/23lk5235232oijlk/registrations/pass.com.mypass/?passesUpdatedSince=1415l
http://localhost:31472/v1/devices/23lk5235232oijlk/registrations/pass.com.mypass/
So would there be a way to get it to work without the presence of the / near the end of the url?
It does look like the device is unable to recognize the route. I get the following message
Get serial #s task (for device 2523ff2fswtsfdh6544, pass type pass.com.mypass, last updated (null); with web service url https://weburl) encountered error: Unexpected response code 404
Because part of the URI had periods in it (pass.com.mypass), this always returned a 404
I had to add the
<modules runAllManagedModulesForAllRequests="true" />
in my web.config. And after that, everything worked as expected
For the route, try:
config.Routes.MapHttpRoute(
name: "DefaultApi3",
routeTemplate: "{version}/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}",
defaults: new { controller = "SerialNumbers", action = "GET" }
);
Note that you should actually have a hard-coded value where {version} is, according to the link you gave us (https://developer.apple.com/library/ios/documentation/PassKit/Reference/PassKit_WebService/WebService.html#//apple_ref/doc/uid/TP40011988-CH0-SW4).
A hard-coded version would look like this:
config.Routes.MapHttpRoute(
name: "DefaultApi3",
routeTemplate: "v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}",
defaults: new { controller = "SerialNumbers", action = "GET" }
);
Your controller action also needs to be able to accept all parameters of the route:
[HttpGet]
public HttpResponseMessage Get(string deviceLibraryIdentifier,
string passTypeIdentifier,
string passesUpdatedSince ="")
{
//do stuff
}
I've looked for a solution to this but even the simplest examples aren't working properly. Passing a single parameter {id} works successfully but that's the only parameter that is working. Changing the single parameter to anything else fails. In the example below multiple parameters also fail. It seems as the only workable parameter is "id".
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Servers",
url: "{controller}/{action}/{id}/{a}",
defaults: new
{
controller = "Test"
}
);
}
public class TestController : Controller
{
[HttpGet]
public ActionResult Monster(string id, string a)
{
return Json(new { success = id }, JsonRequestBehavior.AllowGet);
}
}
The url localhost/Test/Monster/hi Successfully reads the parameter as "hi". Specifying localhost/Test/Monster/hi/hello fails and gives a 404.
Try this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Servers",
url: "{controller}/{action}/{id}/{a}",
defaults: new
{
controller = "Test",
id = UrlParameter.Optional,
a = UrlParameter.Optional
}
);
}
Also, is this your only route?
The order that the routes are set-up in is important, it's very easy to overwrite a route with a later route. I have done that mistake countless times.
In case action is not optional, you should specific the default value for it. Please try :
routes.MapRoute(
name: "Servers",
url: "{controller}/{action}/{id}/{a}",
defaults: new
{
controller = "Test",
action = "Monster"
}
);
In your method you have specified the parameter string a so when you pass the URl localhost/Test/Monster/hi/hello MVC will look for the parameter a in the url as it matches the form post parameters with the parameters in the function
So this link might help you as it helped me
http://www.codeproject.com/Articles/299531/Custom-routes-for-MVC-Application
This is a very late response but the issue with this was that there was an area being registered further downstream that was causing the routing issues. The area being registered had an optional url parameter that was taking the routes over. Utilizing this registered area fixed the issue.
sorry to say but as you saying
localhost/Test/Monster/Hi
working mean only one parameter routing is configured... did you try by restarting the IISExpress as routing get loaded on very first call and one time only..
after making the changes in routing you have to stop the IIS Express from the Icon Tray and re-run you project then with one parameter it should throw error.. as you have not set these option it will work only when u specify both the parameters.
Please excuse my ignorance in this area. I have read many threads and still cannot get my routing correct.
I have a ProductsController like this:
public class ProductsController : ApiController
{
[ActionName("GetListOfStudents")]
public static List<Structures.StudentInfo> GetListOfStudents(string Username, string Password)
{
List<Structures.StudentInfo> si = StudentFunctions.GetListOfStudents(Username, Password);
return si;
}
}
I have a console test program where I have defined the route:
config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/products/GetListOfStudents",
defaults: new { controller = "products", action = "GetListOfStudents" });
But when I run call
GET http://localhost:8080/api/Products/GetListOfStudents
I get the error message:
MessageDetail=No action was found on the controller 'Products' that matches the name 'GetListOfStudents'.
I have been pulling my hair out and cannot work out what the correct route should be.
Would any kind person care to help me out?
Ok- thanks for the help peeps!
This what I did to get it working:
Removed the "static" from the GetListOfStudents function.
Added the route below.
config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/products/GetListOfStudents/{username}/{password}",
defaults: new { controller = "products", action = "GetListOfStudents" }
);
Thanks everyone for your help!
When registering your global api access point, you should tell the config which route to use in the following manner:
config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/{controller}/{action}
defaults: new { controller = "products", action = "GetListOfStudents" });
In this sample you explicitly tell the controller it should only go to the "products" controller, you can make it generic without specifying the control or the action, just omit the defaults, like this:
config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/{controller}/{action}
That should do the job :)
Your GetListOfStudents action requires two parameters, username and password. Yet, the route definition contains neither specification in the route template where the values for those parameters should come from, nor specification for those parameter defaults in the defaults: parameter definition.
So when request comes in, routing is able to find your controller, but it is unable to find the action that it can call with the request and route context that it has because it has no information for the username and password parameters.
The most important is:
ASP.Net's mvc not only seek action by name, also it will check method's signature, only the method is non-static, name matches and parameters matches, the action will be executed.
for your case, there are two ways to correct it.
one way is declare default value, mvc will use default value when parametr not found.
public List<Structures.StudentInfo> GetListOfStudents(string Username = null, string Password = null)
{
List<Structures.StudentInfo> si = StudentFunctions.GetListOfStudents(Username, Password);
return si;
}
the second way is use override
public List<Structures.StudentInfo> GetListOfStudents()
{
return GetListOfStudents(null, null);
}
public List<Structures.StudentInfo> GetListOfStudents(string Username, string Password)
{
List<Structures.StudentInfo> si = StudentFunctions.GetListOfStudents(Username, Password);
return si;
}
I had this problem and solved it by including the verb as part of the action (i.e. GetThis, GetThat) and manually creating routes. I was attempting to create routes using attributes, but that did not work. This SO question may be the answer as to why the attributes aren't working, I haven't gotten that straightened out yet. As an additional note for anyone else having the same problem, when debugging it locally, IE was crashing when the "no action found" xml was returned. Once I gave up and switched to Chrome, the message detail was returned, and it was obvious that my controller at least was being found, it was just a matter of getting the action to work...
If you want to call GetListOfStudents method without parameter you must set default value for parameter. such as
GetListOfStudents(string Username=null, string Password=null)
Otherwise you must call method with Parameters.
GET http://localhost:8080/api/Products/GetListOfStudents/Username/Password
One issue could be the order of the route declarations in your WebApiConfig.cs file. Have a look here about the precedence of routes. If you have two routes with the same amount of parameters, you may need to reorder the routes, or -- depending on how specific the route is -- hardcode the controller or action name
When sending, encode the password with base64.
Then when you about to use it decode it.
byte[] numArray = Convert.FromBase64String(password);
string Pass = Encoding.UTF8.GetString(numArray);
List<Structures.StudentInfo> si = StudentFunctions.GetListOfStudents(Username, Pass);
Works fine for me.
I have an ASP.NET Web API application where I want to respond to the following routes:
1. http://localhost:1234/values
2. http://localhost:1234/values/123
3. http://localhost:1234/values/large
4. http://localhost:1234/values/small
Note: These routes and examples are just that, examples. But they map to what I want achieve.
Should return all values, say a list of numbers.
Should return the value of the resouce with id 123.
Should return a list of what the app considers large values. Whatever that may be.
Should return a list of what the app consider small values.
As with a billion ASP.NET Web Api routing examples, number (1) and (2) are straightforward. But when I try and resolve (3) and (4), then (1) and (2) are no longer working.
This is the routes I have at the moment:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// trying to map to "values/large" or "values/small"
routes.MapHttpRoute(
name: "ActionsApi",
routeTemplate: "{controller}/{action}",
defaults: null,
constraints: new { action = #"^[a-zA-Z]+$" }
);
// trying to map to "values/123"
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: null,
constraints: new { id = #"^\d+$" }
);
// trying to map to "values"
routes.MapHttpRoute(
name: "ControllerApi",
routeTemplate: "{controller}"
);
With the above routes, (3) and (4) work.
(2) returns:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
No action was found on the controller 'Values' that matches the name '123'.
</string>
And (1) returns:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
Multiple actions were found that match the request:
System.Collections.Generic.IEnumerable`1[System.String] Get() on type MvcApplication3.Controllers.ValuesController
System.Collections.Generic.IEnumerable`1[System.String] Large() on type MvcApplication3.Controllers.ValuesController
System.Collections.Generic.IEnumerable`1[System.String] Small() on type MvcApplication3.Controllers.ValuesController
</string>
I am at a loss as to how to setup the routes to support the 4 API examples I listed above.
EDIT: Thanks to David, he pointed out that \w also matched digits, hence a problem. I changed it to [a-zA-Z]+ to match large and small.
Now all work except for (1).
EDIT 2 As suggested by #andrei I made the id parameter optional, to try and get (1) working, but resulted in the following error for that route:
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
The optional default I added here:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = #"^\d+$" }
);
Have you considered leaving the routing as default, and dealing with the "values" in your controller?
e.g.
Change your Get to make id of type string, then check for "special" values inside your controller.
public class ValuesController : ApiController
{
// GET api/values/5
public string Get(string id)
{
if (id == "large")
{
return "large value";
}
if (id == "small")
{
return "small value";
}
return "value " + id;
}
}