I have a Controller which returns a FileStreamResult via SharpZipLib (I have tried DotNetZip and there is no difference).
using (var buffer = new MemoryStream())
{
using (var zipStream = new ZipOutputStream(buffer))
{
zipStream.PutNextEntry(new ZipEntry("The Simpsons"));
var bart = Encoding.UTF8.GetBytes("Homer <3 donuts");
zipStream.Write(bart, 0, bart.Length);
zipStream.IsStreamOwner = false;
return File(buffer, MediaTypeNames.Application.Zip, fileName);
}
}
I am trying to unit test this as such:
var controller = new SimpsonsController();
var result = controller.ConfigurationReport(id);
Assert.IsInstanceOf<FileStreamResult>(result);
var streamResult = (FileStreamResult) result;
var zipInputStream = new ZipInputStream(streamResult.FileStream);
Assert.IsNotNull(zipInputStream);
var zipEntry = zipInputStream.GetNextEntry();
Assert.AreEqual("The Simpsons", zipEntry.Name);
Now the unit test fails with:
System.ObjectDisposedException : Cannot access a closed Stream.
at System.IO.__Error.StreamIsClosed()
at System.IO.MemoryStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer.Fill()
at ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer.ReadLeByte()
at ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer.ReadLeInt()
at ICSharpCode.SharpZipLib.Zip.ZipInputStream.GetNextEntry()
If I try to directly download via a browser, IIS 500s with a similar stacktrace:
Cannot access a closed Stream.
System.ObjectDisposedException: Cannot access a closed Stream.
at System.IO.MemoryStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.Web.Mvc.FileStreamResult.WriteFile(HttpResponseBase response)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
Has anyone tested this kind of stream-based file returning controllers? How did you succeed? Should I simply NOT dispose my classes? Really?
Try this, I think your problem is you are disposing of the stream that is being returned.
public FileStreamResult PDF()
{
MemoryStream buffer = new MemoryStream();
using (var zipStream = new ZipOutputStream(buffer))
{
zipStream.PutNextEntry(new ZipEntry("The Simpsons"));
var bart = Encoding.UTF8.GetBytes("Homer <3 donuts");
zipStream.Write(bart, 0, bart.Length);
zipStream.IsStreamOwner = false;
}
return File(buffer, MediaTypeNames.Application.Zip, fileName);
}
Take a look at this https://stackoverflow.com/a/10891136/985284 and follow other posts from Cheeso for more info.
Related
I am using itext7 for PDF manipulation. I am trying to fill form fields by field.setValue method. My _Reader object is filled at constructor level and is used on Adding and Getting form fields. But on Saving form field value, on closing PdfDocument object following exception is caught:
at System.IO.__Error.StreamIsClosed()
at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at iText.IO.Source.OutputStream`1.Write(Byte[] b, Int32 off, Int32 len)
at iText.IO.Source.OutputStream`1.WriteInteger(Int32 value)
at iText.Kernel.Pdf.PdfWriter.WriteToBody(PdfObject pdfObj)
at iText.Kernel.Pdf.PdfWriter.FlushObject(PdfObject pdfObject, Boolean
canBeInObjStm)
at iText.Kernel.Pdf.PdfDocument.FlushObject(PdfObject pdfObject, Boolean
canBeInObjStm)
at iText.Kernel.Pdf.PdfObject.Flush(Boolean canBeInObjStm)
at iText.Kernel.Pdf.PdfPage.Flush(Boolean flushResourcesContentStreams)
at iText.Kernel.Pdf.PdfPage.Flush()
at iText.Kernel.Pdf.PdfDocument.Close()
Code snippet is as following:
using (var memoryStream = new MemoryStream())
{
PdfDocument document = new PdfDocument(_Reader, new PdfWriter(memoryStream));
PdfAcroForm Form = PdfAcroForm.GetAcroForm(document, true);
foreach (PDFField Field in PDFFields)
{
PdfFormField formField = Form.GetField(Field.Name);
switch (Field.Type)
{
case PDF_FIELD_TYPE.TEXTBOX:
if (!string.IsNullOrEmpty(Field.Value))
formField.SetValue(Field.Value);
else
formField.SetValue(string.Empty);
break;
}
}
document.Close();
byte[] PDFBytes = ((MemoryStream)memoryStream).ToArray();
Thanks in advance for help.
I am creating a stream like class, that inherits from Stream. When I use a StreamWriter class to write the information asynchronously:
using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
await sw.WriteAsync(msg);
I can see how StreamWriter goes straight to void Stream.Write(byte[] buffer, int offset, int count) rather than Task Stream.WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken).
Is this a bug or am I missing something?
I spotted the source of confusion.
StreamWriter flushes synchronously by default unless you specifically flush asynchronously.
Stream.Flush is called when closing, and of course, flushing.
This will invoke Write rather than WriteAsync in the messageWriter stream:
using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
await sw.WriteAsync("Hi");
The StreamWriter will buffer the "Hi" message, and it will be released to the underlying stream on the Flush invocation synchronously when closing the StreamWriter.
So the asynchronous call to StreamWriter.WriteAsync could have no effect on the underlying stream (because the buffering), and when calling StreamWriter.Close, StreamWriter.Flush is called synchronously, and therefore the Flush method on the underlying stream.
This code also calls Write synchronously:
using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
{
sw.AutoFlush = true; // will call Write here to send the UTF8 BOM
await sw.WriteAsync("Hi"); // Write the actual data
}
obviously also this this:
using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
{
await sw.WriteAsync("Hi");
sw.Flush();
}
This will call WriteAsync:
using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
{
await sw.WriteAsync("Hi");
await sw.FlushAsync()
}
I have created a simple class to track how the methods are called:
public class MSWrite : MemoryStream
{
public override bool CanWrite { get { return true; } }
public override void Write(byte[] buffer, int offset, int count)
{
Console.WriteLine("Write");
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
Console.WriteLine("WriteAsync");
return Task.Run(() => { });
}
}
And this test:
Console.WriteLine("Simple");
using(var ms = new MSWrite())
using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
{
await sw.WriteAsync("Hi");
}
Console.WriteLine();
Console.WriteLine("AutoFlush");
using (var ms = new MSWrite())
using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
{
sw.AutoFlush = true;
await sw.WriteAsync("Hi");
}
Console.WriteLine();
Console.WriteLine("Flush async");
using (var ms = new MSWrite())
using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
{
await sw.WriteAsync("Hi");
await sw.FlushAsync();
}
Yields:
Simple
Write
Write
AutoFlush
Write
WriteAsync
Flush async
WriteAsync
WriteAsync
The first write is the UTF8 BOM, the second is the actual data.
No, StreamWriter.WriteAsync does in fact call Stream.WriteAsync (assuming you are on .NET 4.5). If you are seeing otherwise, please post a stack trace.
Note that the Stream base class by default will implement WriteAsync as a Write done on a thread pool thread. You'll need to override WriteAsync in your custom stream to change this behavior.
I created a custom binder that looks like this:
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var o = new MetaObject();
o.OnBinderLoad();
o.StatusTypeId = Convert.ToInt32(bindingContext.ValueProvider.GetValue("StatusTypeId").AttemptedValue);
o.Comments.setValue(bindingContext.ValueProvider.GetValue("Comments").AttemptedValue);
o.EffectiveDate.setValue(bindingContext.ValueProvider.GetValue("EffectiveDate").AttemptedValue);
// bindingContext.ModelMetadata =
ModelBindingContext newBindingContext = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => o, typeof(MetaObject)),
ModelState = bindingContext.ModelState,
ValueProvider = bindingContext.ValueProvider
};
var returnValue = base.BindModel(controllerContext, newBindingContext);
return returnValue;
}
I run the debugger and the value of o and newBindingContext.ModelMetadata has the correct data before the call to base.BindModel. After that point Comments and EffectivDate are null.
How do I trace this and why would that happen.
Thanks for the help
Because I was inheriting from DefaultBinder, the base.bindmodel was overriding what I did. I followed the example below and everything is binding correctly.
http://mgolchin.net/posts/20/dive-deep-into-mvc-imodelbinder-part-1
I found an example about HTTP POST in msdn, but I am wondering how can I make use of reactive extensions here.
using System;
using System.Net;
using System.IO;
using System.Text; using System.Threading;
class HttpWebRequestBeginGetRequest
{
private static ManualResetEvent allDone = new ManualResetEvent(false);
public static void Main(string[] args)
{
// Create a new HttpWebRequest object.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.contoso.com/example.aspx");
request.ContentType = "application/x-www-form-urlencoded";
// Set the Method property to 'POST' to post data to the URI.
request.Method = "POST";
// start the asynchronous operation
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
// Keep the main thread from continuing while the asynchronous
// operation completes. A real world application
// could do something useful such as updating its user interface.
allDone.WaitOne();
}
private static void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
Console.WriteLine("Please enter the input data to be posted:");
string postData = Console.ReadLine();
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Write to the request stream.
postStream.Write(byteArray, 0, postData.Length);
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private static void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
Console.WriteLine(responseString);
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
allDone.Set();
}
}
I am trying to use the following code, but it does not work. Can anyone help me out on this?
Thanks in advance -Peng
return (from request in
Observable.Return((HttpWebRequest)WebRequest.Create(new Uri(postUrl))).Catch(Observable.Empty<HttpWebRequest>())
.Do(req =>
{
// Set up the request properties
req.Method = "POST";
req.ContentType = contentType;
req.UserAgent = userAgent;
req.CookieContainer = new CookieContainer();
Observable.FromAsyncPattern<Stream>(req.BeginGetRequestStream, req.EndGetRequestStream)()
.ObserveOnDispatcher()
.Subscribe(stream =>
{
stream.Write(formData, 0,
formData.Length);
stream.Close();
})
;
})
from response in
Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)().Catch(Observable.Empty<WebResponse>())
from item in GetPostResponse(response.GetResponseStream()).ToObservable().Catch(Observable.Empty<string>())
select item).ObserveOnDispatcher();
Edit: To make it clear, I want to use the rx to implement the same logic in MSDN example.
in the MSDN example, it seems it first makes async call to write RequestStream, and then in the GetRequestStreamCallback, fires another async call to get the response.
Using Rx, I am able to create 2 observables
1. Observable.FromAsyncPattern(request.BeginGetRequestStream, request.EndGetRequestStream)()
2. Observable.FromAsyncPattern(request.BeginGetResponse, request.EndGetResponse)()
The problem is the second observable depends on the first one's result, so how can I do this in Rx?
In the first observable's subcribe method to create the seond observable? is it the good way?
This is how I am doing it. I configure the two Async patters up front, then use SelectMany to chain them together.
I have cut out the error handling etc from this code to keep it simple and show only the bare minimum to get it working. You should append a .Catch() similar to your own code, and if you want to get more than just a string out (say the response code) then you'll need to create a class/struct to hold all the bits of data you need and return that instead.
public IObservable<string> BeginPost(Uri uri, string postData) {
var request = HttpWebRequest.CreateHttp(uri);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
var fetchRequestStream = Observable.FromAsyncPattern<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream);
var fetchResponse = Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse);
return fetchRequestStream().SelectMany(stream => {
using (var writer = new StreamWriter(stream)) writer.Write(postData);
return fetchResponse();
}).Select(result => {
var response = (HttpWebResponse)result;
string s = "";
if (response.StatusCode == HttpStatusCode.OK) {
using (var reader = new StreamReader(response.GetResponseStream())) s = reader.ReadToEnd();
}
return s;
});
}
Your problem is your use of Do() here, you need to move the GetRequestStream into your SelectMany (into your "from bla in, from bla in"...), since it only makes sense to get the response stream after you've written the full request. Right now, you're trying to do both concurrently.
I need to send an image from the Windows Phone 7 to some e-mail addresses.
I use this class to submit text values to a PHP script, wich parses data and sends a formatted e-mail to the addresses.
The problem is that I can't figure out how to send an image to that script, to attach the image to the e-mail. The PHP script can be changed in any way. If I have an Image object, how can I change this class to allow sending images?
public class PostSubmitter
{
public string url { get; set; }
public Dictionary<string, string> parameters { get; set; }
public PostSubmitter() { }
public void Submit()
{
// Prepare web request...
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(url);
myRequest.Method = "POST";
myRequest.ContentType = "application/x-www-form-urlencoded";
myRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), myRequest);
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
System.IO.Stream postStream = request.EndGetRequestStream(asynchronousResult);
// Prepare Parameters String
string parametersString = "";
foreach (KeyValuePair<string, string> parameter in parameters)
{
parametersString = parametersString + (parametersString != "" ? "&" : "") + string.Format("{0}={1}", parameter.Key, parameter.Value);
}
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(parametersString);
// Write to the request stream.
postStream.Write(byteArray, 0, parametersString.Length);
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
//Action<string> act = new Action<string>(DisplayResponse);
//this.Dispatcher.BeginInvoke(act, responseString);
}
I use the class in this way:
Dictionary<string, string> data = new Dictionary<string, string>()
{
{"nom", nom.Text},
{"cognoms", cognoms.Text},
{"email", email.Text},
{"telefon", telefon.Text}
};
PostSubmitter post = new PostSubmitter() { url = "http://example.com/parserscript.php", parameters = data };
post.Submit();
Thank you very much!
I've converted the above code to the following, I'm sure it will help:
public class PostSubmitter
{
public string url { get; set; }
public Dictionary<string, object> parameters { get; set; }
string boundary = "----------" + DateTime.Now.Ticks.ToString();
public PostSubmitter() { }
public void Submit()
{
// Prepare web request...
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(new Uri(url));
myRequest.Method = "POST";
myRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
myRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), myRequest);
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
Stream postStream = request.EndGetRequestStream(asynchronousResult);
writeMultipartObject(postStream, parameters);
postStream.Close();
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
}
public void writeMultipartObject(Stream stream, object data)
{
StreamWriter writer = new StreamWriter(stream);
if (data != null)
{
foreach (var entry in data as Dictionary<string, object>)
{
WriteEntry(writer, entry.Key, entry.Value);
}
}
writer.Write("--");
writer.Write(boundary);
writer.WriteLine("--");
writer.Flush();
}
private void WriteEntry(StreamWriter writer, string key, object value)
{
if (value != null)
{
writer.Write("--");
writer.WriteLine(boundary);
if (value is byte[])
{
byte[] ba = value as byte[];
writer.WriteLine(#"Content-Disposition: form-data; name=""{0}""; filename=""{1}""", key, "sentPhoto.jpg");
writer.WriteLine(#"Content-Type: application/octet-stream");
//writer.WriteLine(#"Content-Type: image / jpeg");
writer.WriteLine(#"Content-Length: " + ba.Length);
writer.WriteLine();
writer.Flush();
Stream output = writer.BaseStream;
output.Write(ba, 0, ba.Length);
output.Flush();
writer.WriteLine();
}
else
{
writer.WriteLine(#"Content-Disposition: form-data; name=""{0}""", key);
writer.WriteLine();
writer.WriteLine(value.ToString());
}
}
}
}
To convert an image from the camera to an byte array I've used the follwing:
private void photoChooserTask_Completed(object sender, PhotoResult e)
{
try
{
BitmapImage image = new BitmapImage();
image.SetSource(e.ChosenPhoto);
foto.Source = image;
using (MemoryStream ms = new MemoryStream())
{
WriteableBitmap btmMap = new WriteableBitmap(image);
// write an image into the stream
Extensions.SaveJpeg(btmMap, ms, image.PixelWidth, image.PixelHeight, 0, 100);
byteArray = ms.ToArray();
}
}
catch (ArgumentNullException) { /* Nothing */ }
}
And I use the class this way:
Dictionary<string, object> data = new Dictionary<string, object>()
{
{"nom", nom.Text},
{"cognoms", cognoms.Text},
{"email", email.Text},
{"telefon", telefon.Text},
{"comentari", comentari.Text},
{"foto", byteArray},
};
PostSubmitter post = new PostSubmitter() { url = "http://example.com/parserscript.php", parameters = data};
post.Submit();
I don't know if it's the best way to send an image from the phone to a server, but I couldn't find anything, so I made my own class just reading this and that, and it has taken me several days. If anybody wants to improve the code or write any comment will be welcomed.
There are lots of questions/answers on here to help already
e.g.
Post with WebRequest - although i couldn't spot any specifically for photos.
Perhaps the best way is to use something like Hammock on Codeplex - http://hammock.codeplex.com/ - or perhaps something like RESTSharp - http://restsharp.org/ - they provide standard REST POST functions.
e.g. if you look within Hammock, then you'll find others who've posted images direct from the camera to tumblr - see http://hammock.codeplex.com/discussions/235650
The above code works perfect. I just use a different method to convert the file to an array of bytes which works perfect with Audio
public static class FileHelper
{
public static byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = stream.Position;
stream.Position = 0;
try
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
stream.Position = originalPosition;
}
}
}