C# - Loading remote image and sending to browser using .ashx file - c#

I'm trying to load a remote image from my Amazon S3 bucket and send it to browser in binary. I'm also trying to learn ASP.Net at the same time. I've been a classic programmer for many years and need to change. I started yesterday and have my first headache today.
On a page in my application I have this image element:
<img src="loadImage.ashx?p=rqrewrwr">
and on loadImage.ashx, I have this exact code:
-------------------------------------------------
<%# WebHandler Language="C#" Class="Handler" %>
string url = "https://............10000.JPG";
byte[] imageData;
using (WebClient client = new WebClient()) {
imageData = client.DownloadData(url);
}
public void ProcessRequest(HttpContext context)
{
context.Response.OutputStream.Write(imageData, 0, imageData.Length);
}
-------------------------------------------------
There is probably quite a lot wrong with this, as it's my first attempt at .net and don't know what I'm doing. To start with, I'm getting the following error but sure there's more to come.
CS0116: A namespace does not directly contain members such as fields or methods
This is on line 3, which is string url = "https://............"

For an HttpHandler, you have to put the code in the code behind... if you expand loadimage.ashx in Solution Explorer, you should see a loadimage.ashx.cs file. This file is where your logic should be, and all of it should be in the ProcessRequest method.
So loadimage.ashx should be basically empty:
<%# WebHandler Language="C#" Class="loadimage" %>
And loadimage.ashx.cs should contain the rest:
using System.Web;
public class loadimage : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string url = "https://............10000.JPG";
byte[] imageData;
using (WebClient client = new WebClient())
{
imageData = client.DownloadData(url);
}
context.Response.OutputStream.Write(imageData, 0, imageData.Length);
}
public bool IsReusable
{
get { return false; }
}
}
Alternatively, you can create an aspx page that serves the image. This removes the code behind requirement, but adds a little more overhead... create a loadimage.aspx page with the following:
<%# Page Language="C#" AutoEventWireup="true" %>
<script language="c#" runat="server">
public void Page_Load(object sender, EventArgs e)
{
string url = "https://............10000.JPG";
byte[] imageData;
using (System.Net.WebClient client = new System.Net.WebClient())
{
imageData = client.DownloadData(url);
}
Response.ContentType = "image/png"; // Change the content type if necessary
Response.OutputStream.Write(imageData, 0, imageData.Length);
Response.Flush();
Response.End();
}
</script>
Then reference this loadimage.aspx in the image src instead of the ashx.

Related

How to access and output images present in the resources in C# to html code?

I want to generate and output an html file with images using C# winforms. I have a few images in the Resources folder, but I'm not able to output them to html.
Could anyone suggest how to access and output images present in Resources to an html file?
My code:
using System;
using System.Windows.Forms;
using System.IO;
namespace winformToHtml
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btn_report_Click(object sender, EventArgs e)
{
StreamWriter sWrite = new StreamWriter("C:\\report.html");
sWrite.WriteLine("<html>");
sWrite.WriteLine("<body>");
sWrite.WriteLine("<p> <img src= 'Resources/image.png' height='10%' width='5%' > </p>");
sWrite.WriteLine("<body>");
sWrite.WriteLine("<html>");
sWrite.Close();
}
}
}
You can use IMG base 64 syntax to render your picture :
public static String Base64Encoded(Image image)
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, ImageFormat.Jpeg);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
Then :
sWrite.WriteLine("<p><img src='data:image/jpeg;base64," + Base64Encoded(Resource.Image) + "' height='10%' width='5%' > </p>");
Your question is missing parts from the story. I'm assuming you have embedded resources in your application and you write an html file that should work from outside your application. The html file references images that are embedded in your executable.
You need to extract those resources to the directory where you write the html file.
If they aren't embedded, you can just use File.Copy().
If you want the html file to be self-contained (i.e. no external references), you can also write the images in the html using base64, for that see #Haga's answer.

How to Reference HTTP Handler from UserControl

