Using Dart to Download a PNG File (Binary File) and displaying it not working - dart

I have a rest API which I am calling to retrieve a PNG image to display on my page.
My Code:
void getProfilePicture(var pic_id) {
request = new HttpRequest();
request.responseType = "blob";
request.onReadyStateChange.listen(onPicture);
// Get Basic Auth credentials
var authorization = 'Basic '+storage.loginData['password'];
// Build JSON
Map reqData = new Map();
reqData['id'] = pic_id.toString();
reqData['type'] = 'WEB_SMALL';
// SEND the request to the server.
var url = sifted.serverAPI+'/api/v1/pictures/getpicture';
request.open('POST', url);
request.withCredentials = false;
request.setRequestHeader('Authorization',authorization);
request.setRequestHeader('Content-Type','application/json');
request.send(json.stringify(reqData));
}
void onPicture(_) {
if (request.readyState == HttpRequest.DONE &&
request.status == 200) {
Blob blob = new Blob(request.response);
FileReader reader = new FileReader();
reader.onLoad.listen((fe) {
ImageElement imgInput = query('#profilepic');
imgInput.src = reader.result;
});
reader.readAsDataUrl(blob);
}
}
It does not work and I get these errors in the Dart editor:
Exception: type 'Blob' is not a subtype of type 'List' of 'blobParts'.
Exception: type 'Blob' is not a subtype of type 'List' of 'blobParts'.
Any suggestions on what I am doing wrong?
Thank you !

The problem is this line:
Blob blob = new Blob(request.response);
The Blob constructor expects a List instead of another Blob (which request.response is in your use case): factory Blob(List blobParts, [String type, String endings])
Just delete the line, and directly call reader.readAsDataUrl(request.response), and it should work.

Related

Mirth HTTP POST request with Parameters using Javascript

