I have a web service where some clients are experiencing issues calling the app.
The issue relates to them passing in JSON, and specifying the Content-Type header as JSON, but the WCF service doesn't seem to accept that header, and either wants that header not to be set, or to be set to octet-stream.
The strange thing is, a separate web method works when the Content-Type header is set to application/json.
Here is the Attributes and declaration of the method I am having trouble with
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "events/{eventId}/devices/{deviceId}/setid?ac={ac}")]
OperationResult SetId(string eventId, string deviceId, string ac, Stream data);
And this is the attributes and declaration of the method which works
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "activate?deviceId={deviceID}")]
OperationResult<ActivationResult> ActivateDevice(string deviceID, Stream data);
Now I know they are 2 different methods, but the activate method works if I provide the Content-Type header of application/json, but the SetId method does not.
In the actual implementation of each method, the stream parameters are converted to the corresponding JSON class. Any ideas why this is not working for both?
The exception message is 'Incoming message for operation 'SetId' contains an unrecognized http body format value 'Json'. The expected body format value is 'Raw'.
Related
I am sending a post request from my flutter to a localhost api. However, the body on the server side is always empty/null. Whereas, if I send the exact same request on postman everything works fine.
String json = jsonEncode(toCheck);
Map<String,String> headers = {
"Accept": "application/json",
"content-type": "application/json",
};
var response = await http.post(
Uri.parse(userPath + 'validateUser/'),
headers: headers,
body: "{\"email\":\"david#hotmail.com\",\"username\":\"\",\"mobile_phone_number\":\"\",\"password\":\"david\"}");
print(response.statusCode);
if(response.statusCode == HttpStatus.ok){
return response.body as bool;
}
print(response.body.toString());
return false;
The status code is always 500 with the following error:
{"Message":"An error has occurred.","ExceptionMessage":"The value cannot be null"...
This error happens because the parameter "json" is null:
[HttpPost]
[Route("validateUser/", Name = "validadeUser")]
public async Task<IHttpActionResult> ValidateUser([FromBody] string json)
{
//get the username and password to validate the user
UserClient client = JsonConvert.DeserializeObject<UserClient>(json); //error happens here because the string json is null
//...
}
However, when making the same exact request on postman, everything is okay:
The host on the android emulator app is the following:
https://10.0.2.2:44304/api/user/validateUser/
PS: looks like a duplicate of Flutter POST request body is empty on server side and Flutter Dart HTTP POST request body is empty on server side but none of those solutions have worked for me, therefore I posting a new question.
It took me a while to spot the error... but in the end, I did!
Your API takes a String argument from the request body:
ValidateUser([FromBody] string json)
That may seem alright at first, since indeed, you are sending a json String as your request body. But the thing is that since you're also using these headers:
{
"Accept": "application/json",
"content-type": "application/json",
}
This bit: "content-type": "application/json" will translate your correctly formatted json String into an actual json Object! So when it reaches your API, it will no longer be a String, and so your API won't be able to receive it properly.
The solution would be to either remove the "content-type": "application/json" from your headers and keep the request body and the API function as they are, or to change the API to:
ValidateUser([FromBody] object json)
The latter is probably the most convenient, since you were going to parse it from json String to json Object anyway! đ
(With this API function, you COULD also remove your "content-type": "application/json" bit from the headers, and then send the request body like this:
body: jsonDecode("{\"email\":\"david#hotmail.com\",\"username\":\"\",\"mobile_phone_number\":\"\",\"password\":\"david\"}"),
Or just not jsonEncode it in the first place... Just send it as an object. This will have the same effect as sending it as a json String with "content-type": "application/json" in the header.)
Btw, as a general rule, make sure you add lots of print and log statements in your code as you develop it! It will help you spot anything that didn't go quite as you had expected, along the way. đ (That's how I spotted this.)
Before sending the request to the server please encode your object to complete the body property of the request. Try this:
body: json.encode({\"email\":\"david#hotmail.com\",\"username\":\"\",\"mobile_phone_number\":\"\",\"password\":\"david\"})
Cheers.
I have exposed calling WCF as Rest Service; I am able to call that specific Web Service with complex object. But one of the Property which is of type Dictionary is not getting serialized and becomes empty when it comes to WCF. I have provided more details in the code.
InFieldValuePair is dictonary
JSON Request :
{
"Requests":[
{
"AppRuleGroup":{
"AppId":0,
"AppName":"XXX",
"SubGroupId":0,
"SubGroupName":"Corporates - Investment Grade",
"GroupId":0,
"GroupName":"Workflow",
"ModuleId":0,
"ModuleName":"Trading",
"RulesLastUpdatedBy":null,
"EvalRules":[
]
},
"InputRequests":[
{
"Guid":"8592080a-6236-4b37-91b5-48c8a988950b",
"InFieldValuePair":{
"CurrentStatus":"Counter1",
"Direction":"Out"
}
}
],
"Guid":"a0f0fba0-bf3b-4d3d-adc8-416b5448b3df"
}
]
}
ABOUT
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
Task<List<RuleEvaluationResponse2>> Evaluate2(List<RuleEvaluationRequest2> Requests);
Expected Result is dictionary object should be populdated
First, please ensure that the property of the object has been decorated by [DataContract]/[DataMember].
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-data-contracts
Besides, if the T has contained other object, in order to ensure the serialization and deserialization works properly, we should consider using [KnownType] attribute.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-contract-known-types
We could use IExtensibleDataObject interface to handle situations where server and client data contracts are inconsistent, and unserialized members are properly serialized.
https://learn.microsoft.com/en-us/dotnet/api/system.runtime.serialization.iextensibledataobject?view=netframework-4.8
At last, when Data Items are too many. Please consider using the MaxItemsInObjectGraph property.
https://thinksimpleshirin.wordpress.com/2011/12/06/increasing-maxitemsinobjectgraph-wcf/
Feel free to let me know if the problem still exists.
Similar to this question, I need to send back JSON.
WCF ResponseFormat For WebGet
But I'm working from within a WCF Behavior being called by a BizTalk 2010 SendPort Adapter.
I'm inside this method:
public object BeforeSendRequest(ref Message request, IClientChannel channel)
So I have the Message and the channel that I can manipulate.
I think the direction is something like this:
1) //WebOperationContext.Current.OutgoingResponse.ContentType = âtext/plainâ;
or
2) OperationContext.Current.... something - but I don't know the object model well.
I'm currently using the MemoryStream:
byte[] byteArrayJSON = Encoding.UTF8.GetBytes(strJSON);
MemoryStream memStreamJSON = new MemoryStream(byteArrayJSON);
//WebOperationContext.Current.OutgoingResponse.ContentType = âtext/plainâ;
Message newMessage = Message.CreateMessage(MessageVersion.None, "", memStreamJSON);
...
request = newMessage; // substitute my new message for the original one.
My headers have this:
Content-Type: application/json
Accept: application/json
I think these are the lines I need, but still testing...
WebBodyFormatMessageProperty bodyFormat = new WebBodyFormatMessageProperty(WebContentFormat.Json);
newMessage.Properties.Add(WebBodyFormatMessageProperty.Name, bodyFormat);
It looks like maybe now I should pass XML and this will cause the serialization to happen? I'm now on to my next error:
System.ArgumentException: Encountered unexpected namespace 'http://schemas.datacontract.org/2004/07/System.IO'. The namespace must be empty.
Parameter name: ns
Going to try "raw":
WebBodyFormatMessageProperty bodyFormat = new WebBodyFormatMessageProperty(WebContentFormat.Json);
newMessage.Properties.Add(WebBodyFormatMessageProperty.Name, bodyFormat);
I am using Jersey 2.5.1 as jax-rs implementation and I use Moxy as JSON serialiser. I configured Jersey to print validation errors to output in web.xml.
<init-param>
<param-name>jersey.config.beanValidation.enableOutputValidationErrorEntity.server</param-name>
<param-value>true</param-value>
</init-param>
That works fine as validation errors are returned in plain text (text/plain). The problem is that I would like to get validation error messages in JSON format and according to Jersey documentation in order to do this a JSON provider must be configured to this. As far as I know it Moxy is configured as a JSON provider when its dependencies are attached to classpath. Unfortunately my validation errors are not returned in JSON (application/json) format. What can be wrong. Do I have to configure extra bits?
P.s.
when I debug ValidationExceptionMapper following code returns Variant object with media type text/plain
if (property != null && Boolean.valueOf(property.toString())) {
final List<Variant> variants = Variant.mediaTypes(
MediaType.TEXT_PLAIN_TYPE,
MediaType.TEXT_HTML_TYPE,
MediaType.APPLICATION_XML_TYPE,
MediaType.APPLICATION_JSON_TYPE).build();
final Variant variant = request.get().selectVariant(variants);
if (variant != null) {
response.type(variant.getMediaType());
} else {
// default media type which will be used only when none media type from {#value variants} is in accept
// header of original request.
// could be settable by configuration property.
response.type(MediaType.TEXT_PLAIN_TYPE);
}
response.entity(
new GenericEntity<List<ValidationError>>(
ValidationHelper.constraintViolationToValidationErrors(cve),
new GenericType<List<ValidationError>>() {}.getType()
)
);
}
As I mentioned in the comment the reason for not returning JSON format was due to the fact that I was sending header:
Accept: */*
It must be set to:
Accept: application/json
in order work properly.
I got a REST WCF Service running in .net 4 and I've tested the web service it is working and accepting HttpRequest I make to it. But I ran into a problem trying to access the HttpRequest body within the web service. I've tried sending random sizes of data appended on the HttpRequest using both Fiddler and my WinForm app and I can't seem to find any objects in runtime where I can find my request body is located. My initial instinct was to look in the HttpContext.Current.Request.InputStream but the length of that property is 0, so I tried looking in IncomingWebRequestContext that object doesn't even have a method nor properties to get the body of the HttpRequest.
So my question is, is there actually a way to access the HttpRequest request body in WCF?
PS:
The data inside the request body is JSON strings and for response it would return the data inside response body as JSON string too.
Much simpler, this answer on WCF + REST: Where is the request data? works fine.
Also, if your request body is deserializable, you can just pass a class. Barring some typos, this should work:
public class Banana
{
public string Colour;
public int Size;
}
...
[WebInvoke(
Method = "POST",
UriTemplate = "bananas",
ResponseFormat=WebMessageFormat.Json,
RequestFormat=WebMessageFormat.Json)]
string CreateBanana(Banana banana);
...
public string CreateBanana(Banana banana)
{
return "It's a " + banana.Colour + " banana!";
}
Doing POST with data {"Colour": "blue", "Size": 5} to this resource should return "It's a blue banana!".
Try with ((System.ServiceModel.Channels.BufferedMessageData)(((System.ServiceModel.Channels.BufferedMessage)((OperationContext.Current.RequestContext).RequestMessage)).MessageData)).Buffer
it has type System.ArraySegment<byte>
or read WCF + REST: Where is the request data?