ODataController and binary data - asp.net

What is the best way to support accepting of binary data on an ODataController (in .net)? The binary stream can be large, atleast 2MB. I have a controller derived from ODataController (System.Web.Http.Odata.OdataController).
How can I make this controller accept a Content-Type other than application/json (application/octet-stream perhaps)
I am using a base64 encoded string of the binary data in the upload. Is there a better approach?
What I have currently inside the ODataController is:
[HttpPut]
public float Put(string userId, string userType, [FromBody] string base64data)
Two pain points:
base64data parses as null, unless the string is wrapped in an object. For example, a body like "This is a string" results in a null. The body, "{"value":"This is a string"}" parses fine.
If I send more than 2MB of data, I again receive a null (with no errors).
What is the way to support binary data on an odata endpoint with higher allowed limits and efficient way?

How can I make this controller accept a Content-Type other than
application/json (application/octet-stream perhaps)
Use a custom media type formatter Checkout an example here...
I am using a base64 encoded string of the binary data in the upload.
Is there a better approach?
If you don't want to go through the custom media formatter route then you're better off posting your binary data as multipart/form-data. Sample here
base64data parses as null, unless the string is wrapped in an object.
For example, a body like "This is a string" results in a null. The
body, "{"value":"This is a string"}" parses fine.
This is because the default json media formatter expects a json string. However your custom media type formatter will take of raw string.
If I send more than 2MB of data, I again receive a null (with no
errors).
Because you're exceeding the max limit. You can change that using:
<configuration>
<appSettings>
<add key="aspnet:MaxJsonDeserializerMembers" value="1000" />
</appSettings>
</configuration>
Learn more here http://support.microsoft.com/kb/2661403

Related

BizTalk WCF-WebHttp URI mapping problem with escaped variable

I am trying to use BizTak WCF-WebHttp adapter to send to Service Desk Plus CMDB API using Variable Mapping.
When trying using the browser, it works fine. Service Desk Plus CMDB API requires an URI like (strictly shortened for readability):
http://host.com/api/cmdb/ci?OPERATION_NAME=read&TECHNICIAN_KEY=Mykey&format=XML&INPUT_DATA=<?xml version='1.0'?>
<API>
<name>email#host.com</name>
</API>
I have used the URI http://host.com/api/cmdb/ci and URL Mapping.
<BtsHttpUrlMapping>
<Operation Url="?OPERATION_NAME=read&TECHNICIAN_KEY=MyKey&format=XML&INPUT_DATA=<?xml version=&apos;1.0&apos;?>
<API>
<name>email#host.com</name>
</API>"/>
</BtsHttpUrlMapping>
This works fine, but I need a more dynamic approach. I tried using Variable Mapping, so I replaced the hard coded email address with a variable.
<BtsHttpUrlMapping>
<Operation Url="?OPERATION_NAME=read&TECHNICIAN_KEY=MyKey&format=XML&INPUT_DATA=<?xml version=&apos;1.0&apos;?>
<API>
<name>{email}</name>
</API>"/>
</BtsHttpUrlMapping>
Trying to save the URL Mapping with the variable I get an error.
WCF-WebHttp Transport Properties
Error saving properties.
(System.InvalidOperationException) The UriTemplate
?OPERATION_NAME=read&TECHNICIAN_KEY=MyKey&format=XML&INPUT_DATA=<?xml version='1.0'?><API><name>{email}</name></API>
is not valid; each portion of the query string must be of the form 'name=value', when value cannot be a compound segment. See the documentation for UriTemplate for more details.
If I try a variable that is not within the escaped XML string, like with the key, then it works fine.
<BtsHttpUrlMapping>
<Operation Url="?OPERATION_NAME=read&TECHNICIAN_KEY={key}&format=XML&INPUT_DATA=<?xml version=&apos;1.0&apos;?>
<API>
<value>email#host.com</value>
</API>"/>
</BtsHttpUrlMapping>
My intention is to be able to use a variable within the escaped XML string. If that is not possible; I will have to turn to a dynamic adapter and Create the URI and URL mapping in an orchestration.
Did u understand why it said each portion of the query string must be of the form 'name=value? There are just a few ways to make UriTemplates work.
See how a UriTemplate works here. Here is an example that is valid:
weather/{state}/{city}?forecast={day}
So in your case you should make everything after INPUT_DATA= a variable. Which means the whole escaped XML string you were talking about.

How does Servlet HttpServletResponse::setCharacterEncoding() work?

I have learned that in general, Java uses UTF-16 as the internal String representation.
My question is what actually happens when composing a response in Java and applying different char encoding, e.g. response.setCharacterEncoding("ISO-8859-1").
Does it actually convert the response's body bytes from UTF-16 to ISO-8859-1 or it just adds some metadata to the response object?
I'm assuming you're talking about a class that works along the lines of HttpServletResponse. If that's the case, then yes, it changes the body of the response, if you call getWriter. The writer that is returned by that has to convert any strings that are written to it into bytes, and the encoding is used for that.
If you've set the content type, then setting the content encoding will also make that information available via the Content-Type header. As per the ServletResponse docs:
Calling setContentType(java.lang.String) with the String of text/html and calling this method with the String of UTF-8 is equivalent with calling setContentType with the String of text/html; charset=UTF-8.

"<" character in JSON data is serialized to \u003c

