错误的原因大约是Invalid attempt to read when no data is present
是因为 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 文档。