How to get string from dataPackageView.GetDataAsync() - c#

I'm trying to get non-standard-format data from the clipboard using DataPackageView.GetDataAsync. I am stumped on converting the returned system.__ComObject to a string.
Here is the code:
var dataPackageView = Windows.ApplicationModel.DataTransfer.Clipboard.GetContent();
if (dataPackageView.Contains("FileName"))
{
var data = await dataPackageView.GetDataAsync("FileName");
// How to convert data to string?
}
I am looking for a solution that will work with any non-standard clipboard format. "FileName" is an easily testable format as you can put it on the clipboard by copying a file in Windows Explorer.
In C++/Win32, I can get the clipboard data as follows:
OpenClipboard(nullptr);
UINT clipboarFormat = RegisterClipboardFormat(L"FileName");
HANDLE hData = GetClipboardData(clipboarFormat);
char * pszText = static_cast<char*>(GlobalLock(hData));
GlobalUnlock(hData);
CloseClipboard();
In C++, the clipboard data is just an array of bytes. It must be possible to get the same array of bytes in C#, but I have no clue on unwrapping/converting the system.__ComObject
Edit: Rephrasing the question:
How do I get a string or array of byes out of the system.__ComObject returned by dataPackageView.GetDataAsync(someFormat), where someFormat is an arbitrary clipboard format created by another application?
It is very clear to me how to get the data. The difficult part is using the data that is returned.
The accepted answer must show how to create a string or array of bytes from the "data" returned by
var data = await dataPackageView.GetDataAsync(someFormat);

if you know its a file you can use the following code
var content = Clipboard.GetContent();
IReadOnlyList<IStorageItem> files = await content.GetStorageItemsAsync();
var file = files.First() as StorageFile;
From MSDN article on StandardDataFormats
The DataPackage class supports a number of legacy formats for interoperability between Windows Store apps and desktop apps. To retrieve these formats, you pass one of the following strings to the DataPackageView.GetDataAsync method instead of a value from the StandardDataFormats class.
eg
var content = Clipboard.GetContent();
var data = await content.GetDataAsync("PenData"); //Stream for HGLOBAL corresponding to CF_PENDATA

This article explains how custom dataPackage objects are implemented.
http://www.minddriven.de/index.php/technology/dot-net/c-sharp/winrt-datapackage-custom-objects
The key is to cast the return value of dataPackageView.GetAsync() into an IRandomAccessStream
Here is something that works:
var dataPackageView = Windows.ApplicationModel.DataTransfer.Clipboard.GetContent();
if (dataPackageView.Contains("FileName"))
{
var data = await dataPackageView.GetDataAsync("FileName");
// convert data to string
var data = await dataPackageView.GetDataAsync("FileName");
var dataObj = data as IRandomAccessStream;
var stream = dataObj.GetInputStreamAt(0);
IBuffer buff = new Windows.Storage.Streams.Buffer((uint)dataObj.Size);
await stream.ReadAsync(buff, (uint)dataObj.Size, InputStreamOptions.None);
var filePath = Encoding.ASCII.GetString(buff.ToArray());
filePath = filePath.Replace("\0","");//get rid of null characters
}
This should work for any custom data format, not just "FileName". If you do not require a string, you could just use the bytes available from the IRandomAccessStream.

Related

How use the Byte Array of a image?

So, i am getting the byte array of a LongRaw image from Oracle...
I am using a webapi to this. After get the array, how i use it on the Client-side ?
Do Its better i convert to base64string and pass this value converting just at the client side ?
cmd.InitialLONGFetchSize = -1;
var reader = cmd.ExecuteReader();
if (reader.Read())
{
// Fetch the LONG RAW
OracleBinary imgBinary = reader.GetOracleBinary(0);
// Get the bytes from the binary obj
byte[] imgBytes = imgBinary.IsNull ? null : imgBinary.Value;
//var imgString = Uri.EscapeDataString(Convert.ToBase64String(imgBytes));
}
//CRIO A LISTA
lretorno.Load(reader, LoadOption.OverwriteChanges, "BUSCAFOTO");
reader.Close();
connection.Close();
connection.Dispose();
var teste = lretorno.Tables[0].AsEnumerable().Select(row => new FotoEnvolvido
{
FOTO = (byte[])(row["FOTO"]),
//FOTO = Convert.ToString(row["FOTO"]),
});
return teste;
You can write a Web API Controller that returns the binary data of an image. Base64 strings impose a overhead of the amount of bytes that have to be transmitted. Please avoid this.
A sample controller can look like this example:
public class WebApiController : ApiController
{
public async Task<HttpResponseMessage> Get(string id)
{
var bytes = await GetBytesFromDataLayerAsync(id);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new MemoryStream(bytes);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("image/jpeg");
return result;
}
private async Task<byte[]> GetBytesFromDataLayerAsync(string id)
{
// put your Oracle logic here
return ...
}
}
Depending on what your doing as rboe said writing the bytes directly to the client will save some data size(approx. 37%) and computing overhead. If your not only displaying jpeg images you should also set the mime-type to the correct value... take a look at this source for a rather complete set of extension to mime-type mappings. If you do not know the mime-type you can try "application/octet-stream" as that is the general mime-type for binary data.
If your displaying your content via web browser you could just use an <img> tag something like <img src="view_image.aspx?id=5"> you can even create the dynamically with javascript/jQuery.
If you really do want the image data embedded in a json request which might be useful if you have a lot of little icons and don't want a ton of requests (with http/2 I don't think this will matter) or another reason, then yes first encode the binary data using...
string base64EncodedData = Convert.ToBase64String(bytes);
If the client is javascript you can decode using the latest browsers native functions
var decodedImageData = window.atob(base64EncodedData);
See:
mozilla.org docs
This answer
This answer
If you are however just sending it to another c# endpoint you can use...
byte[] decodedImageData = Convert.FromBase64String(base64EncodedData);
And like I mentioned in the comment to ensure it's encrypted just make the site only support https:// and if you don't have a SSL cert you can get one for free from http://startssl.com

