c# how to get a stream processed by httpResponse.BinaryWrite - asp.net

I have the following method that writes a stream in a HttpResponse object.
public HttpResponse ShowPDF(Stream stream)
{
MemoryStream memoryStream = (MemoryStream) stream;
httpResponse.Clear();
httpResponse.Buffer = true;
httpResponse.ContentType = "application/pdf";
httpResponse.BinaryWrite(memoryStream.ToArray());
httpResponse.End();
return httpResponse;
}
In order to test it, I need to recover the processed stream.
Is there someway to read the stream from the httpResponse object?

I have two ideas... one to mock the HttpResponse, and the other is to simulate a web server.
1. Mocking HttpResponse
I wrote this before I knew which mocking framework you used. Here's how you could test your method using TypeMock.
This assumes that you pass your httpResponse variable to the method, changing the method as follows:
public void ShowPDF(Stream stream, HttpResponse httpResponse)
Of course you would change this to passing it to a property on your Page object instead, if it is a member of your Page class.
And here's an example of how you could test using a fake HttpResponse:
internal void TestPDF()
{
FileStream fileStream = new FileStream("C:\\deleteme\\The Mischievous Nerd's Guide to World Domination.pdf", FileMode.Open);
MemoryStream memoryStream = new MemoryStream();
try
{
memoryStream.SetLength(fileStream.Length);
fileStream.Read(memoryStream.GetBuffer(), 0, (int)fileStream.Length);
memoryStream.Flush();
fileStream.Close();
byte[] buffer = null;
var fakeHttpResponse = Isolate.Fake.Instance<HttpResponse>(Members.ReturnRecursiveFakes);
Isolate.WhenCalled(() => fakeHttpResponse.BinaryWrite(null)).DoInstead((context) => { buffer = (byte[])context.Parameters[0]; });
ShowPDF(memoryStream, fakeHttpResponse);
if (buffer == null)
throw new Exception("It didn't write!");
}
finally
{
memoryStream.Close();
}
}
2. Simulate a Web Server
Perhaps you can do this by simulating a web server. It might sound crazy, but it doesn't look like it's that much code. Here are a couple of links about running Web Forms outside of IIS.
Can I run a ASPX and grep the result without making HTTP request?
http://msdn.microsoft.com/en-us/magazine/cc163879.aspx

Related

How do I use response from an web api returning an image?