I'm a newb when it comes to creating an ASP.NET custom user control that will render and return .png charts to an ASP.NET web application.
I've created a simple sandbox project that creates an ellipse on a bitmap, renders it to a MemoryStream, and now I want to stream the output connected via an HTTP handler so as to render an asp:image in my markup page.
My problem is that I don't know how to connect the MemoryStream created in my usercontrol to the GetImage method of the http handler. I know that the GetMethod of the HTTP Handler creating a memory stream within the method isn't correct, but I don't know how to access the memorystream of the codebehind.
My prototype test project code is:
namespace ChartControl
{
public partial class ChartCtl : System.Web.UI.UserControl
{
private int imageHeight = 150;
private int imageWidth = 400;
protected void Page_Load(object sender, EventArgs e)
{
renderChart();
}
protected MemoryStream renderChart()
{
Image imgChart = new Bitmap(imageWidth, imageHeight);
Graphics g = Graphics.FromImage(imgChart);
Rectangle r = new Rectangle(0, 0, imageWidth, imageHeight);
g.DrawEllipse(Pens.Orange, g.VisibleClipBounds);
MemoryStream ms = new MemoryStream();
imgChart.Save(ms, ImageFormat.Png);
return ms;
}
}
}
My HTTP Handler is:
namespace WIChart.UserControls
{
public class ImageHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
if (!String.IsNullOrEmpty(context.Request.QueryString["id"]))
{
int id = Int32.Parse(context.Request.QueryString["id"]);
// Now we have the id, just pass it to GetImage to build the image
Image image = GetImage(id);
context.Response.ContentType = "image/png";
image.Save(context.Response.OutputStream, ImageFormat.Png);
}
else
{
context.Response.ContentType = "text/html";
context.Response.Write("<p>Valid id is required.</p>");
}
}
#region IHttpHandler Members
public bool IsReusable
{
get { return false; }
}
private Image GetImage(int id)
{
MemoryStream stream = new MemoryStream();
return Image.FromStream(stream);
}
#endregion
}
}
My .ascx page is:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="ChartCtl.ascx.cs" Inherits="ChartControl.ChartCtl" %>
<%# Register Assembly="System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI.DataVisualization.Charting" TagPrefix="asp" %>
<div class="content-wrapper">
<div class="float-left">
<p class="site-title">
<asp:Image id="imgChart" ImageUrl="~/ImageHandler.ashx?id=1" runat="server" />
</p>
</div>
</div>
Thank you for any help that you can provide!
I couldn't understand what exactly you need here. But You can load image from user control using below code.
using System.Web;
using System.Web.UI;
using System.IO;
namespace WebApplication1
{
public class ImageHandler : Page, IHttpHandler
{
public new void ProcessRequest(HttpContext context)
{
context.Response.Clear();
ChartCtl chartCtl = (ChartCtl)LoadControl(ResolveClientUrl("ChartCtl.ascx"));
MemoryStream ms = new MemoryStream();
ms = chartCtl.renderChart(ms);
context.Response.Clear();
context.Response.ContentType = "image/jpeg";
context.Response.BinaryWrite(ReadFully(ms));
context.Response.End();
}
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
#region IHttpHandler Members
public new bool IsReusable
{
get { return false; }
}
#endregion
}
}
HTML-
<asp:Image ID="imgChart" ImageUrl="~/ImageHandler.ashx" runat="server" />
ChartCtrl -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
namespace WebApplication1
{
public partial class ChartCtl : System.Web.UI.UserControl
{
private int imageHeight = 150;
private int imageWidth = 400;
public MemoryStream renderChart(MemoryStream ms)
{
Image imgChart = new Bitmap(imageWidth, imageHeight);
Graphics g = Graphics.FromImage(imgChart);
Rectangle r = new Rectangle(0, 0, imageWidth, imageHeight);
g.DrawEllipse(Pens.SteelBlue, g.VisibleClipBounds);
imgChart.Save(ms, ImageFormat.Jpeg); // save the image to the memorystream to be processed via the Image/HttpHandler
imgChart.Save(Context.Response.OutputStream, ImageFormat.Jpeg); // save to drive just to verify that image is being properly created.
return ms;
}
}
}
Web.Config [IIS 7] -
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<handlers>
<add name="ImageHandler" verb="*"
path="ImageHandler.ashx"
type="WebApplication1.ImageHandler, WebApplication1"
resourceType="Unspecified" />
</handlers>
</system.webServer>
Mem Stream to byte array conversion is from Creating a byte array from a stream
Check this link also http://www.codeproject.com/Articles/34084/Generic-Image-Handler-Using-IHttpHandler
P.S - I don't know why your code is being executed only with constructor. Without constructor I'm able to execute the code. When you are loading a web control from Handler, normal page events wouldn't get executed. We need call methods manually.
I think You need to host your website in IIS to get HTTpHandler called, I am not sure about this part.
You are coming at this a bit backwards with using your imagehandler as a page -- try to think of the page as static HTML where you are referencing an image and the answer is pretty straightforward. What you need to do is add an image tag referencing your graphic-generating handler -- ie <img src="~/MyHandler.ashx" />.
The challenge then becomes how to marshal data into the handler. There are loads of ways to handle this, the basic ones being query string variables if the data is simple or a query string with enough data so the handler can go back and load it's own data.

