ASP.NET - 在 GridView 中显示图像和 pdf

发布于 2024-08-12 17:38:18 字数 2292 浏览 6 评论 0原文

我想在 asp:GridView 中显示“图像”列。这个想法是提供图像的缩略图以及实际尺寸图像的链接。对于某些行,这也可以是 PDF 文档。我想要 PDF 的链接。 PDF 或图像存储在 SQL 数据库中。

现在我在处理程序 (.ashx) 文件中出现错误:

“当不存在数据时,读取尝试无效。”

这是我的代码:

ASP:

<asp:GridView ID="GridView1" runat="server" 
            AutoGenerateColumns="False" DataKeyNames="ID"
            DataSourceID="SqlDataSource1">
   <Columns>
      <asp:BoundField DataField="assessment_id" HeaderText="assessment_id" 
                    InsertVisible="False" ReadOnly="True"
                    SortExpression="assessment_id" />
      <asp:BoundField DataField="a_mime" HeaderText="a_mime" SortExpression="a_mime" />
      <asp:TemplateField HeaderText="a_data">       
        <ItemTemplate>
        <asp:Image ID="Image1" runat="server" ImageUrl='<%# "Handler.ashx?ID=" + Eval("ID")%>'/>
        </ItemTemplate>
      </asp:TemplateField>
  </Columns>
</asp:GridView>

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
  ConnectionString="<%$ ConnectionStrings:testConnectionString %>"
  SelectCommand="SELECT [assessment_id], [a_data], [a_mime] FROM [Assessments]">    
</asp:SqlDataSource>

处理程序ASHX:

<%@ WebHandler Language="C#" Class="Handler" %>

public class Handler : IHttpHandler {

public void ProcessRequest (HttpContext context) 
{
    SqlConnection con = new SqlConnection();
    con.ConnectionString = ConfigurationManager.ConnectionStrings["testConnectionString"].ConnectionString;

    // Create SQL Command 
    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = "Select a_data from Assessments where assessment_id =@ID";
    cmd.CommandType = System.Data.CommandType.Text;
    cmd.Connection = con;

    SqlParameter ImageID = new SqlParameter("@ID", System.Data.SqlDbType.Int);
    ImageID.Value = Convert.ToInt32(context.Request.QueryString["assessment_id"]);
    cmd.Parameters.Add(ImageID);
    con.Open();

    SqlDataReader dReader = cmd.ExecuteReader();
    dReader.Read();

    context.Response.BinaryWrite((byte[])dReader["a_data"]);

    dReader.Close();

    con.Close();
}

如果可能,请帮助我。如果这很耗时,请提供示例或博客文章的链接。

I want to display in an asp:GridView an "Images" column. The idea is to provide a thumbnails of the image with link to real size image. For some rows, this may alternatively be a PDF document. I'd like the link to be to the PDF. The PDF or image are stored in a SQL database.

Now I have error in Handler (.ashx) file:

"Invalid attempt to read when no data is present."

This is my code :

ASP:

<asp:GridView ID="GridView1" runat="server" 
            AutoGenerateColumns="False" DataKeyNames="ID"
            DataSourceID="SqlDataSource1">
   <Columns>
      <asp:BoundField DataField="assessment_id" HeaderText="assessment_id" 
                    InsertVisible="False" ReadOnly="True"
                    SortExpression="assessment_id" />
      <asp:BoundField DataField="a_mime" HeaderText="a_mime" SortExpression="a_mime" />
      <asp:TemplateField HeaderText="a_data">       
        <ItemTemplate>
        <asp:Image ID="Image1" runat="server" ImageUrl='<%# "Handler.ashx?ID=" + Eval("ID")%>'/>
        </ItemTemplate>
      </asp:TemplateField>
  </Columns>
</asp:GridView>

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
  ConnectionString="<%$ ConnectionStrings:testConnectionString %>"
  SelectCommand="SELECT [assessment_id], [a_data], [a_mime] FROM [Assessments]">    
</asp:SqlDataSource>

The Handler ASHX:

<%@ WebHandler Language="C#" Class="Handler" %>

public class Handler : IHttpHandler {

public void ProcessRequest (HttpContext context) 
{
    SqlConnection con = new SqlConnection();
    con.ConnectionString = ConfigurationManager.ConnectionStrings["testConnectionString"].ConnectionString;

    // Create SQL Command 
    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = "Select a_data from Assessments where assessment_id =@ID";
    cmd.CommandType = System.Data.CommandType.Text;
    cmd.Connection = con;

    SqlParameter ImageID = new SqlParameter("@ID", System.Data.SqlDbType.Int);
    ImageID.Value = Convert.ToInt32(context.Request.QueryString["assessment_id"]);
    cmd.Parameters.Add(ImageID);
    con.Open();

    SqlDataReader dReader = cmd.ExecuteReader();
    dReader.Read();

    context.Response.BinaryWrite((byte[])dReader["a_data"]);

    dReader.Close();

    con.Close();
}

If it is possible, please help me. If it's time-consuming, please provide a link to an example or blog post.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

能怎样 2024-08-19 17:38:18

关于没有数据时读取无效尝试的错误原因是 DataReader 不包含任何记录(给定 ID 没有图像)。
考虑将您的代码更改为:

SqlDataReader dReader = cmd.ExecuteReader();

if (dReader.HasRows)
{
  while (dReader.Read())
  {
     context.Response.BinaryWrite((byte[])dReader["a_data"]);
  }

  dReader.Close();
}

一些改进建议

