In this case I would suggest using a IHttpHandler
instead of a generic WebForm. https://msdn.microsoft.com/en-us/library/system.web.ihttphandler(v=vs.110).aspx
The handler is more suitable for this request as it will be able to respond quickly and is purpose built for handling specific requests that are not necessarily HTML based. This can be quite simple to wire up to accept a request, query the database and generate an image that you choose. Now you haven't provided much information about where the image comes from but lets look at a simple request.
To begin in a webforms web application select a new GenericHandler
which we will name DynamicImage.ashx
. Which will build our initial template as below.
public class DynamicImage : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
}
public bool IsReusable
{
get
{
return false;
}
}
}
This template provides the basics to handle our request. When the request arrives the WebServer will execute the ProcessRequest()
method passing in the HttpContext
as a parameter. From here we can use this to deliver our response.
For argument sakes lets say we are querying the image based on the QueryString
parameter username
which represents a user in our database. I have included some basic code on your steps to achieve this. (Code commented)
public void ProcessRequest(HttpContext context)
{
//get our username from the query string
var username = context.Request.QueryString["username"];
//clear the response and set the content type headers
context.Response.Clear();
context.Response.ContentType = "image/png";
//if the username is empty then end the response with a 401 not found status code
if (string.IsNullOrWhiteSpace(username))
{
context.Response.StatusCode = 401;
context.Response.End();
return;
}
//do a db query to validate the user. If not valid do a 401 not found
bool isValidUser = new UserManager().IsValidUser(username);
if (!isValidUser)
{
context.Response.StatusCode = 401;
context.Response.End();
return;
}
//get the user image file path from a server directory. If not found end with 401 not found
string filePath = context.Server.MapPath(string.Format("~/App_Data/userimages/{0}.png", username));
if (!System.IO.File.Exists(filePath))
{
context.Response.StatusCode = 401;
context.Response.End();
return;
}
//finish the response by transmitting the file
context.Response.StatusCode = 200;
context.Response.TransmitFile(filePath);
context.Response.Flush();
context.Response.End();
}
To call this handler you can simply set the src
of the image to a path similar to /DynamicImage.ashx?username=johndoe
.
Now your requirement may be slightly different. For example you may be retrieving the image from the database as a byte[]
therefore instead of using the context.Response.TransmitFile()
method you may wish to use the context.Response.BinaryWrite()
method. This method transmits a byte[]
as the response stream.
Finally I would refer you to another post (of mine) that talks about caching these images from a client perspective. This is very helpful if your button will be generated quite frequently. Leverage browser caching in IIS (google pagespeed issue)