WinRT No mapping for the Unicode character exists in the target multi-byte code page - file-io

I am trying to read a file in my Windows 8 Store App. Here is a fragment of code I use to achieve this:
if(file != null)
{
var stream = await file.OpenAsync(FileAccessMode.Read);
var size = stream.Size;
using(var inputStream = stream.GetInputStreamAt(0))
{
DataReader dataReader = new DataReader(inputStream);
uint numbytes = await dataReader.LoadAsync((uint)size);
string text = dataReader.ReadString(numbytes);
}
}
However, an exeption is thrown at line:
string text = dataReader.ReadString(numbytes);
Exeption message:
No mapping for the Unicode character exists in the target multi-byte code page.
How do I get by this?

I managed to read file correctly using similar approach to suggested by duDE:
if(file != null)
{
IBuffer buffer = await FileIO.ReadBufferAsync(file);
DataReader reader = DataReader.FromBuffer(buffer);
byte[] fileContent = new byte[reader.UnconsumedBufferLength];
reader.ReadBytes(fileContent);
string text = Encoding.UTF8.GetString(fileContent, 0, fileContent.Length);
}
Can somebody please elaborate, why my initial approach didn't work?

Try this instead of string text = dataReader.ReadString(numbytes):
dataReader.ReadBytes(stream);
string text = Convert.ToBase64String(stream);

If, like me, this was the top result when search for the same error regarding UWP, see the below:
The code I had which was throwing the error (no mapping for the unicode character exists..):
var storageFile = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFileAsync(fileToken);
using (var stream = await storageFile.OpenAsync(FileAccessMode.Read))
{
using (var dataReader = new DataReader(stream))
{
await dataReader.LoadAsync((uint)stream.Size);
var json = dataReader.ReadString((uint)stream.Size);
return JsonConvert.DeserializeObject<T>(json);
}
}
What I changed it to so that it works correctly
var storageFile = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFileAsync(fileToken);
using (var stream = await storageFile.OpenAsync(FileAccessMode.Read))
{
T data = default(T);
using (StreamReader astream = new StreamReader(stream.AsStreamForRead()))
using (JsonTextReader reader = new JsonTextReader(astream))
{
JsonSerializer serializer = new JsonSerializer();
data = (T)serializer.Deserialize(reader, typeof(T));
}
return data;
}

Related

How to call API method that accepts XML in ASP.NET Core Web APIs?

The API Method I am calling is:
[HttpPost("PostXml")]
[Consumes("application/xml")]
[Produces("application/xml")]
public Reservation PostXml([FromBody] Reservation res) =>
repository.AddReservation(new Reservation
{
Name = res.Name,
StartLocation = res.StartLocation,
EndLocation = res.EndLocation
});
The client code:
[HttpPost]
public async Task<IActionResult> AddReservationByXml(Reservation reservation)
{
Reservation receivedReservation = new Reservation();
using (var httpClient = new HttpClient())
{
StringContent content = new StringContent(ConvertObjectToXMLString(reservation), Encoding.UTF8, "application/xml");
using (var response = await httpClient.PostAsync("http://localhost:8888/api/Reservation/PostXml", content))
{
string apiResponse = await response.Content.ReadAsStringAsync();
receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
}
}
return View(receivedReservation);
}
string ConvertObjectToXMLString(object classObject)
{
string xmlString = null;
XmlSerializer xmlSerializer = new XmlSerializer(classObject.GetType());
using (MemoryStream memoryStream = new MemoryStream())
{
xmlSerializer.Serialize(memoryStream, classObject);
memoryStream.Position = 0;
xmlString = new StreamReader(memoryStream).ReadToEnd();
}
return xmlString;
}
I am failing to call the API method and getting the error:
400One or
more validation errors
occurred.https://tools.ietf.org/html/rfc7231#section-6.5.1|f5452728-4c49abe4d88e559e.1.8095e7c1_An
error occurred while deserializing input
data.
What is wrong here?
You got error from this line
receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
Please check the validation of your Reservation Model and detail the values you past
and the content of error you got.
Your XML request should be with the correct case as the c# class. XML is case sensitive.
Try this code.
XmlSerializer xsSubmit = new XmlSerializer(typeof(Reservation));
System.IO.StringWriter sww = new System.IO.StringWriter();
XmlWriter writer = XmlWriter.Create(sww);
xsSubmit.Serialize(writer, reservation);
var xml = sww.ToString();