How to retrieve data sent from Web application?

Here i am passing the session id on a button click from one asp.net application to another asp.net application.
Application 1:
protected void imgBTN_Click(object sender, EventArgs e)
{
string sessionKey = HttpContext.Current.Session.SessionID;
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(#"http://localhost:43392/PartnerHome.aspx");
string svcCredentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(sessionKey));
req.Headers.Add("Authorization", "Basic " + svcCredentials);
try
{
using (WebResponse svcResponse = (HttpWebResponse)req.GetResponse())
{
using (StreamReader sr = new StreamReader(svcResponse.GetResponseStream()))
{
string jsonTxt = sr.ReadToEnd();
}
}
}
catch (Exception c)
{
}
}
and my problem here is how to retrieve this session id there in my second asp.net application pageload
Application 2:
protected void Page_Load(object sender, EventArgs e)
{
}
Any Suggestion?
Another solution:
What I would do is to add an invisible image (some transparant pixel) on the page of application 1:
<img src="http://site2.domain.com/transpimage.aspx">
The invisible image would actually be a asp.net page hosted by site 2.
In the page load event of transpimage.aspx. I would output some image:
public void Page_Load(...)
{
using(Bitmap image = new Bitmap(1,1))
using(MemoryStream stream = new MemoryStream())
{
image.Save(stream);
Response.ContentType = "image/png";
stream.WriteTo(Response.OutputStream);
Response.End();
}
}
Since the image from application 2 is served by an aspx page (not a static image in a file) it will keep the session of application2 alive. I've done this before and it tends to be fairly robust.
If you are familiar with HttpHandlers you can write the "image page" as a handler, but don't forget that if you do it as a handler you need to inherit from the IRequiresSessionState interface to actually acccess the session.
Hope this helps!

C# Image Gallery - Image Button Not Showing

