Pergunta

On my aspx page I have a dynamically created menu of links to documents that are stored in an Oracle Database.

When the user clicks on a link within the menu, it calls a JScript function which calls a WebMethod decorated vb.net Procedure in the code behind page. This function is passed the element ID which it uses to query the Oracle database and return the corresponding blob object which is the document the user requested.

When I was testing this, I hooked it up to a button, hard coded everything and was able to return the document to the browser which worked with no issues. Below is what I used to return the blob object to the browser.

Response.Clear()
Response.ClearContent()
Response.ClearHeaders()

Response.Buffer = True
Response.AddHeader("Content-Disposition", "attachment; filename=" + docname)
Response.ContentType = "application/pdf"

Response.BinaryWrite(bytes)

Now that I've moved the code into the callable method. I just learned that I can't use Response to write the file i've pulled from the database to the browser. Or if it can be done I have no clue how to do it. Here is the following code.

ASPX page.

 <%@ Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/Site.Master" CodeBehind="FrmBookMain.aspx.vb" Inherits="ccc.com.FormsBook" %>

<%@ Register Assembly="Obout.Ajax.UI" Namespace="Obout.Ajax.UI.TreeView" TagPrefix="obout" %>
<%@ Register assembly="obout_Splitter2_Net" namespace="OboutInc.Splitter2" tagprefix="obspl" %>
<%@ Register assembly="System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" namespace="System.Web.UI" tagprefix="cc1" %>
<%@ Register assembly="obout_Interface" namespace="Obout.Interface" tagprefix="cc2" %>
<%@ Register assembly="obout_EasyMenu_Pro" namespace="OboutInc.EasyMenu_Pro" tagprefix="oem" %>
<%@ Register assembly="System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" namespace="System.Web.UI.HtmlControls" tagprefix="cc3" %>


<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<div style="width:900px; height:450px">


<obspl:Splitter ID="spl1" runat="server">
    
    <leftpanel>
        <content>
            <asp:PlaceHolder ID="placeHolder1" EnableViewState="false" runat="server"></asp:PlaceHolder>
        </content>
    </leftpanel>
   
    <RightPanel>
        <Content>
            <div class="tdText" style="width:400px;height:80%;padding-left:30px;padding-top:30px">
                        <h2>Document Repository</h2>
                        Choose a document from the left menu...
            </div>
        </Content>
    </RightPanel>
</obspl:Splitter>

</div>
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true"/>
<script type="text/javascript" src="../Java/Frm_JScript.js"/> 

</asp:Content>

JavaScript Code

function GetDocument(src) {
 PageMethods.wbmGetDocument(src);
}

VB.net Module

Module modGetDoc_Frm

<WebMethod()>
    Public Sub wbmGetDocument(ByVal sID As String)

        Dim dr As OracleDataReader = Get_DataReader(sSql_GetDocument(sID))
        Dim blob As OracleBlob = dr.GetOracleBlob(1)

        Dim bytes(blob.Length) As Byte : blob.Read(bytes, 0, blob.Length)

        Dim doctype As String = dr(2).ToString()
        Dim docname As String = dr(3).ToString()
        
      *** Everything below won't work in module is there an alternative or what am I doing wrong***
        Response.Clear()
        Response.ClearContent()
        Response.ClearHeaders()
        Response.Buffer = True
        
        Response.AddHeader("Content-Disposition", "attachment; filename=" + docname)
        Response.ContentType = "application/pdf"
        Response.BinaryWrite(bytes)


    End Sub


End Module

FIX

As @Icarus said below I added a .ashx page called it from the java script, and allowed it to process the files. Doing it this way allows you to access response stream from codebehind. This link helped me understand .ashx pages in more detail http://www.dotnetperls.com/ashx

JavaScript

function GetDocument(id) {
    window.open('FrmDocHandler.ashx?ID=' + id);
}

.ashx code

 Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

        Dim sID As String = context.Request.QueryString("id")

        Dim fileName As String
        Dim fileType As String
        Dim bytes() As Byte

        bytes = Get_Blob(fileName, fileType, sSql_GetDocument(sID))
        context.Response.Clear()
        'clear the content of the browser
        context.Response.ClearContent()
        context.Response.ClearHeaders()
        context.Response.Buffer = True

        context.Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName)

        context.Response.ContentType = GetMIMEType(fileType)

        context.Response.BinaryWrite(bytes)
Foi útil?

Solução

The reason you can't do this is because you are now in the context of an XML HTTP Request (better known as AJAX) and you can't write binary data directly to the response unless you use the hack or the new features in XMLHttpRequest2 documented here.

If you don't want to resort to hacks or risk not being widely supported in some browsers, one alternative would be to simply -from Javascript- open a new window with the document id passed as parameter in the url. Something like:

function GetDocument(src) {
   window.open('FileHandler.ashx?docId='+src);
}

And then stream the PDF as you are doing it now.

FileHandler.ashx can be either an Http Handler or if you want to keep it simple, make it a normal aspx page, grab the id from Request.QueryString and stream the PDF.

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