My stream keeps throwing Read/Write Timeout exceptions

I am parsing a PowerPoint presentation using Open Office SDK 2.0. At one point in the program I'm passing a stream to a method that will return an image's MD5. However, there seems to be a problem in the stream, before it even gets to my MD5 method.
Here's my code:
// Get image information here.
var blipRelId = blip.Embed;
var imagePart = (ImagePart)slidePart.GetPartById(blipRelId);
var imageFileName = imagePart.Uri.OriginalString;
var imageStream = imagePart.GetStream();
var imageMd5 = Hasher.CalculateStreamHash(imageStream);
In debug, before I let it drop into Hasher.CalculateStreamHash, I check the imageStream properties. Immediately, I see that the ReadTimeout and WriteTimeout both have similar errors:
imageStream.ReadTimeout' threw an exception of type 'System.InvalidOperationException
imageStream.WriteTimeout' threw an exception of type 'System.InvalidOperationException
Here's a picture of the properties that I"m seeing during debug, in case it helps:
This code is running over a PowerPoint presentation. I'm wondering if the fact that it's zipped (a PowerPoint presentation is basically just a zipped up file) is the reason I'm seeing those timeout errors?
UPDATE: I tried taking the stream, getting the image and converting it to a byte array and sending that to the MD5 method as a memory stream, but I still get those same errors in the Read/Write Timeout properties of the stream. Here's the code as it is now:
// Get image information here.
var blipRelId = blip.Embed;
var imagePart = (ImagePart)slidePart.GetPartById(blipRelId);
var imageFileName = imagePart.Uri.OriginalString;
var imageStream = imagePart.GetStream();
// Convert image to memory stream
var img = Image.FromStream(imageStream);
var imageMemoryStream = new MemoryStream(this.imageToByteArray(img));
var imageMd5 = Hasher.CalculateStreamHash(imageMemoryStream);
For clarity, here's the signature for the CalculateStreamHash method:
public static string CalculateStreamHash([NotNull] Stream stream)
Mischief managed! I was able to overcome this problem by using a BufferedStream and adding an overloaded method to my MD5 method that accepted a BufferedStream as a parameter:
// Get image information here.
var blipRelId = blip.Embed;
var imagePart = (ImagePart)slidePart.GetPartById(blipRelId);
var imageFileName = imagePart.Uri.OriginalString;
// Convert image to buffered stream
var imageBufferedStream = new BufferedStream(imagePart.GetStream());
var imageMd5 = Hasher.CalculateStreamHash(imageBufferedStream);
...and:
public static string CalculateStreamHash([NotNull] BufferedStream bufferedStream)

reading a web api blob into a string that I can send as part of a json object to the server and turn back into a file

i'm trying to turn a wav file into a string I can send to the server as a part of a json object, so that on the server I can turn that string back into a file.
i have tried to use readAsBinaryString and read as text, can't get past error in reading the string into a byte array.
reader.onloadend = saveMedia;
reader.readAsText(Blob);
//reader.readAsBinaryString(Blob); also tried.
then the callback sends an ajax request with an object holding the string in "reader.result" and on the server i tried things like:
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] BinaryData = encoding.GetBytes(stringFromRequest);
the answers to this question below seem to be that this should not be done. but i really want to do it this way because of another tool I am using (breeze js). don't want to use a separate post action with a file data type.
releted:
File API - Blob to JSON
Found a way that works:
var reader = new FileReader();
reader.onloadend = afterRead;
reader.readAsBinaryString(blob);
function afterRead() {
// convert binary string to base64 for a safe transfer to the server.
entity.BinaryProp = window.btoa(reader.result);
}
on the server-side:
string BinaryString = (string)entityInfo.UnmappedValuesMap["BinaryProp"];
byte[] BinaryData = Convert.FromBase64String(BinaryString);
You can use fileReader.readAsDataURL(fileObject), this encode blob to base64, which can safely upload to server by API.
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
let thumbnail = reader.result;
console.log(thumbnail)
//send to API
};
The answer above is great, but there is a simpler way.
var reader = new FileReader();
reader.onloadend = afterRead;
reader.readAsDataURL(blob); // Use this function instead
function afterRead() {
entity.BinaryProp = reader.result; //result is already a base64 string!
}
See documentation here: FileReader.readAsDataURL()

