Pergunta

Eu quero mostrar em um asp: GridView uma coluna de "Imagens". A idéia é fornecer miniaturas de imagem com link de imagem em tamanho real para. Para algumas linhas, isso pode, alternativamente, ser um documento PDF. Eu gostaria que a ligação com o PDF. O PDF ou imagem são armazenados em um banco de dados SQL.

Agora eu tenho erro no arquivo Handler (.ashx):

"Invalid tentativa de ler quando nenhum dado está presente."

Este é meu código:

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

Se for possível, por favor me ajude. Se é demorado, por favor fornecer um link para um exemplo ou blog post.

Foi útil?

Solução

A razão para o erro sobre Invalid attempt to read when no data is present é porque o DataReader não contém quaisquer registros (sem imagem para o ID fornecido). Considere alterar seu código para:

SqlDataReader dReader = cmd.ExecuteReader();

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

  dReader.Close();
}

Algumas sugestões para melhoria

  • tentar prever quando uma linha não terá uma imagem
  • quando você pode detectar na sua página ASP.NET, execute a chamada para a página de .ashx
  • quando você pode detectar que você precisa para tornar o link para o PDF, mostram uma boa imagem estática pdf e sua ligação será a URL.

Considere a verificação, sempre que possível, que o dado de Avaliação tem a imagem ou PDF necessário. Talvez adicionar uma cláusula WHERE para determinar, de alguma forma, se este registro necessidades para exibir o cenário PDF ou imagem.

Maio Sugiro também que você converter suas instruções SQL em um procedimento armazenado, como acima, e modificar seu SqlDataSource como tal:

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  

Agora, em seu GridView, você pode determinar se você deseja processar uma imagem ou um link PDF.

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

Configuração de seu Gridview para ter um evento ItemDataBound que chama um novo método que você pode escrever.

<asp:GridView OnRowDataBound="ShowImageOrPdf" 

Em seu código-behind, você pode, então, determinar quais WebControl para processar em que espaço reservado.

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

Então em seu .ashx, você vai ter que ler os parâmetros querystring para determinar o que de saída:. Uma imagem, uma imagem em miniatura, ou o documento PDF armazenado no banco de dados

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top