  • 尝试预测当您可以在 ASP.NET 页面上检测到某行没有图像
  • 调用
  • 时,执行对 .ashx 页面的 您可以检测到您需要渲染 PDF 的链接,显示一个漂亮的静态 pdf 图像,其链接将是 URL。

如果可能,请考虑检查给定的评估是否具有所需的图像或 PDF。也许添加一个 where 子句来以某种方式确定该记录是否需要显示 PDF 或图像场景。

我还可以建议您将 SQL 语句转换为存储过程,如上所述,并修改您的 SqlDataSource,如下所示:

CREATE PROC ListAssessments
AS

SELECT [assessment_id]
     , [a_data]
     , [a_mime] 
     , CASE WHEN a_mime = 'PDF' THEN 1
       ELSE 0
       END AS IsPDF

FROM Assessments  

现在,在 Gridview 上,您可以确定是要渲染图像还是 PDF 链接。

<asp:TemplateField HeaderText="Image">       
  <ItemTemplate>
     <asp:PlaceHolder id="ph1" runat="server" />    
  </ItemTemplate>
</asp:TemplateField>

将 Gridview 设置为具有一个 ItemDataBound 事件,该事件调用您可以编写的新方法。

<asp:GridView OnRowDataBound="ShowImageOrPdf" 

在代码隐藏中,您可以确定要在该占位符中呈现哪个 Web 控件。

protected void ShowImageOrPdf(object sender, GridViewRowEventArgs e)
{
    const string LINK = "handler.ashx?Id={0}&Type={1}";
    GridView gv = (GridView)sender;

    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        string assessmentID = gv.DataKeys[e.Row.RowIndex].Value.ToString();
        bool isPDF =  (bool)e.Row.DataItem["IsPDF"];
        HyperLink h = new HyperLink();

        if (isPDF)
        {
            //render a link showing that it's a PDF.
            h.NavigateUrl = string.Format(LINK, assessmentID, "PDF");
            h.ImageUrl = "http://www.adobe.com/images/pdficon_large.gif";
            h.Text = "View PDF";
        }
        else
        {
            //render a thumbnail with a link to the image
            h.NavigateUrl = string.Format(LINK, assessmentID, "IMG");

            //have the handler create a thumbnail somehow.
            h.ImageUrl = string.Concat(h.NavigateUrl + "&Size=Small");
        } 
       //write the link back to the placeholder.
       e.Row.FindControl("ph1").Controls.Add(h);
    }
}

然后,在 .ashx 中,您必须读取查询字符串参数来确定要输出的内容:图像、缩略图或存储在数据库中的 PDF 文档。

The reason for the error about Invalid attempt to read when no data is present is because the DataReader doesn't contain any records (no image for the given ID).
Consider changing your code to:

SqlDataReader dReader = cmd.ExecuteReader();

if (dReader.HasRows)
{
  while (dReader.Read())
  {
     context.Response.BinaryWrite((byte[])dReader["a_data"]);
  }

  dReader.Close();
}

A few suggestions for improvement

  • try to predict when a row won't have an image
  • when you can detect on your ASP.NET page, perform the call to the .ashx page
  • when you can detect that you need to render the link to the PDF, show a nice static pdf image and its link will be the URL.

Consider checking, where possible, that the given Assessment has the image or PDF required. Perhaps add a where clause to determine, somehow, whether this record needs to display the PDF or image scenario.

May I suggest also that you convert your SQL statements into a stored procedure, as above, and modify your SqlDataSource as such:

CREATE PROC ListAssessments
AS

SELECT [assessment_id]
     , [a_data]
     , [a_mime] 
     , CASE WHEN a_mime = 'PDF' THEN 1
       ELSE 0
       END AS IsPDF

FROM Assessments  

Now on your Gridview, you can determine whether you want to render an image or a PDF link.

<asp:TemplateField HeaderText="Image">       
  <ItemTemplate>
     <asp:PlaceHolder id="ph1" runat="server" />    
  </ItemTemplate>
</asp:TemplateField>

Setup your Gridview to have an ItemDataBound event that calls a new method that you can write.

<asp:GridView OnRowDataBound="ShowImageOrPdf" 

In your code-behind, you can then determine which webcontrol to render in that placeholder.

protected void ShowImageOrPdf(object sender, GridViewRowEventArgs e)
{
    const string LINK = "handler.ashx?Id={0}&Type={1}";
    GridView gv = (GridView)sender;

    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        string assessmentID = gv.DataKeys[e.Row.RowIndex].Value.ToString();
        bool isPDF =  (bool)e.Row.DataItem["IsPDF"];
        HyperLink h = new HyperLink();

        if (isPDF)
        {
            //render a link showing that it's a PDF.
            h.NavigateUrl = string.Format(LINK, assessmentID, "PDF");
            h.ImageUrl = "http://www.adobe.com/images/pdficon_large.gif";
            h.Text = "View PDF";
        }
        else
        {
            //render a thumbnail with a link to the image
            h.NavigateUrl = string.Format(LINK, assessmentID, "IMG");

            //have the handler create a thumbnail somehow.
            h.ImageUrl = string.Concat(h.NavigateUrl + "&Size=Small");
        } 
       //write the link back to the placeholder.
       e.Row.FindControl("ph1").Controls.Add(h);
    }
}

Then in your .ashx, you'll have to read the querystring parameters to determine what to output: an image, a thumbnail image, or the PDF document stored in the database.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文