How to read string from HttpRequest form data in correct encoding

Today I have done a service to receive emails from SendGrid and finally have sent an email with a text "At long last", first time in non-English language during testing. Unfortunately, the encoding has become a problem that I cannot fix.
In a ServiceStack service I have a string property (in an input object that is posted to the service from SendGrid) in an encoding that is different from UTF8 or Unicode (KOI8-R in my case).
public class SengGridEmail : IReturn<SengGridEmailResponse>
{
public string Text { get; set; }
}
When I try to convert this string to UTF8 I get ????s, probably because when I access the Text property it is already converted into Unicode (.NET's internal string representation). This question and answer illustrate the issue.
My question is how to get original KOI8-R bytes within ServiceStack service or ASP.NEt MVC controller, so that I could convert it to UTF8 text?
Update:
Accessing base.Request.FormData["text"] doesn't help
var originalEncoding = Encoding.GetEncoding("KOI8-R");
var originalBytes = originalEncoding.GetBytes(base.Request.FormData["text"]);
But if I take base64 string from the original sent mail and convert it to byte[], and then convert those bytes to UTF8 string - it works. Either base.Request.FormData["text"] is already in Unicode .NET string format, or (less likely) it is something on SendGrid side.
Update 2:
Here is a unit test that shows what is happening:
[Test]
public void EncodingTest()
{
const string originalString = "наконец-то\r\n";
const string base64Koi = "zsHLz87Fwy3Uzw0K";
const string charset = "KOI8-R";
var originalBytes = base64Koi.FromBase64String(); // KOI bytes
var originalEncoding = Encoding.GetEncoding(charset); // KOI Encoding
var originalText = originalEncoding.GetString(originalBytes); // this is initial string correctly converted to .NET representation
Assert.AreEqual(originalString, originalText);
var unicodeEncoding = Encoding.UTF8;
var originalWrongString = unicodeEncoding.GetString(originalBytes); // this is how the KOI string is represented in .NET, equals to base.Request.FormData["text"]
var originalWrongBytes = originalEncoding.GetBytes(originalWrongString);
var unicodeBytes = Encoding.Convert(originalEncoding, unicodeEncoding, originalBytes);
var result = unicodeEncoding.GetString(unicodeBytes);
var unicodeWrongBytes = Encoding.Convert(originalEncoding, unicodeEncoding, originalWrongBytes);
var wrongResult = unicodeEncoding.GetString(unicodeWrongBytes); // this is what I see in DB
Assert.AreEqual(originalString, result);
Assert.AreEqual(originalString, wrongResult); // I want this to pass!
}
Discovered two underlying problems for my problem.
The first is from SendGrid - they post multi-part data without specifying content-type for non-unicode elements.
The second is from ServiceStack - currently it doesn't support encoding other than utf-8 for multi-part data.
Update:
SendGrid helpdesk promised to look into the issue, ServiceStack now fully support custom charsets in multi-part data.
As for initial question itself, one could access buffered stream in ServiceStack as described here: Can ServiceStack Runner Get Request Body?.

Getting Json Output from Byte Array

I just started a new project on WCF and to be honest I'm very new at this with limited knowledge.
So what I'm trying to do is open a file that is stored in my computer (e.g. word, pdf, etc.) and display the contents in the webpage in JSon format. I converted the file in a byte array and tried to display the Stream. When I did that it asked me to open the file or save it. I don't want that - I just want the contents of the file to be displayed on my local host when i call the method.
Here's what I have:
public string GetRawFile()
{
string file = #"C:\.....\TestFile.pdf";
byte[] rawFile = File.ReadAllBytes(file);
//Stream stream = new MemoryStream(rawFile);
//DataContractJsonSerializer obj = newDataContractJsonSerializer(typeof(string));
//string result = obj.ReadObject(stream).ToString();
//Deserializing
MemoryStream stream = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
stream.Write(rawFile, 0, rawFile.Length);
stream.Seek(0, SeekOrigin.Begin);
Object obj = (Object) binForm.Deserialize(stream);
System.Web.Script.Serialization.JavaScriptSerializer xyz = new System.Web.Script.Serialization.JavaScriptSerializer();
string ejson = xyz.Serialize(obj);
WebOperationContext.Current.OutgoingRequest.ContentType = "text/json";
return ejson;
}
I'm trying to return a string and it's not working, but when I return just the stream it's popping up the "openwith" message.
Also should I use the GET or POST on my datacontract. I'm using REST in C#.
I'm assuming that your file actually contains json. If that is the case just do this;
string file = File.ReadAllText("C:\path\to\file.extension");
You're making the problem a lot more complicated than it needs to be. Just read the file and return it's data as a string. I think you want to use GET for the http method. Generally speaking, you all use post if you're adding new content. If for example the users request would cause the application to write some data to a file or data base then you would typically use POST for the http method. If they're just requesting data, you almost always use GET.

Categories