I have two web asp.net mvc based projects.
The first one has an image preview api, is implemented somewhat like this...
private async Task <HttpResponseMessage> GetImage(int id)
{
string filePath = "abstractedforsimplicity.png";
using(var file = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
{
byte[] buff = new byte[file.Length];
await file.ReadAsync(buff, 0, (int) file.Length);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(buff)
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
return result;
}
}
this works, I am able to show a preview with the following url - domain/api/image/3
Now I am a different application where I want to again make use of the same preview. I do not want to expose this api directly, so will be making a proxy api which will be making the call internally.
public HttpResponseMessage GetImage(int id)
{
string tempalteUrl = string.Format("{0}/{1}", ConfigurationManager.AppSettings["rmgpubadmin:template-base-url"], id);
WebClient client = new WebClient();
byte[] bytes = client.DownloadData(tempalteUrl);
// not very sure what should i do here ??
return null;
}
I tried to converting the bytes to an object, but if fails with errors - System.Runtime.Serialization.SerializationException.
The input stream is not a valid binary format. The starting contents (in bytes) are: 89-50-4E-47-0D-0A-1A-0A-00-00-00-0D-49-48-44-52-00 ...
What should i be doing here?

WCF Synchronous vs Asynchronous

I have been looking at MSDN and codeproject, but I am still a bit confused.
Synchronous Service vs an Asynchronous service.
I have a WCF service end point. This service has a 2way SSL applied to its web.config file.
The client end point is a Oracle based java Weblogic Suite. This has its own private key and public key. The client needs to communicate with our service both asynchronously and synchronously.
I CAN ONLY CHANGE THINGS ON THE SERVER SIDE
http://www.codeproject.com/Articles/91528/How-to-Call-WCF-Services-Synchronously-and-Asynchr
http://msdn.microsoft.com/en-us/library/ms731177.aspx
The following code is the synchronous part of the SVC, cs file:-
public getQuoteSyncResponse1 getQuoteSync(getQuoteSyncRequest request)
{
// Create new response
getQuoteSyncResponse1 res = new getQuoteSyncResponse1();
res.GetQuoteSyncResponse = new GetQuoteSyncResponse();
res.GetQuoteSyncResponse.Header = new GetQuoteResponseHeaderType();
res.GetQuoteSyncResponse.Response = new GetQuoteSyncResponseType();
// Create and populate header
res.GetQuoteSyncResponse.Header.MessageId = request.GetQuoteRequestSync.Header.MessageId;
res.GetQuoteSyncResponse.Header.Timestamp = request.GetQuoteRequestSync.Header.Timestamp;
res.GetQuoteSyncResponse.Header.QuoteId = request.GetQuoteRequestSync.Header.QuoteId;
res.GetQuoteSyncResponse.Header.CarrierId = request.GetQuoteRequestSync.Header.CarrierId;
List<RejectionType> rj = new List<RejectionType>();
string _sTotalEmployees = request.GetQuoteRequestSync.Request.Employer.TotalEmployees;
int _TotalEmployees = 0;
if (int.TryParse(_sTotalEmployees, out _TotalEmployees) == false)
{
RejectionType rt;
rt = new RejectionType();
rt.ReasonCode = "R01";
rt.ReasonDescription = "Invalid Number of Employees";
rj.Add(rt);
res.GetQuoteSyncResponse.Response.Rejections = rj.ToArray();
res.GetQuoteSyncResponse.Response.ReceiptStatus = AcceptanceContentType.Reject;
return res;
}
res.GetQuoteSyncResponse.Response.ReceiptStatus = AcceptanceContentType.Success;
List<QuoteType> q = new List<QuoteType>();
QuoteType qt;
qt = new QuoteType();
qt.PlanId = "P345678";
qt.EEPremium = 1220;
qt.EESPPremium = 2222;
qt.EEDepPremium = 3333;
qt.EEFamilyPremium = 4444;
qt.TotalMonthlyPremium = 3456;
qt.CoverageEffectiveDate = DateTime.Now;
q.Add(qt);
res.GetQuoteSyncResponse.Response.Quotes = q.ToArray();
return res;}
so this Synchronous part of the service is working. Now, how do I use this to transform it into the asynchronous equivalent?
Should I be starting the async method in the cs file? or in the svc file? I am confused...
public getQuoteAsyncResponse getQuoteAsync(getQuoteAsyncRequest request, AsyncCallback callback, Object state)
{
// Create new response
getQuoteAsyncResponse res = new getQuoteAsyncResponse();
return new getQuoteAsyncResponse();
}
I sort of understand about the callback deli-gator, object state and such, but can someone illustrate this further for me? How do I format the asynchronous part of the service? The web has so many examples... but all very confusing. I must have some inherent misunderstanding on this concept.
Edit:- I was told in the answer that, the server side needs no manipulation for async style of communication. However I found this:-
Implementing Asynchronous Operations in WCF
Just as the WCF plumbing enables clients to call server operations asynchronously, without the server needing to know anything about it, WCF also allows service operations to be defined asynchronously. So an operation like:
[OperationContract]
string DoWork(int value);
…might instead be expressed in the service contract as:
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginDoWork(int value, AsyncCallback callback, object state);
string EndDoWork(IAsyncResult result);
Note that the two forms are equivalent, and indistinguishable in the WCF metadata: they both expose an operation called DoWork[1]:
The async part needs to be done in the client. This means you are probably doing something similar to:
var response = ServiceReference.GetSomething();
Instead, make a proxy to get the callback. Create and event (or delegate) that gets fired (or called) whenever the callback receives the response. In the above statement, you are obviously waiting for the response to be assigned into the variable before moving to the next line.
Instead, you could
On the Service contract, be sure to decorate with [OperationContract(IsOneWay = true)]
If you use ServiceReference or serviceutil, it will automatically create "incoming events" and do all the client side async work for you.
If you are using TCP, create an callback contract as well, then on client you can do something like
ServiceReference1.IncomingSomething += new eventHandler.
Now you can do ServiceReferecnce1.GetSomething(), and the response will go to the eventhandler function.
If this is RESTFUL:
public void MakeAsyncRequest(string url, string contentType)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = contentType;
request.Method = WebRequestMethods.Http.Get;
request.Timeout = 10000;
request.Proxy = null;
request.BeginGetResponse(new AsyncCallback(ReadCallback), request);
}
catch (Exception ex)
{
LogManager.LogException(ex);
}
}
private void ReadCallback(IAsyncResult asyncResult)
{
HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
string strContent = string.Empty;
string s;
try
{
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult))
{
Stream responseStream = response.GetResponseStream();
using (StreamReader sr = new StreamReader(responseStream))
{
//Need to return this response
strContent = sr.ReadToEnd();
}
}
}
catch (Exception ex)
{
throw;
}
}

HttpResponse in Webapi controller in MVC