The following code by #Nick Rupley works well, but, I need also to pass parameters as POST. How do we pass POST parameters?
from java.net.URL
var url = new java.net.URL('http://localhost/myphpscript.php');
var conn = url.openConnection();
var is = conn.getInputStream();
try {
var result = org.apache.commons.io.IOUtils.toString(is, 'UTF-8');
} finally {
is.close();
}
2 Parameters to pass: firstname="John" and lastname="Smith"
Thanks
This will POST with MIME type application/x-www-form-urlencoded. It is using apache httpclient, which is already included with mirth, as it is used internally by the HTTP Sender connector, as well as some other functionality. Other solutions may require you to download jars and add library resources.
Closer is part of Google Guava, which is also already included with mirth.
Check comments where Rhino javascript allows for simplified code compared to direct Java conversion.
It wouldn't be a bad idea to wrap all of this up in a code template function.
var result;
// Using block level Java class imports
with (JavaImporter(
org.apache.commons.io.IOUtils,
org.apache.http.client.methods.HttpPost,
org.apache.http.client.entity.UrlEncodedFormEntity,
org.apache.http.impl.client.HttpClients,
org.apache.http.message.BasicNameValuePair,
com.google.common.io.Closer))
{
var closer = Closer.create();
try {
var httpclient = closer.register(HttpClients.createDefault());
var httpPost = new HttpPost('http://localhost:9919/myphpscript.php');
// javascript array as java List
var postParameters = [
new BasicNameValuePair("firstname", "John"),
new BasicNameValuePair("lastname", "Smith")
];
// Rhino JavaBean access to set property
// Same as httpPost.setEntity(new UrlEncodedFormEntity(postParameters, "UTF-8"));
httpPost.entity = new UrlEncodedFormEntity(postParameters, "UTF-8");
var response = closer.register(httpclient.execute(httpPost));
// Rhino JavaBean access to get properties
// Same as var is = response.getEntity().getContent();
var is = closer.register(response.entity.content);
result = IOUtils.toString(is, 'UTF-8');
} finally {
closer.close();
}
}
logger.info(result);
Following is a complete working HTTP POST request solution tested in Mirth 3.9.1
importPackage(Packages.org.apache.http.client);
importPackage(Packages.org.apache.http.client.methods);
importPackage(Packages.org.apache.http.impl.client);
importPackage(Packages.org.apache.http.message);
importPackage(Packages.org.apache.http.client.entity);
importPackage(Packages.org.apache.http.entity);
importPackage(Packages.org.apache.http.util);
var httpclient = HttpClients.createDefault();
var httpPost = new HttpPost("http://localhost/test/");
var httpGet = new HttpGet("http://httpbin.org/get");
// FIll in each of the fields below by entering your values between the ""'s
var authJSON = {
"userName": "username",
"password": "password",
};
var contentStr =JSON.stringify(authJSON);
//logger.info("JSON String: "+contentStr);
httpPost.setEntity(new StringEntity(contentStr,ContentType.APPLICATION_JSON,"UTF-8"));
httpPost.setHeader('Content-Type', 'application/json');
httpPost.setHeader("Accept", "application/json");
// Execute the HTTP POST
var resp;
try {
// Get the response
resp = httpclient.execute(httpPost);
var statusCode = resp.getStatusLine().getStatusCode();
var entity = resp.getEntity();
var responseString = EntityUtils.toString(entity, "UTF-8");
var authHeader = resp.getFirstHeader("Authorization");
// logger.info("Key : " + authHeader.getName()+" ,Value : " + authHeader.getValue());
// Save off the response and status code to Channel Maps for any potential troubleshooting
channelMap.put("responseString", responseString);
channelMap.put("statusCode", statusCode);
// Parse the JSON response
var responseJson = JSON.parse(responseString);
// If an error is returned, manually throw an exception
// Else save the token to a channel map for use later in the processing
if (statusCode >= 300) {
throw(responseString);
} else {
logger.info("Token: "+ authHeader.getValue());
channelMap.put("token", authHeader.getValue());
}
} catch (err) {
logger.debug(err)
throw(err);
} finally {
resp.close();
}
This linke + above answers helped me to come up with a solution
https://help.datica.com/hc/en-us/articles/115005322946-Advanced-Mirth-Functionality
There are plenty of libraries that can help you with URI building in Java. You can find them below. But if you want to stay in Javascript just add your parameters manually than create it.
function addParam(uri, appendQuery) {
if (appendQuery != null) {
uri += "?" + appendQuery;
}
return uri;
}
var newUri = addParam('http://localhost/myphpscript.php', 'firstname="John"');
var url = new java.net.URL(newUri);
Java EE 7
import javax.ws.rs.core.UriBuilder;
...
return UriBuilder.fromUri(url).queryParam(key, value).build();
org.apache.httpcomponents:httpclient:4.5.2
import org.apache.http.client.utils.URIBuilder;
...
return new URIBuilder(url).addParameter(key, value).build();
org.springframework:spring-web:4.2.5.RELEASE
import org.springframework.web.util.UriComponentsBuilder;
...
return UriComponentsBuilder.fromUriString(url).queryParam(key, value).build().toUri();
There are multiple ways to provide http client connection with java. Since your question is specific to java.net.URL I will stick to that.
Basically you can pass parameters as POST, GET, PUT, DELETE using .setRequestMethod this will be used along with new java.net.URL(ur-destination-url).openConnection();
Here is the complete code I've using javascript in Mirth using the same java.net.URL use this it will be helpful. It worked well for me.
do {
try {
// Assuming your writing this in the destination Javascript writer
var data = connectorMessage.getEncodedData();
//Destination URL
destURL = “https://Your-api-that-needs-to-be-connected.com”;
//URL
var url = new java.net.URL(destURL);
var conn = url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
enter code here
conn.setRequestProperty (“Authorization”, globalMap.get(‘UniversalToken’));
conn.setRequestMethod(“DELETE”); // this can be post or put or get or patch
conn.setRequestProperty(“Content-length”, data.length());
conn.setRequestProperty(“Content-type”, “application/json”);
var outStream = conn.getOutputStream();
var outWriter = new java.io.OutputStreamWriter(outStream);
outWriter.write(data);
outWriter.close();
// Get response Code (200, 500 etc.)
var respCode = conn.getResponseCode();
if (respCode != 200) {
// Write error to error folder
var stringData = response.toString() + “\n”;
FileUtil.write(“C:/Outbox/Errors/” + $(“originalFilename”) + “.ERROR_RESPONSE”, false, stringData);
// Return Error to Mirth to move the file to the error folder
return ERROR;
}
errorCond = “false”;
break;
}
catch(err) {
channelMap.put(“RESPONSE”, err);
responseMap.put(“WEBSVC”, ResponseFactory.getErrorResponse(err))
throw(err);
// Can return ERROR, QUEUED, SENT
// This re-queues the message on a fatal error. I”m doing this since any fatal message may be
// caused by HTTPS connect errors etc. The message will be re-queued
return QUEUED; // Re-queue the message
java.lang.Thread.sleep(6000); // 6 seconds * 10
errorCond = “true”;
}
}
while (errorCond == “true”);