I have a JSON object where the value of one element is a string. In this string there are the characters "<RPC>". I take this entire JSON object and in my ASP.NET server code, I perform the following to take the object named rpc_response and add it to the data in a POST response:
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
HttpContext.Current.Response.AddHeader("Pragma", "no-cache");
HttpContext.Current.Response.AddHeader("Cache-Control", "private, no-cache");
HttpContext.Current.Response.AddHeader("Content-Disposition", "inline; filename=\"files.json\"");
HttpContext.Current.Response.Write(serializer.Serialize(rpc_response));
HttpContext.Current.Response.ContentType = "application/json";
HttpContext.Current.Response.StatusCode = 200;
After the object is serialized, I receive it on the other end (not a web browser), and that particular string looks like: \u003cRPC\u003e.
What can I do to prevent these (and other) characters from not being encoded properly, still being able to serialize my JSON object?
The characters are being encoded "properly"!1 Use a working JSON library to correctly access the JSON data - it is a valid JSON encoding.
Escaping these characters prevents HTML injection via JSON - and makes the JSON XML-friendly. That is, even if the JSON is emited directly into JavaScript (as is done fairly often as JSON is a valid2 subset of JavaScript), it cannot be used to terminate the <script> element early because the relevant characters (e.g. <, >) are encoded within JSON itself.
The standard JavaScriptSerializer does not have the ability to change this behavior. Such escaping might be configurable (or different) in the Json.NET implementation - but, it shouldn't matter because a valid JSON client/library must understand the \u escapes.
1 From RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON),
Any character may be escaped. If the character is in the Basic Multilingual Plane (U+0000 through U+FFFF), then it may be represented as a six-character sequence: a reverse solidus, followed by the lowercase letter u, followed by four hexadecimal digits that encode the character's code point ..
See also C# To transform Facebook Response to proper encoded string (which is also related to the JSON escaping).
2 There is a rare case when this does not hold, but ignoring (or accounting for) that..

Character encoding issue with Spring MVC and HTML form

I'm working with spring mvc. I've set up a web form that has two simple text inputs. On controller, I use #ModelAttribute to let spring build the bean from the web form.
The problem comes when user puts on those text fields specials characters, like 酒店 and this kind of stuff, spring doesn't read it as utf-8, and they become the usual bad-encoded string.
I've checked web.xml and there's the utf-8 encoding filter, all pages are marqued as utf-8 and browser is sending right charset headers. Any idea on what's going on?
You may want to check this out:
http://forum.springsource.org/showthread.php?81858-ResponseBody-and-UTF-8
The short of it is that if you are using annotated methods then the messageconverter being used has a default character set. You can change this setting in your web.xml by setting the supported media types.
However, if your service doesn't like that media type, you may get a 406 error. You can create your own string message converter and set the default encoding, but there is no easy way with the built in HttpStringMessageConverter.
Alternately you can re-encode a string to a different character set:
String newresponse = new String(responseString.getBytes("ISO-8859-1"), "UTF-8");
You may also want to check out the related question here: How to get UTF-8 working in Java webapps?
the solution is simple by add produces = "text/plain;charset=UTF-8" to request mapping you can force spring mvc to encode the returned text.

Spring Integration - http outbound gateway custom headers

I have java object that I would like to pass as a custom header to my request on the http outbound gateway. Below is a snippet
<int:gateway id="service" service-interface="MyService" default-request-channel="requestChannel" default-reply-channel="replyChannel">
<int:method name="doSomething" payload-expression="#args[0] + ',' + #args[1]">
<int:header name="method_name" value="login"/>
<int:header name="service_identifier" value="myService"/>
</int:method>
</int:gateway>
<int:header-enricher input-channel="requestChannel" output-channel="gatewayChannel">
<int:header name="user_context" expression="T(UserContextHolder).getContext()"/>
</int:header-enricher>
<int-http:outbound-gateway request-channel="gatewayChannel" url="myURL" mapped-request-headers="user_context, service_identifier, method_name, HTTP_REQUEST_HEADERS"
http-method="POST" reply-channel="replyChannel"/>
Where UserContext could be a java object
UserContext implements Serializable {
String userId;
RequestParameters params;
ScopeEnum scope;
....
}
The problem I have is header user_context is not mapped in the header. From the logs, I can see that the DefaultHttpHeaderMapper is requesting for a Converter or ConversionService. See below -
09:54:59,488 - WARN main org.springframework.integration.http.support.DefaultHttpHeaderMapper - Header 'X- user_context' with value 'UserContextImpl#5e3ca754' will not be set since it is not a String and no Converter is available. Consider registering a Converter with ConversionService (e.g., <int:converter>)
How do I do this please ?
Thanks!
Standard HTTP headers are in key:value format and both key and value are strings.
You try to send object as a HTTP header value which is not very wise (and almost impossible because there may be some limits on the size of headers - for example 8KB Apache default limit).
You have three options:
Consider not using HTTP outbound gateway and use JMS instead (the best one in my opinion)
Add transformer which will serialize UserContext to String (if it was relatively short string it would be ok, in the other case I'd not recommend it)
Implement custom converter UserContext->String as described in section Datatype Channel Configuration of the spring reference documentation:
http://static.springsource.org/spring-integration/reference/htmlsingle/#channel-configuration

Resources