CloudBlockBlob DownloadTextAsync Behavior Difference

I am using an azure function with event grid trigger and CloudBlockBlob as input binding. The content is getting downloaded from CloudBlockBob using DownloadTextAsync(AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext)
If the file being downloaded above is being generated using XmlDocument, DownloadTextAsync returns gibberish. However, if the file is generated by using FileStream, it works fine. PFB the implementations of generating the file-
Using XmlDocument
var stringwriter = new System.IO.StringWriter();
var serializer = new XmlSerializer(typeof(List<ContractName>), new XmlRootAttribute("RootAttributeName"));
serializer.Serialize(stringwriter, contractData);
var xmlString = stringwriter.ToString();
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlString);
doc.PreserveWhitespace = true;
doc.Save(fileName);
Using FileStream
var serializer = new XmlSerializer(typeof(List<ContractName>), new XmlRootAttribute("RootAttributeName"));
var file = new FileStream(fileName, FileMode.OpenOrCreate);
serializer.Serialize(file, contractData);
file.Close();
Code being used to download the content-
Using DownloadTextAsync
private static async System.Threading.Tasks.Task<string> DownloadContentAsync_DownloadTextAsync(string storageAccountConnectionString, string containerName, string blobName)
{
CloudBlobContainer container = GetContainer(storageAccountConnectionString, containerName);
ICloudBlob blob = await container.GetBlobReferenceFromServerAsync(blobName);
// Download the blob content
string xmlBlobContent =
await (blob as CloudBlockBlob).DownloadTextAsync(
null,
new BlobRequestOptions { LocationMode = LocationMode.PrimaryThenSecondary },
new OperationContext());
return xmlBlobContent;
}
Using DownloadToStreamAsync
private static async System.Threading.Tasks.Task<string> DownloadContentAsync_DownloadToStreamAsync(string storageAccountConnectionString, string containerName, string blobName)
{
CloudBlobContainer container = GetContainer(storageAccountConnectionString, containerName);
ICloudBlob blob = await container.GetBlobReferenceFromServerAsync(blobName);
// Download the blob content
MemoryStream resultStream = new MemoryStream();
await (blob as CloudBlockBlob).DownloadToStreamAsync(
resultStream,
null,
new BlobRequestOptions { LocationMode = LocationMode.PrimaryThenSecondary },
new OperationContext());
string xmlBlobContent = System.Text.Encoding.UTF8.GetString(resultStream.ToArray());
return xmlBlobContent;
}
Why there is a difference in response from DownloadTextAsync.
Updated 0713:
Figured it out. The root cause is that when you're using XmlDocument to generate the xml file, the encoding is utf-16. But for FileStream, it generates the xml file with encoding utf-8.
So, the solution is that, when using XmlDocument, we can specify the encoding to utf-8(no code change for FileStream). Sample code as below:
Generate xml file using XmlDocument:
//2. Using XMLDoc
serializer.Serialize(stringwriter, contractData);
var xmlString = stringwriter.ToString();
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlString);
doc.PreserveWhitespace = true;
string fileName = String.Format(#"C:\TestBlobDownloadContent\UsingXMLDoc" + count + ".xml");
//encoding as utf-8
using (TextWriter sw = new StreamWriter(fileName, false, Encoding.UTF8))
{
doc.Save(sw);
}
When read the xml file from blob storage via DownloadTextAsync() method, no need to specify the encoding option, like below:
// Download the blob content
string xmlBlobContent =
await (blob as CloudBlockBlob).DownloadTextAsync(
null,
new BlobRequestOptions { LocationMode = LocationMode.PrimaryThenSecondary },
new OperationContext());
Original answer:
This is due to the encode/decode issue.
Solution:
In the DownloadTextAsync() method, add parameter System.Text.Encoding.Unicode. Like below:
string xmlBlobContent =
await (blob as CloudBlockBlob).DownloadTextAsync(
System.Text.Encoding.Unicode,
null,
new BlobRequestOptions { LocationMode = LocationMode.PrimaryThenSecondary },
new OperationContext());
The test result:

Reading JSON File inside the Javascript adapter

MFP 8, Javascript adapters should read the JSON file (TestData.json) placed in
"\src\main\adapter-resources"
I need to read the static array contents from json/text file within the same JAVASCRIPT HTTP adapter. How to do the same ?
Read the static arrays from file (Text/JSON) within same adapter folder.
As explained in this solution, you can read a JSON file with Javascript as shown below.
function readFile(filename) {
var content = "";
var fileReader = new java.io.FileReader(filename);
var bufferedReader = new java.io.BufferedReader(fileReader);
var line;
while((line = bufferedReader.readLine()) != null) {
content += line;
}
bufferedReader.close();
return content;
}
function test() {
var file = 'yourfilename.json';
var fileContents;
try {
fileContents = JSON.parse(readFile(file));
} catch(ex) {
// handle error
}
return {
fileContents: fileContents
};

Why CsvHelper not reading from MemoryStream?

I am trying to convert an uploaded csv file to an object, so i can save in db.
In the controller I am using CsvHeler
But looks like this only works if I first save the file and read from it. CsvHelper is not able to process the file contents directly from memory stream. In the code below the first GetRecords returns empty
[HttpPost]
[Route(ApiRoutes.EodVariationMarginPlugs)]
public async Task<IActionResult> UploadPlugAsync(IFormFile filePayload)
{
if (filePayload.Length > 0)
{
using (var stream = new MemoryStream())
{
filePayload.CopyTo(stream);
using (var reader = new StreamReader(stream))
using (var csv = new CsvReader(reader))
{
csv.Configuration.RegisterClassMap<EodVariationMarginPlugMap>();
csv.Configuration.MissingFieldFound = null;
var records = csv.GetRecords<EodVariationMarginPlug>().ToList(); // record count is 0
foreach (var p in records)
{
p.CreatedAt = DateTimeOffset.Now;
p.CreatedBy = HttpContext.User.Identity.Name;
}
await _repository.InsertPlugsAsync(records);
}
}
var fileName = ContentDispositionHeaderValue
.Parse(filePayload.ContentDisposition)
.FileName.ToString().Trim('"');
var path = Path.Combine(Path.GetTempPath(), fileName);
using (var fileStream = new FileStream(path, FileMode.Create))
{
await filePayload.CopyToAsync(fileStream);
}
var textReader = System.IO.File.OpenText(path);
using (var csv = new CsvReader(textReader))
{
csv.Configuration.RegisterClassMap<EodVariationMarginPlugMap>();
csv.Configuration.MissingFieldFound = null;
var records = csv.GetRecords<EodVariationMarginPlug>().ToList();
foreach (var p in records)
{
p.CreatedAt = DateTimeOffset.Now;
p.CreatedBy = HttpContext.User.Identity.Name;
}
await _repository.InsertPlugsAsync(records);
}
}
return Ok();
}
The most common error here is forgetting MemoryStream is binary; it deals in bytes. You need something that deals in characters, which isn't always a 1:1 adaption. The good news is you avoided that error by wrapping the MemoryStream in a StreamReader:
using (var reader = new StreamReader(stream))
StreamReader implements TextReader, which works with characters rather than bytes. Yay! The bad news is the StreamReader is created right after this line:
filePayload.CopyTo(stream);
The problem was that line left the stream pointed at the end of the data. When you try to read from it, there's nothing left in the stream.
All you should need to do to fix this is seek back to the beginning. So this:
using (var stream = new MemoryStream())
{
filePayload.CopyTo(stream);
using (var reader = new StreamReader(stream))
Becomes this:
using (var stream = new MemoryStream())
{
filePayload.CopyTo(stream);
stream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(stream))

get url of image from Umbraco examine search UDI

I'm using Umbraco with Lucene and Examine
I'm trying to get the url of a image but at the moment I get the following
"umb://media/57ad107794724d0289b4f9fe44c298a8"
How can I get the URL for the media from the UDI, my code attempt so far is below.
foreach (var item in searchResults)
{
var content = Umbraco.Content(item.Fields["id"]);
if (item.Fields.Keys.Contains("image"))
{
var image = item.Fields["image"].Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries);
var pathToImage = string.Join(",", image);
var mediaItem = Umbraco.TypedContent(pathToImage);
var test3 = mediaItem.Url; <--------------------Throws NullReferenceException
}
}
Any help appreciated
Try the following
if (item.Fields.Keys.Contains("image"))
{
var imgUdi = item.Fields["image"];
var udi = Udi.Parse(imgUdi);
var mediaTest = Umbraco.TypedMedia(udi);
string pathToImage = mediaTest.Url;
}
Notice how I'm using Udi.Parse to get the ID, then you can use that to get the url