WCF HTTP GET parameter causes bad request - c#

I have a WCF service with the following operation contract:
[OperationContract]
[WebGet(BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "/VerifyKeys.json/{customerKey}/{userKey}")]
[return: MessageParameter(Name = "MyDetail")]
MyDetail VerifyKeys(string customerKey, string userKey);
My method is like this:
public MyDetail VerifyKeys(string customerKey, string userKey)
{
...
return _myDetail;
}
My request is like this:
http://mydomain.com/MyService.svc/web/VerifyKeys.json/FE3D0F1D-5B8B-4677-B332-70B7ABA80A97/08F4349A-30E5-457D-F2BD-70A23CE17F41?deviceId=66345ec6-a5fe-4b5f-8cf2-1b0d8c344dc2&deviceToken=AgTGERCBaS3d8n2QWxF9EtwcLktIoygoXpc8Y42ObZWja3RSjN%2bFBeshaY4ASainj3MusBbVopXbUFQrrgXUOSkAbOA7tChNKOFNKQ2gB8sEfCe5Du9BZufW4bAP5312MKRqV8g%3d&deviceType=Pink24
I have different versions of my application calling this method. Rather than create a new method, I have used a query string at the end. By parsing the url, I can get the additional parameters I need. ie. deviceToken, deviceId, & deviceType
My request worked fine while the deviceToken parameter was smaller. Now the company providing me with my device token has made an excessively huge one. And now my request returns Bad Request 400.
AgTGERCBaS3d8n2QWxF9EtwcLktIoygoXpc8Y42ObZWja3RSjN%2bFBeshaY4ASainj3MusBbVopXbUFQrrgXUOSkAbOA7tChNKOFNKQ2gB8sEfCe5Du9BZufW4bAP5312MKRqV8g%3d
If I remove these characters from the end of my query string, the request goes through successfully. "Q2gB8sEfCe5Du9BZufW4bAP5312MKRqV8g%3d"
I have done some research and discovered that the max for a parameter is 255 characters. My device token is only 140.
To add to my confusion, if I change the order of the deviceId and deviceToken parameters, then I must shorten the deviceId parameter to send successfully. Another point of interest is that if I try to shorten any of the other parameters, then my request still fails. I must always shorten the second parameter.
Has any one else had similar problems and found a solution?
How can I send my looong device token via a query string at the end of a path?

It's possible it's the length of your query string itself, not the parameter.
Try adding
<httpRuntime maxQueryStringLength="2500"
maxUrlLength="2500" maxRequestLength="2500" />
to your config and see if the error persists

I found the solution after posting this question. Such is often the way.
The device token was getting saved to a field that was NVARCHAR(100). Previously this was enough. The device token can now be at least 140 characters. I changed the field to NVARCHAR(255). The problem is fixed. No more Bad Request 400.

Related

Error Deserializing WCF POST Request With Multiple Parameters

i did search before posting this question and none of the answers helped me
i am hosting a WCF web service on IIS and using GET and POST in it successfully. the error is only showing when calling a POST web method with multiple param
Example:
**//this fails**
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, UriTemplate = "test", BodyStyle = WebMessageBodyStyle.WrappedRequest)]
String test(String p, String credential);
**//this works**
[OperationContract]
[WebInvoke(Method = "POST",UriTemplate = "test")]
String test(String p);
the code behind simply returns a string for testing
I am receiving the following error:
The server encountered an error processing the request. The exception
message is 'Error in deserializing body of request message for
operation 'test'. The OperationFormatter could not deserialize any
information from the Message because the Message is empty (IsEmpty =
true)
i am testing the following web methods on POSTMAN
Parameters passed are random string:
p: tt
credetial: ghdhdj
WCF doesn’t support form-data by default, we merely pass the parameter by using the Wrapper element when we use Http_Post request.
As you mentioned, we should use the below code to wrap the multiple parameters.
[OperationContract]
[WebInvoke(BodyStyle =WebMessageBodyStyle.Wrapped)]
string GetData(string value,string value2);
And then we can pass the parameters with JSON format.
{"value":"ab","value2":"cd"}
Screenshot.
Feel free to let me know if the problem still exists.