How to upload a small file plus metadata with GraphServiceClient to OneDrive with a single POST request?

I would like to upload small files with metadata (DriveItem) attached so that the LastModifiedDateTime property is set properly.
First, my current workaround is this:
var graphFileSystemInfo = new Microsoft.Graph.FileSystemInfo()
{
CreatedDateTime = fileSystemInfo.CreationTimeUtc,
LastAccessedDateTime = fileSystemInfo.LastAccessTimeUtc,
LastModifiedDateTime = fileSystemInfo.LastWriteTimeUtc
};
using (var stream = new System.IO.File.OpenRead(localPath))
{
if (fileSystemInfo.Length <= 4 * 1024 * 1024) // file.Length <= 4 MB
{
var driveItem = new DriveItem()
{
File = new File(),
FileSystemInfo = graphFileSystemInfo,
Name = Path.GetFileName(item.Path)
};
try
{
var newDriveItem = await graphClient.Me.Drive.Root.ItemWithPath(item.Path).Content.Request().PutAsync<DriveItem>(stream);
await graphClient.Me.Drive.Items[newDriveItem.Id].Request().UpdateAsync(driveItem);
}
catch (Exception ex)
{
throw;
}
}
else
{
// large file upload
}
}
This code works by first uploading the content via PutAsync and then updating the metadata via UpdateAsync. I tried to do it vice versa (as suggested here) but then I get the error that no file without content can be created. If I then add content to the DriveItem.Content property, the next error is that the stream's ReadTimeout and WriteTimeout properties cannot be read. With a wrapper class for the FileStream, I can overcome this but then I get the next error: A stream property 'content' has a value in the payload. In OData, stream property must not have a value, it must only use property annotations.
By googling, I found that there is another way to upload data, called multipart upload (link). With this description I tried to use the GraphServiceClient to create such a request. But it seems that this is only fully implemented for OneNote items. I took this code as template and created the following function to mimic the OneNote behavior:
public static async Task UploadSmallFile(GraphServiceClient graphClient, DriveItem driveItem, Stream stream)
{
var jsondata = JsonConvert.SerializeObject(driveItem);
// Create the metadata part.
StringContent stringContent = new StringContent(jsondata, Encoding.UTF8, "application/json");
stringContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("related");
stringContent.Headers.ContentDisposition.Name = "Metadata";
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// Create the data part.
var streamContent = new StreamContent(stream);
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("related");
streamContent.Headers.ContentDisposition.Name = "Data";
streamContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
// Put the multiparts together
string boundary = "MultiPartBoundary32541";
MultipartContent multiPartContent = new MultipartContent("related", boundary);
multiPartContent.Add(stringContent);
multiPartContent.Add(streamContent);
var requestUrl = graphClient.Me.Drive.Items["F4C4DC6C33B9D421!103"].Children.Request().RequestUrl;
// Create the request message and add the content.
HttpRequestMessage hrm = new HttpRequestMessage(HttpMethod.Post, requestUrl);
hrm.Content = multiPartContent;
// Send the request and get the response.
var response = await graphClient.HttpProvider.SendAsync(hrm);
}
With this code, I get the error Entity only allows writes with a JSON Content-Type header.
What am I doing wrong?
Not sure why the provided error occurs, your example appears to be a valid and corresponds to Request body example
But the alternative option could be considered for this matter, since Microsoft Graph supports JSON batching, the folowing example demonstrates how to upload a file and update its metadata within a single request:
POST https://graph.microsoft.com/v1.0/$batch
Accept: application/json
Content-Type: application/json
{
"requests": [
{
"id":"1",
"method":"PUT",
"url":"/me/drive/root:/Sample.docx:/content",
"headers":{
"Content-Type":"application/octet-stream"
},
},
{
"id":"2",
"method":"PATCH",
"url":"/me/drive/root:/Sample.docx:",
"headers":{
"Content-Type":"application/json; charset=utf-8"
},
"body":{
"fileSystemInfo":{
"lastModifiedDateTime":"2019-08-09T00:49:37.7758742+03:00"
}
},
"dependsOn":["1"]
}
]
}
Here is a C# example
var bytes = System.IO.File.ReadAllBytes(path);
var stream = new MemoryStream(bytes);
var batchRequest = new BatchRequest();
//1.1 construct upload file query
var uploadRequest = graphClient.Me
.Drive
.Root
.ItemWithPath(System.IO.Path.GetFileName(path))
.Content
.Request();
batchRequest.AddQuery(uploadRequest, HttpMethod.Put, new StreamContent(stream));
//1.2 construct update driveItem query
var updateRequest = graphClient.Me
.Drive
.Root
.ItemWithPath(System.IO.Path.GetFileName(path))
.Request();
var driveItem = new DriveItem()
{
FileSystemInfo = new FileSystemInfo()
{
LastModifiedDateTime = DateTimeOffset.UtcNow.AddDays(-1)
}
};
var jsonPayload = new StringContent(graphClient.HttpProvider.Serializer.SerializeObject(driveItem), Encoding.UTF8, "application/json");
batchRequest.AddQuery(updateRequest, new HttpMethod("PATCH"), jsonPayload, true, typeof(Microsoft.Graph.DriveItem));
//2. execute Batch request
var result = await graphClient.SendBatchAsync(batchRequest);
var updatedDriveItem = result[1] as DriveItem;
Console.WriteLine(updatedDriveItem.LastModifiedDateTime);
where SendBatchAsync is an extension method which implements JSON Batching support for Microsoft Graph .NET Client Library

