How to base.RequestContext.ToOptimizedResultUsingCache() return string for Accept-Encoding: deflate? - servicestack

I do have following code...
and Accept-Encoding: deflate
public object Get(DTOs.Product request)
{
...
var sCache = base.RequestContext.ToOptimizedResultUsingCache(
this.CacheClient, cacheKey, expireInTimespan, () =>
{
// Business layer returns resultant dataset as XmlDocument
...
return sXML.InnerXml;
});
//returns ServiceStack.Common.Web.HttpResult;
return GenerateResp(sCache, base.Request.Headers["Accept"]);
}
Issue is base.RequestContext.ToOptimizedResultUsingCache returns ServiceStack.Common.Web.CompressedResult even though I am returning XML. I understand that Accept-Encoding: deflate causes RequestContext.CompressionType to deflate.
Above code works fine, when there is no Accept-Encoding (through fiddler test).
But, if the request comes from a browser, it would come as a Compressed, in this case how can I get sCache as string to pass it to GenerateResp?
Thanks for your help.

I am able to resolve the issue by modifying code to...
public object Get(DTOs.Product request)
{
...
var objCache = base.RequestContext.ToOptimizedResultUsingCache(
this.CacheClient, cacheKey, expireInTimespan, () =>
{
// Business layer returns resultant dataset as XmlDocument
...
return sXML.InnerXml;
});
string compressionType = base.RequestContext.CompressionType;
bool doCompression = compressionType != null;
string transformed = "";
if (doCompression)
{
byte[] bCache = ((ServiceStack.Common.Web.CompressedResult)(objCache)).Contents;
transformed = bCache.Decompress(base.RequestContext.CompressionType);
}
else
{
transformed = (string)objCache;
}
//returns ServiceStack.Common.Web.HttpResult;
//In GenerateResp, If compressionType contains "gzip" or "deflate", I compress back the response to respective compression, and add respective Content-Encoding to the header.
return GenerateResp(transformed, base.Request.Headers["Accept"], compressionType);
}
Thank you.

Related

Trigger notification after Computer Vision OCR extraction is complete

