Form Recognizer SDK, analyze with custom model, file stream issue - c#

When I'm trying to analyze a pdf document using FileStream from a local file, everything works fine.
But when I use a IFormFile and use method OpenReadStream() and pass that stream to the Analyze method for form analyzer, i get an exception. I also tried creating a new stream out of the IFromFile stream and that did not work either.
Any help will be much appreciated. Thank you
Working code:
using var stream = new FileStream("D:\\somefile.pdf", FileMode.Open);
var result = await _formRecognizerClient.AnalyzeWithCustomModelAsync(modelId, fileStream, "application/pdf");
Code I am trying to make work:
using var stream = file.OpenReadStream(); // file is an IFormFile
var result = await _formRecognizerClient.AnalyzeWithCustomModelAsync(modelId, stream , file.ContentType);

I have a solution for now, its not elegant but it works. I am of course very much looking for something better if anyone can help.
For now, I am creating a file, saving it and creating a FileStream out of it. Also works in docker as I'm testing using docker-compose
var iFormFileStream = file.OpenReadStream();
var stream = File.Create(string.Format("tempfilename.pdf", File.));
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(stream);
stream.Close();
using var fileStream = new FileStream("tempfilename.pdf", FileMode.Open);
var result = await _formRecognizerClient.AnalyzeWithCustomModelAsync(modelId, fileStream, "application/pdf");

Related

How to return an image as an IActionResult from an Image/Bitmap object

I am generating a Barcode image using the barcodelib library + the System.Drawing.Common package available in .Net Core.
I want to return the image to the users in their browser as a plain image (or as a download) but I seem to not find a good way to do so.
What I've tried:
var barcode = new Barcode().Encode(TYPE.CODE128, reference);
usuing (var outputStream = new MemoryStream())
{
barcode.Save(outputStream, ImageFormat.Jpeg);
outputStream.Seek(0, SeekOrigin.Begin);
return File(outputStream, "image/jpeg");
}
This gives an exception, saying that the stream is closed.
It can be fixed by removing the using but isn't it bad? doesn't the streams stay in memory?
Remove the using block on the outputStream. The stream is being closed/disposed before it can be used by the response.
The FileResult will close the stream when it is finished using it.
var barcode = new Barcode().Encode(TYPE.CODE128, reference);
var outputStream = new MemoryStream();
barcode.Save(outputStream, ImageFormat.Jpeg);
outputStream.Seek(0, SeekOrigin.Begin);
return File(outputStream, "image/jpeg");
While FileResult will close the stream, frankly, I don't like depending on some external thing cleaning up after me, and at least to my eyes, the code just looks wrong newing up a MemoryStream outside of a using block and just letting it go without ever explicitly closing it.
There's an overload of File that accepts a byte array, so you can simply move your return outside of your using block.
byte[] bytes;
using (var ms = new MemoryStream())
{
var barcode = new Barcode().Encode(TYPE.CODE128, reference);
barcode.Save(ms, ImageFormat.Jpeg);
bytes = ms.ToArray();
}
return File(bytes, "image/jpeg");
It's a bit of personal preference, admittedly, but that just looks cleaner and more "correct" to me.

Sending Image from C# to Android via JSON

I have images stored in SQL server, and I want to send them to Android app via JSON with other data. What's the best way to do this?
BTW my server side written in ASP Web API(C#).
In other way I want to make my image like this http://myserver/image.jpg
so I can included in my JSON and download it in Android app.
As its not where clear from your question, This Link is the best what I can find for you. In it he is accessing ASP.NET WebAPI and converting all the things to JSON when access or pass it through the Andriod studio
http://hintdesk.com/how-to-call-asp-net-web-api-service-from-android/
and here is a complete series that can help you more
http://www.tutecentral.com/restful-api-for-android-part-1/
Hope this helps
I finally figure it out
This is the code
public HttpResponseMessage getImage(String name)
{
name = name + ".png";
var result = new HttpResponseMessage(HttpStatusCode.OK);
String filePath = HostingEnvironment.MapPath("~/images/"+name);
FileStream fileStream = new FileStream(filePath, FileMode.Open);
Image image = Image.FromStream(fileStream);
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Jpeg);
result.Content = new ByteArrayContent(memoryStream.ToArray());
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
fileStream.Dispose();
return result;
}

C# Serving a stream to a browser - can it be done?

I am trying to output a file to the browser from a REST API - but I don't have a physical file, instead I have a MemoryStream (and I would prefer not to write a physical file).
This works:
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(path, FileMode.Open);
result.Content = new StreamContent(stream);
return result;
This does not:
var stream = new MemoryStream();
// Iterate DataReader and populate MemoryStream code omitted for brevity.
// Assume MemoryStream has been written to correctly and contains data.
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(stream);
return result;
This has consumed most of my weekend so I would be delighted if anyone can offer some definitive insight.
I've found the answer through trial and error and a lot of research:
Yes, it can be done.
Instead of using StreamContent use ByteArrayContent:
e.g.
result.Content = new ByteArrayContent( stream.GetBuffer() );
Ensure that there is no HttpResponseMessage.ContentLength set or it will fail to work (connection reset) - it took me hours to figure that out.

