Render image in asp.net MVC
My scenario is this:
I create o custom report based on a stored procedure that returns three columns (person_id[long], name[varchar(100)], age[int], photo[image]). Those are the columns and types in my database table.
Right now i'm using something like this for each image of the report.
<img src="<%= Url.Action("ShowImage", "Reports", new {personId = result["PERSON_ID"]}) %>" />
with ShowImage being
public virtual ActionResult ShowImage(long? personId)
{
try
{
if (pe开发者_如何学编程rsonId.HasValue)
{
byte[] imageArray = StudentClient.GetPersonPhotoById(personId.Value);
if (imageArray == null)
return File(noPhotoArray, "image/jpg");
#region Validate that the uploaded picture is an image - temporary code
// Get Mime Type
byte[] buffer = new byte[256];
buffer = imageArray.Take(imageArray.Length >= 256 ? 256 : imageArray.Length).ToArray();
var mimeType = UrlmonMimeType.GetMimeType(buffer);
if (String.IsNullOrEmpty(mimeType) || mimeType.IndexOf("image") == -1)
return File(noPhotoArray, "image/jpg");
#endregion
return File(imageArray, "image/jpg");
}
}
catch
{
return File(noPhotoArray, "image/jpg");
}
}
I would like to use some sort of alternative because this is very stresful due to the fact the ShowImage() calls a service method StudentClient.GetPersonPhotoById(personId.Value); for every single picture, meaning allot of calls to the service and the DB also.
I would like to actually use that photo column that returns a byte array instead of using the Person_id column through the ShowImage controller method.
That would practicaly reduce the number of calls to the service to 0 and use the actual data from the image column. This seems pretty straight forward but I struggle to find a solution.
Thank you!
Simplest solution - use OutputCache. Moreover, you can set cache location to client, and the browser will cache the images once they're downloaded. VaryByParam will give you the ability to cache images depending on personId.
There's quite a neat technique where you can stream the binary data directly from the SQL Server to the client, via the webserver.
This is my code for doing it:
public void StreamFile(Stream stream)
{
DbDataReader dr = LoadDbStream();
if (!dr.Read())
return;
const int BUFFERSIZE = 512;
byte[] Buffer = new byte[BUFFERSIZE];
long StartIndex = 0;
long Read = dr.GetBytes(0, StartIndex, Buffer, 0, BUFFERSIZE);
while (Read == BUFFERSIZE)
{
stream.Write(Buffer, 0, BUFFERSIZE);
StartIndex += BUFFERSIZE;
Read = dr.GetBytes(0, StartIndex, Buffer, 0, BUFFERSIZE);
}
stream.Write(Buffer, 0, (int)Read);
}
private DbDataReader LoadDbStream()
{
DbCommand cmd = Cms.Data.GetCommand("SELECT Data FROM CMS_Files WHERE FileId = @FileId", "@FileId", Id.ToString());
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection.Open();
return cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection);
}
The command object is an ordinary command object. The key part is the CommandBehavior.SequentialAccess flag as this makes sql server only send data when you ask for. You therefore can only read the columns in the order they are specified in the query. the other point to make is stream should be the outputstream from the request & switch output buffering off.
Couple this with outputcaching and you reduce the memory load on the server.
Simon
You can use this as source form the image.
src="data:image/jpg;base64,<%= System.Convert.ToBase64String(result["PHOTO"] as byte[]) %>"
精彩评论