Object reference not set to an object while file upload in OneDrive

I am using Microsoft Graph SDK to upload file in chunks in OneDrive. I am using below code to upload the file:
try
{
GraphServiceClient graphClient = this.GetGraphServiceClient(accessToken);
string fileName = Path.GetFileName(srcFilePath);
using (var fileContentStream = System.IO.File.Open(srcFilePath, System.IO.FileMode.Open))
{
var uploadSession = await graphClient.Me.Drive.Root.ItemWithPath(fileName).CreateUploadSession().Request().PostAsync();
var maxChunkSize = 5 * 1024 * 1024;
var provider = new ChunkedUploadProvider(uploadSession, graphClient, fileContentStream, maxChunkSize);
var chunkRequests = provider.GetUploadChunkRequests();
var readBuffer = new byte[maxChunkSize];
var trackedExceptions = new List<Exception>();
Microsoft.Graph.DriveItem itemResult = null;
foreach (var request in chunkRequests)
{
var result = await provider.GetChunkRequestResponseAsync(request, readBuffer, trackedExceptions);
if (result.UploadSucceeded)
{
itemResult = result.ItemResponse;
}
}
}
}
catch (Microsoft.Graph.ServiceException e)
{
}
catch (Exception ex)
{
}
The above code works fine with normal file names. However, when I am trying to upload a file with name as Test#123.pdf, "Object reference not set to an object" exception is thrown at line var provider = new ChunkedUploadProvider(uploadSession, graphClient, fileContentStream, maxChunkSize); Please see below screenshot:
Is this a limitation of OneDrive SDK, or am I not passing the parameters correctly?
The # sign has a special meaning in a URL. Before you can use it, you'll need to URL Encode the file name: Test%23123.pdf.

Pdf missing signature after uploading from ASP.NET MVC XMLHttpRequest