I'm making a C# image gallery for a website (I know there's many free ones out there, but I want the experience). I'm grabbing files from a directory on the website by storing them in a array.
protected void Page_Load(object sender, EventArgs e)
{
string[] files = null;
files = Directory.GetFiles(Server.MapPath(#"Pictures"),"*.jpg");
I then am creating an array of Imagebuttons (which I will use as thumb-nails) and I'm dynamically adding them into a panel on the web form. However, the image buttons are added on the form correctly, but the pictures show the little square/circle/triangle symbol and fail to load the actual image.
ImageButton[] arrIbs = new ImageButton[files.Length - 1];
for (int i = 0; i < files.Length-1; i++)
{
arrIbs[i] = new ImageButton();
arrIbs[i].ID = "imgbtn" + Convert.ToString(i);
arrIbs[i].ImageUrl = Convert.ToString(files[i]);
Response.Write(Convert.ToString(files[i]) + "**--**");
arrIbs[i].Width = 160;
arrIbs[i].Height = 100;
arrIbs[i].BorderStyle = BorderStyle.Inset;
//arrIbs[i].BorderStyle = 2;
arrIbs[i].AlternateText = System.IO.Path.GetFileName(Convert.ToString(files[i]));
arrIbs[i].PostBackUrl = "default.aspx?Img=" + Convert.ToString(files[i]);
pnlThumbs.Controls.Add(arrIbs[i]);
}
}
This may or may not be related to the issue (if not related, it is a sub-question). When setting the Server.MapPath() to #"~/Gallery/Pictures" (which is where the directory is in relevance to the site root) I get an error. It states that "C:/.../.../.../... could not be found" The web-site only builds if I set the directory as "Pictures", which is where the pictures are, and "Pictures" is in the same folder as "Default.aspx" which the above code is at. I never have much luck with the ~ (tilda) character. Is this a file-structure issue, or a IIS issue?
The problem with this is that you're setting a path on the server as the image button source. The browser will try to load these images from the client's machine, hence they cannot load. You will also need to make sure that the ASPNET user on the server has permissions to that folder.
What you need to do is to serve the jpeg's streams as the source for the image buttons.
You could have an aspx page which takes in the path in a query string parameter and loads the file and serves it.
Eg, have a page called GetImage.aspx as such:
<%# Page Language="C#" %>
<%# Import Namespace="System.IO" %>
<script runat="server" language="c#">
public void Page_Load()
{
try
{
Response.Clear();
Response.ContentType = "image/jpeg";
string filename = Page.Request.QueryString["file"];
using (FileStream stream = new FileStream(filename, FileMode.Open))
{
int streamLength = (int)stream.Length;
byte[] buffer = new byte[streamLength];
stream.Read(buffer, 0, streamLength);
Response.BinaryWrite(buffer);
}
}
finally
{
Response.End();
}
}
</script>
and now when you create your ImageButtons, this should be your ImageUrl:
arrIbs[i].ImageUrl = String.Format("GetImage.aspx?file={0}", HttpUtility.UrlEncode(files[i]));

asp.net Page loading twice when making an underlying connection

I have a aspx page that seems to be loading twice when I enter the Url to the page.
In this page's loading event, I'm making an connection to a server to retrieve a document and then I output the downloaded bytes to the output stream of the page.
This is causing the page to load twice for some strange reason. If I hard code a byte array without making this connection, the page loads once and all is well.
Here are the methods used to retrieve the external document. Maybe you can see something I can't.
public static byte[] GetDocument(string url)
{
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
Stream stream = myHttpWebResponse.GetResponseStream();
byte[] _Data = StreamToBytes(stream);
return _Data;
}
private static byte[] StreamToBytes(System.IO.Stream theStream)
{
if (theStream == null)
throw new ArgumentException("URL null.");
int bytesRead = 0;
byte[] buffer = new byte[8096];
MemoryStream bufferStream = new MemoryStream();
try
{
do
{
bytesRead = theStream.Read(buffer, 0, 8096);
bufferStream.Write(buffer, 0, bytesRead);
} while (bytesRead > 0);
}
finally
{
bufferStream.Flush();
theStream.Close();
theStream.Dispose();
}
return bufferStream.ToArray();
}
The likely culprit is having the page directive of AutoEventWireup="true" in addition to OnInit() having this.Page_Load += Page_Load;
Auto Event Wireup does what it sounds like. If there is a method that follows the naming convention, the event is automatically wired up.
You also oftentimes see this on button handlers. The button handler will be set specifically, and the page will also create a button handler if the name follows the convention buttonname_OnClick(sender,args)
These kind of problems often happens due to img tags that have an empty src ...

Categories