I am using Web api controller as follows:
[HttpPost]
public HttpResponseMessage PostMethod(string filename)
{
Stream downloadStream = BL.method(fileName);
HttpResponseMessage response = new HttpResponseMessage();
response.content= new StreamContent(downloadStream);
return response;
}
When I try to call the above method using fiddler I am getting an exception saying
'downloadStream.ReadTimeout' threw an exception of type
'System.InvalidOperationException'.
Can the stream be set in response and sent? Is there any modification for the above code?
There seems to be a problem with your stream. Without knowing how stream is generated it is difficult to say. If you replace BL.method(fileName); with just loading the file yourself using FileStream this should work (I just tested it myself).
On the side note, there are a few problems with your approach:
You use POST. Since you are not changing anything GET is better.
You are not setting ContentType header so client can have problem using resource
You are not disposing the stream so this stream could stay in limbo and generally not good.
Try using the PushStreamContent, maybe by not buffering the file in memory, you might avoid your timeout.
[HttpPost]
public HttpResponseMessage PostMethod(string filename)
{
Stream downloadStream = BL.method(fileName);
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new PushStreamContent((responseStream, httpContent, tc) => {
downloadStream.CopyTo(responseStream);
responseStream.Close();
}, "application/octet-stream");
return response;
}

How to get raw request body in ASP.NET?

In the HttpApplication.BeginRequest event, how can I read the entire raw request body? When I try to read it the InputStream is of 0 length, leading me to believe it was probably already read by ASP.NET.
I've tried to read the InputStream like this:
using (StreamReader reader = new StreamReader(context.Request.InputStream))
{
string text = reader.ReadToEnd();
}
But all I get is an empty string. I've reset the position back to 0, but of course once the stream is read it's gone for good, so that didn't work. And finally, checking the length of the stream returns 0.
Edit: This is for POST requests.
The request object is not populated in the BeginRequest event. You need to access this object later in the event life cycle, for example Init, Load, or PreRender. Also, you might want to copy the input stream to a memory stream, so you can use seek:
protected void Page_Load(object sender, EventArgs e)
{
MemoryStream memstream = new MemoryStream();
Request.InputStream.CopyTo(memstream);
memstream.Position = 0;
using (StreamReader reader = new StreamReader(memstream))
{
string text = reader.ReadToEnd();
}
}
Pål's answer is correct, but it can be done much shorter as well:
string req_txt;
using (StreamReader reader = new StreamReader(HttpContext.Current.Request.InputStream))
{
req_txt = reader.ReadToEnd();
}
This is with .NET 4.6.
In ASP.NET Core 2:
using (var reader = new StreamReader(HttpContext.Request.Body)) {
var body = reader.ReadToEnd();
}
I had a similar requirement to get the raw content and struck the same issue. I found that calling Seek(0, SeekOrigin.Begin) solved the problem.
This is not a particularly good approach as it makes assumptions about how the underlying infrastructure operates, but it seems to work.
It is important to reset position of InputStream.
var memstream = new MemoryStream();
Request.InputStream.CopyTo(memstream);
Request.InputStream.Position = 0;
using (StreamReader reader = new StreamReader(memstream)) {
var text = reader.ReadToEnd();
Debug.WriteLine(text);
}
Here's what I ended up doing:
//Save the request content. (Unfortunately it can't be written to a stream directly.)
context.Request.SaveAs(filePath, false);

How to do httpPost to a webservice which accepts a byte array of a file using c#

I am working on an API kind of project,
I have wrote a WebMethod (not exactly. I am using MVC to create REST like API)
public UploadFileImage(string employeeId, byte[] imageBytes, string imageName)
{
// saves the imagebyte as an image to a folder
}
the web service would be consumed by a web app, or windows or even iphone or such portable stuffs. I am testing my web service using a web app, by simple httpPost.
string Post(Uri RequestUri, string Data)
{
try
{
HttpWebRequest request = HttpWebRequest.Create(RequestUri) as HttpWebRequest;
request.Method = "POST";
request.ContentType = IsXml.Checked ? "text/xml" : "application/x-www-form-urlencoded";
byte[] bytes = Encoding.ASCII.GetBytes(Data);
Stream os = null; // send the Post
request.ContentLength = bytes.Length; //Count bytes to send
os = request.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
HttpWebResponse httpWebResponse = (HttpWebResponse)request.GetResponse();
StreamReader streamReader = new StreamReader(request.GetResponse().GetResponseStream());
return streamReader.ReadToEnd();
}
catch (Exception ex)
{
return ex.Message;
}
}
This code works fine for evey method like, AddEmployee, DeleteEmployee etc. THe parameter Data is of form "Id=123&name=abcdefgh&desig=Developer",
How I call any other function is
Post(new Uri("http://localhost/addemployee"),"name=abcd&password=efgh")
where post is the function i wrote.
All good for all functions. Except that I dont know how to consume the above mentioned function UploadFileImage to upload an image?
Thanks
Try encoding the imageBytes as Base64.
From your code snippet is not too clear how you call UploadFileImage, that is how you convert its parameters tripplet into Data.
That is why my answer is quite generic:
In general, you'd better transfer your image file by
request.ContentType = "multipart/form-data; boundary=----------------------------" + DateTime.Now.Ticks.ToString("x");
Please allow me to refer you to a sample at StackOverflow on how to format a multipart request. I am sure that if you google, you shall find a lots of detailed examples and explanations as well.
I hope this helps :-)

Resources