I'm working on a ASP.NET MVC page to let users upload a Pdf document once they have digitally signed it.
But for some reason the signature is destroyed when uploading the document even when it's graphic representation is properly displayed.
Here is the code I use to upload the file:
$(document).on('click', 'input[value=Upload]', function (e, argument) {
var formdata = new FormData();
for (i = 0; i < document.getElementById('FileBox').files.length; i++) {
formdata.append(document.getElementById('FileBox').files[i].name, document.getElementById('FileBox').files[i]);
}
var url = '#Url.Action("Upload", "Test")'
var xhr = new XMLHttpRequest();
xhr.open('POST', url);
xhr.send(formdata);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var response = $.parseJSON(xhr.response);
alert(response.result);
}
}
});
I'm retrieving the uploaded files in the controller as follows:
Public Function PostedFiles() As List(Of Byte())
Dim retval As New List(Of Byte())
Dim oRequest As HttpRequest = Web.HttpContext.Current.Request
For Each sFileKey As String In oRequest.Files
Dim oFile As HttpPostedFile = oRequest.Files(sFileKey)
If oFile.ContentLength > 0 Then
Dim iLength As Integer = oFile.ContentLength
Dim oBytes(iLength) As Byte
Dim oStream As System.IO.Stream = oFile.InputStream()
oStream.Read(oBytes, 0, iLength)
retval.Add(oBytes)
End If
Next
Return retval
End Function
After persisting the byte arrays in a SQL server database, when I take them back from the database there is no longer any signature, just the graphic representation of it.
Thanks Mkl for your comment, I realize I was getting no signature since the document was displayed in the browser. Opening the persisted file in Acrobat Reader successfully shows the signature.

How to make ol.source.ImageWMS send POST request

In our project, we're using OpenLayers-3's ol.source.ImageWMS to show image provided by Mapserver WMS. Since we're using Mapserver runtime substitution, our request can become quite long, which could cause a problem for a GET request.
Is there a way to make ol.source.ImageWMS send POST request?
I answer this just for the reference based on this Openlayers dev thread, hopefully it will help someone in the future!. I needed to pass a very long CQL request to a Geoserver wms, and GET was limited in size, so I used POST like the following:
var POSTWMSLayer = new ol.layer.Image({
source: new ol.source.ImageWMS({
url: 'https://test.server.com/geoserver/wms',
params: {
'LAYERS': 'firstworkspace:states',
'CQL_FILTER':'gid IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159)
},
serverType: 'geoserver',
imageLoadFunction: function (image, src) {
var img = image.getImage();
if (typeof window.btoa === 'function') {
var urlArray = src.split("?");
var url = urlArray[0];
var params = urlArray[1];
var xhr = new XMLHttpRequest();
xhr.onload = function (e) {
if (this.status === 200) {
var uInt8Array = new Uint8Array(this.response);
var i = uInt8Array.length;
var binaryString = new Array(i);
while (i--) {
binaryString[i] = String.fromCharCode(uInt8Array[i]);
}
var data = binaryString.join('');
var type = xhr.getResponseHeader('content-type');
if (type.indexOf('image') === 0) {
img.src = 'data:' + type + ';base64,' + window.btoa(data);
}
}
};
xhr.open('POST', url, true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.responseType = 'arraybuffer';
xhr.send(params);
} else {
img.src = src;
}
}
})
});
Actually the httprequest is the problem, use Httprequest Post method instead of get method in ol.source.ImageWMS?
Get request can not pass long string parameters. For big parameters we need to pass request with post method.
Now the bottleneck is that the post method is not supported in openlayers 3 whereas in old version it had support for post method.
Note: This is old OpenLayers code
var query = new OpenLayers.Layer.WMS.Post("My Layer",
'http://192.168.6.51:8090/geoserver/VP/wms', {
LAYERS : 'Namespace:LayerName',
sld_body : strSld_body,
format : 'image/jpeg',
transparent : 'true'
},
{
unsupportedBrowsers: [],
isBaseLayer: false,
yx : {'EPSG:4326' : true}
} );
In openlayers 3 there may be a workaround.

Resources