I am exploring Microsoft Computer Vision's Read API (asyncBatchAnalyze) for extracting text from images. I found some sample code on Microsoft site to extract text from images asynchronously.It works in following way:
1) Submit image to asyncBatchAnalyze API.
2) This API accepts the request and returns a URI.
3) We need to poll this URI to get the extracted data.
Is there any way in which we can trigger some notification (like publishing an notification in AWS SQS or similar service) when asyncBatchAnalyze is done with image analysis?
public class MicrosoftOCRAsyncReadText {
private static final String SUBSCRIPTION_KEY = “key”;
private static final String ENDPOINT = "https://computervision.cognitiveservices.azure.com";
private static final String URI_BASE = ENDPOINT + "/vision/v2.1/read/core/asyncBatchAnalyze";
public static void main(String[] args) {
CloseableHttpClient httpTextClient = HttpClientBuilder.create().build();
CloseableHttpClient httpResultClient = HttpClientBuilder.create().build();;
try {
URIBuilder builder = new URIBuilder(URI_BASE);
URI uri = builder.build();
HttpPost request = new HttpPost(uri);
request.setHeader("Content-Type", "application/octet-stream");
request.setHeader("Ocp-Apim-Subscription-Key", SUBSCRIPTION_KEY);
String image = "/Users/xxxxx/Documents/img1.jpg";
File file = new File(image);
FileEntity reqEntity = new FileEntity(file);
request.setEntity(reqEntity);
HttpResponse response = httpTextClient.execute(request);
if (response.getStatusLine().getStatusCode() != 202) {
HttpEntity entity = response.getEntity();
String jsonString = EntityUtils.toString(entity);
JSONObject json = new JSONObject(jsonString);
System.out.println("Error:\n");
System.out.println(json.toString(2));
return;
}
String operationLocation = null;
Header[] responseHeaders = response.getAllHeaders();
for (Header header : responseHeaders) {
if (header.getName().equals("Operation-Location")) {
operationLocation = header.getValue();
break;
}
}
if (operationLocation == null) {
System.out.println("\nError retrieving Operation-Location.\nExiting.");
System.exit(1);
}
/* Wait for asyncBatchAnalyze to complete. In place of this wait, can we trigger any notification from Computer Vision when the extract text operation is complete?
*/
Thread.sleep(5000);
// Call the second REST API method and get the response.
HttpGet resultRequest = new HttpGet(operationLocation);
resultRequest.setHeader("Ocp-Apim-Subscription-Key", SUBSCRIPTION_KEY);
HttpResponse resultResponse = httpResultClient.execute(resultRequest);
HttpEntity responseEntity = resultResponse.getEntity();
if (responseEntity != null) {
String jsonString = EntityUtils.toString(responseEntity);
JSONObject json = new JSONObject(jsonString);
System.out.println(json.toString(2));
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
There is no notification / webhook mechanism on those asynchronous operations.
The only thing that I can see right know is to change the implementation you mentioned by using a while condition which is checking regularly if the result is there or not (and a mechanism to cancel waiting - based on maximum waiting time or number of retries).
See sample in Microsoft docs here, especially this part:
// If the first REST API method completes successfully, the second
// REST API method retrieves the text written in the image.
//
// Note: The response may not be immediately available. Text
// recognition is an asynchronous operation that can take a variable
// amount of time depending on the length of the text.
// You may need to wait or retry this operation.
//
// This example checks once per second for ten seconds.
string contentString;
int i = 0;
do
{
System.Threading.Thread.Sleep(1000);
response = await client.GetAsync(operationLocation);
contentString = await response.Content.ReadAsStringAsync();
++i;
}
while (i < 10 && contentString.IndexOf("\"status\":\"Succeeded\"") == -1);
if (i == 10 && contentString.IndexOf("\"status\":\"Succeeded\"") == -1)
{
Console.WriteLine("\nTimeout error.\n");
return;
}
// Display the JSON response.
Console.WriteLine("\nResponse:\n\n{0}\n",
JToken.Parse(contentString).ToString());

Unity WWW Text response is garbled

I am using the sample code from the Unity website for the WWW class to make an API request but the text response is garbage. It looks like ����. When I log the response headers, I get a 200 response and everything seems ok except that the CONTENT-TYPE is image/jpeg. I have tried several different random .json files to test it out and they all return the same thing. Requesting an image to use as a texture does work.
public class SpeechReq : MonoBehaviour {
//public string url = "https://gist.githubusercontent.com/wethecode/1f79baf168680afb0f2d/raw/755f9fb71dcc34df811b4bc26448d88a0f97f34d/snippets.json";
public string url = "https://gist.githubusercontent.com/damienh/fea91ab710475d499a09/raw/893065428badd8bfdc7b39fe17675b8aa031ac51/gistfile1.json";
IEnumerator Start()
{
WWW www = new WWW(url);
yield return www;
string respText = www.text;
Debug.Log(respText);
//Output: ����
byte[] resp = www.bytes;
var str = System.Text.Encoding.Default.GetString(resp);
Debug.Log(str);
//Output: ÿØÿà
if (www.responseHeaders.Count > 0)
{
foreach (KeyValuePair<string, string> entry in www.responseHeaders)
{
Debug.Log(entry.Value + "=" + entry.Key);
//Output: HTTP/1.0 200 OK=STATUS
//...
//image/jpeg=CONTENT-TYPE
}
}
}
}
The WWW class's .text method returns the UTF8 Byte Order Mark at the beginning of the response by default. See a description of the BOM here
You could try:
string jsonText = "";
if (string.IsNullOrEmpty(www.error))
{
jsonText = System.Text.Encoding.UTF8.GetString(www.bytes, 3, www.bytes.Length - 3); // Skip the UTF8 BOM
JSONObject myObject = new JSONObject(jsonText);
}

Gaelyk: returned truncated JSON

I am "piping" a json feed (in some cases quite big) that is returned from an external service, to hide an access api-key to the client (the access key is the only available authentication system for that service).
I am using Gaelyk and I wrote this groovlet:
try {
feed(params.topic)
} catch(Exception e) {
redirect "/failure"
}
def feed(topic) {
URL url = new URL("https://somewhere.com/$topic/<apikey>/feed")
def restResponse = url.get()
if (restResponse.responseCode == 200) {
response.contentType = 'application/json'
out << restResponse.text
}
}
The only problem is that the "restResponse" is very big and the value returned by the groovlet is truncated. So I will get back a json like this:
[{"item":....},{"item":....},{"item":....},{"ite
How can I return the complete json without any truncation?
Well I found the solution and the problem was at the beginning (the URL content must be read as stream). So the content truncated it was not the output but the input:
def feed(topic) {
URL url = "https://somewhere.com/$topic/<apikey>/feed".toURL()
def restResponse = url.get()
if (restResponse.responseCode == 200) {
response.contentType = 'application/json'
StringBuffer sb = new StringBuffer()
url.eachLine {
sb << it
}
out << sb.toString()
}
}

How to call PUT method from Web Api using HttpClient?

I want to call Api function (1st) . from 2nd Api function using HttpClient. But I always get 404 Error.
1st Api Function (EndPoint : http : // localhost : xxxxx /api/Test/)
public HttpResponseMessage Put(int id, int accountId, byte[] content)
[...]
2nd Api function
public HttpResponseMessage Put(int id, int aid, byte[] filecontent)
{
WebRequestHandler handler = new WebRequestHandler()
{
AllowAutoRedirect = false,
UseProxy = false
};
using (HttpClient client = new HttpClient(handler))
{
client.BaseAddress = new Uri("http://localhost:xxxxx/");
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var param = new object[6];
param[0] = id;
param[1] = "/";
param[2] = "?aid=";
param[3] = aid;
param[4] = "&content=";
param[5] = filecontent;
using (HttpResponseMessage response = client.PutAsJsonAsync("api/Test/", param).Result)
{
return response.EnsureSuccessStatusCode();
}
}
}
So My question is that. Can I post Method Parameter as an object array from HttpClient as I did ? I don't want to Pass model as method parameter.
What is the wrong in my code ?
Unable to get any response , after change code to
return client.PutAsJsonAsync(uri, filecontent)
.ContinueWith<HttpResponseMessage>
(
task => task.Result.EnsureSuccessStatusCode()
);
OR
return client.PutAsJsonAsync(uri, filecontent)
.ContinueWith
(
task => task.Result.EnsureSuccessStatusCode()
);
As you probably found out, no you can't. When you call PostAsJsonAsync, the code will convert the parameter to JSON and send it in the request body. Your parameter is a JSON array which will look something like the array below:
[1,"/","?aid",345,"&content=","aGVsbG8gd29ybGQ="]
Which isn't what the first function is expecting (at least that's what I imagine, since you haven't showed the route info). There are a couple of problems here:
By default, parameters of type byte[] (reference types) are passed in the body of the request, not in the URI (unless you explicitly tag the parameter with the [FromUri] attribute).
The other parameters (again, based on my guess about your route) need to be part of the URI, not the body.
The code would look something like this:
var uri = "api/Test/" + id + "/?aid=" + aid;
using (HttpResponseMessage response = client.PutAsJsonAsync(uri, filecontent).Result)
{
return response.EnsureSuccessStatusCode();
}
Now, there's another potential issue with the code above. It's waiting on the network response (that's what happens when you access the .Result property in the Task<HttpResponseMessage> returned by PostAsJsonAsync. Depending on the environment, the worse that can happen is that it may deadlock (waiting on a thread in which the network response will arrive). In the best case this thread will be blocked for the duration of the network call, which is also bad. Consider using the asynchronous mode (awaiting the result, returning a Task<T> in your action) instead, like in the example below
public async Task<HttpResponseMessage> Put(int id, int aid, byte[] filecontent)
{
// ...
var uri = "api/Test/" + id + "/?aid=" + aid;
HttpResponseMessage response = await client.PutAsJsonAsync(uri, filecontent);
return response.EnsureSuccessStatusCode();
}
Or without the async / await keywords:
public Task<HttpResponseMessage> Put(int id, int aid, byte[] filecontent)
{
// ...
var uri = "api/Test/" + id + "/?aid=" + aid;
return client.PutAsJsonAsync(uri, filecontent).ContinueWith<HttpResponseMessage>(
task => task.Result.EnsureSuccessStatusCode());
}

How can I use WebHttpRelayBinding with application/json requests?

When I try to use a generic message handler, I run into errors when the accept, or content-type is html/xml/json if I use my own type such as text/x-json everything works as expected the message is dispatched to my handlers and the stream returns the data to the webclient. I have stepped through this with a debugger and my code successfully creates the message but something in the servicebus binding chokes and causes the server not to respond. Is there a setting I need to change to allow application/json and make the service bus send raw data rather then trying to reserialize it?
[WebGet( UriTemplate = "*" )]
[OperationContract( AsyncPattern = true )]
public IAsyncResult BeginGet( AsyncCallback callback, object state )
{
var context = WebOperationContext.Current;
return DispatchToHttpServer( context.IncomingRequest, null, context.OutgoingResponse, _config.BufferRequestContent, callback, state );
}
public Message EndGet( IAsyncResult ar )
{
var t = ar as Task<Stream>;
var stream = t.Result;
return StreamMessageHelper.CreateMessage( MessageVersion.None, "GETRESPONSE", stream ?? new MemoryStream() );
}
Instead of using: StreamMessageHelper.CreateMessage, you can use the following one after you change :
WebOperationContext.Current.OutgoingResponse.ContentTYpe = "application/json"
public Message CreateJsonMessage(MessageVersion version, string action, Stream jsonStream)
{
var bodyWriter = new JsonStreamBodyWriter(jsonStream);
var message = Message.CreateMessage(version, action, bodyWriter);
message.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Json));
return message;
}
class JsonStreamBodyWriter : BodyWriter
{
Stream jsonStream;
public JsonStreamBodyWriter(Stream jsonStream)
: base(false)
{
this.jsonStream = jsonStream;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteNode(JsonReaderWriterFactory.CreateJsonReader(this.jsonStream, XmlDictionaryReaderQuotas.Max), false);
writer.Flush();
}
}

Resources