在asp.net MVC中渲染图像

时间:2011-07-08 13:45:36

标签: asp.net sql-server asp.net-mvc uiviewcontroller

我的情况是:

我根据存储过程创建自定义报告,该存储过程返回三列(person_id [long],name [varchar(100)],age [int],photo [image])。这些是我的数据库表中的列和类型。

现在我正在为报告的每个图像使用这样的东西。

<img src="<%= Url.Action("ShowImage", "Reports", new {personId = result["PERSON_ID"]}) %>" />

ShowImage为

 public virtual ActionResult ShowImage(long? personId)
    {
            try
            {
                if (personId.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");
            }
    }

我想使用某种替代方法,因为ShowImage()调用服务方法StudentClient.GetPersonPhotoById(personId.Value)这是非常有意义的。对于每一张图片,意味着分配对服务和DB的调用。

我想实际使用返回字节数组的照片列,而不是通过ShowImage控制器方法使用Person_id列。

这实际上会将对服务的调用次数减少为0并使用image列中的实际数据。这似乎非常简单,但我很难找到解决方案。

谢谢!

3 个答案:

答案 0 :(得分:3)

最简单的解决方案 - 使用OutputCache。此外,您可以将缓存位置设置为客户端,浏览器将在下载后缓存图像。 VaryByParam将使您能够根据personId缓存图像。

答案 1 :(得分:0)

有一种非常巧妙的技术,您可以通过网络服务器将二进制数据直接从SQL Server流式传输到客户端。

这是我的代码:

    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);
    }

命令对象是普通的命令对象。关键部分是CommandBehavior.SequentialAccess标志,因为这使得sql server只在你要求时发送数据。因此,您只能按查询中指定的顺序读取列。要做的另一点是流应该是来自请求和输出的输出流。切换输出缓冲。

将此与outputcaching结合使用,可以减少服务器上的内存负载。

西蒙

答案 2 :(得分:0)

您可以将其用作图像的来源。

src="data:image/jpg;base64,<%= System.Convert.ToBase64String(result["PHOTO"] as byte[]) %>"