WCF Rest GET with multiple parameters

I have a WCF Rest Service and an OperationContract defined in the following way:
[ServiceContract]
public interface IMyService {
[OperationContract]
[WebInvoke( Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "get/{filename}" )]
MyFileStructure GetFile( string filename );
}
The Server stores some files and the GetFile() retrieves some information from the specified file in the GET request and put them in a MyFileStructure instance which is then JSON parsed and returned back to the client.
E.g. the user can get data from the file named myfile.xml, just typing the following on the browser: http://localhost:[port]/MyService.svc/get/myfile
(the file extension is always ".xml").
This works fine.
The question:
I now need to customize this request a bit more, passing some parameters to my file request. Basically, each stored XML file contains a set of attributes, which can be different (in attribute names and size) from file to file. Please notice that a domain of these attributes does not exist. Each parameter in the request should refer to a specific attribute of the specified file, but since the attributes defined in the file are not known, I cannot use the following:
[OperationContract]
[WebInvoke( Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "get/{filename}?param1={param1}" )]
MyFileStructure GetFile( string filename );
I would like to be able to pass my parameter list in a standard GET request, e.g.:
http://localhost:[port]/MyService.svc/get/myfile?myparam1=value1&myparam2_value2&...
but, at the same time being able to receive that as a single string/whatever object on the server side, in order to process the parameters based on the selected file. Is that possible? How?
You can receive a json object with any parameters you want or a key value pair object, like a dictionary, as it follows:
MyFileStructure GetFile( string filename, [FromBody]IDictionary<string, string> params);
And in javascript:
var parms = {};
parms['param1'] = "one";
parms['param2'] = "two";
$.ajax({
url: '/api/GetFile?filename=' + filename,
data: JSON.stringify(parms),
contentType: 'application/json'
type: 'POST',
dataType: 'json'
});
Hope it helps.
From the question I didn't understand if it is critical to use only GET requests or not.
But if it is, one more options could be usage of http headers. You can pass any header you want from the client, do then a GET request and then access these header in your service using weboperationcontext.current.incomingrequest.headers.
You can check here if some header specified and run some specific code for it, otherwise check another header and so on.
And yes WebAPI, is a kind of symbiosis of WCF and ASP.NET which is preferably now for RESTful API development. But you can use headers there as well.
I think it is not a good idea to use GET Http verb for method which takes a multiple parameters as input data. In this case I would recommend to use POST Http Verb. Something like that:
[OperationContract]
[WebInvoke( Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = **WebMessageBodyStyle.WrappedRequest**,
UriTemplate = "/getFiles" )]
MyFileStructure GetFile( List<string> filenames );
It will be a little bit comfortable to use and it also has a serious advantages over sending data via Get request such as safety. If you will have a lot of parameters you may lost some of them because of max length of url (which equal to 2000 characters). Using post request you can avoid this problem
My best bet is use a post request to do it. You can use Stream as parameter in method and which will gain you to read and save file stream and other data also.

POST method, error 400l bad request. asp.net