How to get the stream for a Multipart file in webapi upload?

I need to upload a file using Stream (Azure Blobstorage), and just cannot find out how to get the stream from the object itself. See code below.
I'm new to the WebAPI and have used some examples. I'm getting the files and filedata, but it's not correct type for my methods to upload it. Therefore, I need to get or convert it into a normal Stream, which seems a bit hard at the moment :)
I know I need to use ReadAsStreamAsync().Result in some way, but it crashes in the foreach loop since I'm getting two provider.Contents (first one seems right, second one does not).
[System.Web.Http.HttpPost]
public async Task<HttpResponseMessage> Upload()
{
if (!Request.Content.IsMimeMultipartContent())
{
this.Request.CreateResponse(HttpStatusCode.UnsupportedMediaType);
}
var provider = GetMultipartProvider();
var result = await Request.Content.ReadAsMultipartAsync(provider);
// On upload, files are given a generic name like "BodyPart_26d6abe1-3ae1-416a-9429-b35f15e6e5d5"
// so this is how you can get the original file name
var originalFileName = GetDeserializedFileName(result.FileData.First());
// uploadedFileInfo object will give you some additional stuff like file length,
// creation time, directory name, a few filesystem methods etc..
var uploadedFileInfo = new FileInfo(result.FileData.First().LocalFileName);
// Remove this line as well as GetFormData method if you're not
// sending any form data with your upload request
var fileUploadObj = GetFormData<UploadDataModel>(result);
Stream filestream = null;
using (Stream stream = new MemoryStream())
{
foreach (HttpContent content in provider.Contents)
{
BinaryFormatter bFormatter = new BinaryFormatter();
bFormatter.Serialize(stream, content.ReadAsStreamAsync().Result);
stream.Position = 0;
filestream = stream;
}
}
var storage = new StorageServices();
storage.UploadBlob(filestream, originalFileName);**strong text**
private MultipartFormDataStreamProvider GetMultipartProvider()
{
var uploadFolder = "~/App_Data/Tmp/FileUploads"; // you could put this to web.config
var root = HttpContext.Current.Server.MapPath(uploadFolder);
Directory.CreateDirectory(root);
return new MultipartFormDataStreamProvider(root);
}
This is identical to a dilemma I had a few months ago (capturing the upload stream before the MultipartStreamProvider took over and auto-magically saved the stream to a file). The recommendation was to inherit that class and override the methods ... but that didn't work in my case. :( (I wanted the functionality of both the MultipartFileStreamProvider and MultipartFormDataStreamProvider rolled into one MultipartStreamProvider, without the autosave part).
This might help; here's one written by one of the Web API developers, and this from the same developer.
Hi just wanted to post my answer so if anybody encounters the same issue they can find a solution here itself.
here
MultipartMemoryStreamProvider stream = await this.Request.Content.ReadAsMultipartAsync();
foreach (var st in stream.Contents)
{
var fileBytes = await st.ReadAsByteArrayAsync();
string base64 = Convert.ToBase64String(fileBytes);
var contentHeader = st.Headers;
string filename = contentHeader.ContentDisposition.FileName.Replace("\"", "");
string filetype = contentHeader.ContentType.MediaType;
}
I used MultipartMemoryStreamProvider and got all the details like filename and filetype from the header of content.
Hope this helps someone.

How do I get the name of a file generated with a stream in C#?

I'm building a Windows 8 metro app with XAML/C#. I'm saving an .xml file my data structure with a stream, like this:
XmlSerializer serializer = new XmlSerializer(typeof(MyObjectType));
using (var stream = await App.LocalStorage.OpenStreamForWriteAsync(MyObject.Title + ".xml", Windows.Storage.CreationCollisionOption.GenerateUniqueName))
serializer.Serialize(stream, MyObject);
Where:
App.LocalStorage
Is obviously a StorageFolder objecty set to
Windows.Storage.ApplicationData.Current.LocalFolder
The GenerateUniqueName option is set in order to avoid collisions, because my objects can have the same title. Now, I need to get the file name my stream generated, how can I get it?
Thank you
Try creating the file first.
var sourceFileName = MyObject.Title + ".xml";
StorageFile storageFile = await App.LocalStorage.CreateFileAsync(sourceFileName, Windows.Storage.CreationCollisionOption.GenerateUniqueName);
using (var stream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
{
serializer.Serialize(stream, MyObject);
}
The OpenStreamForWriteAsync method does not seem to give you any easy way to access this information. You could switch to accessing it another way:
StorageFile file = await App.LocalStorage.CreateFileAsync(...);
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
// do stuff, file name is at file.Name

Categories