I'm trying to send data from my iPhone to a windows server 2008.
I found a tutorial, but I'm unfamiliar with asp.net.
So this is my code (in asp.net)
[OperationContract]
[WebInvoke(Method = "POST",
UriTemplate = "InsertEmployee?names={name}&lastnames={lastname}",
BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
//ResponseFormat = WebMessageFormat.Xml)]
//method
bool InsertEmployeeMethod(string name, string lastname);
//
and, I tried testing the installation with "postman", software that let me see the errors and checks in the Method. I sent a test of the code via postman.
And in Google, like this:
http://192.168.1.209/JsonWcfService/GetEmployees.svc/InsertEmployee?name=ildaguin&lastname=pregunton
That returns an Error 400 (Bad request).
How do I resolve this?
One way 400 Bad Request occurs is a syntax error. More details would be helpful including the message you are sending with Postman and the error returned if an error is returned.
If an error is not returned in Postman, then I would compare that to the message right before it is being sent in debug from your code. I can help you out with both if you can post additional details / code.
It is likely that you are missing some information or there is some spelling issue in the request, is a header variable required perhaps ( maybe Bearer token ). Are some words not case correct?
Good Luck

Is it possible to use both GET and POST in a same method?

I would like to know, in a wcf rest service is it possible to use both HTTP POST and HTTP Get in same method? I mean to say that a client page can either use post or get to invoke my method.
My client wants me to implement a method in this way.
As our API is a "RESTful" service we should be able to use both GET
and POST with this method. The parameter can be placed in the URL
of a GET request and also in the Header section of the GET request. When
using a HTTP POST with this method the parameter can be
stored in the header section or the body.
Is it possible?
Lets do it by writing code! Suppose you have a method!
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "Leads",
ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare)]
[WebGet(UriTemplate="/Leads")]
Result AddLeads(ReqLead[] rl); // This is our method.
When you will run your service, it will compiled and run successfully and browser will display you a page.
Now green arrow pointing is my Service name. By cliking on it will redirect you an error page and it will make an idea clear to you! See the image below.
I hope it will give you an idea. Moreover! In you [OperationContract] you will define only one method type, whether GET or POST. You can't have both.
Thanks

REST webservice "Bad request"

I'm writing a REST webservice having a method like this:
[WebGet(
UriTemplate = "/Test/{p1}/{p2}",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Xml)]
public string Test(string p1, string p2)
{
// Do something here
}
So if I call basurl/Test/prova/test my method Test is invoked with p1="prova" and p2="test" and everything works fine.
Problem comes when I try to use a param having (for example) % char: even translating it in URL code, when I try to call basurl/Test/prova/te%25st I get a
Errore HTTP 400 - Bad Request.
If I use
[WebGet(
UriTemplate = "/Test/{p1}?p2={p2}",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Xml)]
public string Test(string p1, string p2)
{
// Do something here
}
and call basurl/Test/prova?p2=te%25st it works.
Why? What can I do to let first syntax work?
UPDATE:
Look at my answer with a possible solution.
If someone finds a better one, please post it!!
Thanks
Googling around I've just found this link:
http://weblogs.asp.net/imranbaloch/archive/2010/04/23/understanding-400-bad-request-exception.aspx
where they say:
ASP.NET Restrictions:
After passing the restrictions enforced by the kernel mode http.sys then the request is handed off to IIS and then to ASP.NET
engine and then again request has to pass some restriction from
ASP.NET in order to complete it successfully.
ASP.NET only allows URL path lengths to 260 characters(only paths, for example http://a/b/c/d, here path is from a to d). This
means that if you have long paths containing 261 characters then you
will get the Bad Request exception. This is due to NTFS file-path
limit.
Another restriction is that which characters can be used in URL path portion.You can use any characters except some characters
because they are called invalid characters in path. Here are some of
these invalid character in the path portion of a URL, <,>,*,%,&,:,\,?.
For confirming this just right click on your Solution Explorer and Add
New Folder and name this File to any of the above character, you will
get the message. Files or folders cannot be empty strings nor they
contain only '.' or have any of the following characters.....
For checking the above situation i have created a Web Application and put Default.aspx inside A%A folder (created from
windows explorer), then navigate to,
http://localhost:1234/A%25A/Default.aspx, what i get response from
server is the Bad Request exception. The reason is that %25 is the %
character which is invalid URL path character in ASP.NET. However you
can use these characters in query string.
The reason for these restrictions are due to security, for example with the help of % you can double encode the URL path portion
and : is used to get some specific resource from server.
So I'm starting to think that my problem is impossible to solve.
I'm sure that this problem is not present in some REST webservice written in PHP and hosted with Apache, so I think it's just a IIS/ASP "security" restriction I can't find a workaround for...
UPDATE WITH FINAL SOLUTION:
I found a solution here: read the article to understand everything.
You should know that it could be risky, so think well before using it.
<system.web>
<httpRuntime requestPathInvalidCharacters="" />
<pages validateRequest="false" />
</system.web>

Categories