views:

45

answers:

2

Hi there,

I have a MVC 2 web application. The website captures grant applications for loans. With each application I can upload documents. The way that we upload documents to the database is as follows:

private IEnumerable<byte> GetStreamByteArrayData(Stream stream)
{
   byte[] buffer = new byte[8192];
   int bytesRead = 0;
   while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
   {
      for (int byteIndex = 0; byteIndex < bytesRead; byteIndex++)
      {
         yield return buffer[byteIndex];
      }
   }
}

The calling method looks like this:

Convert.ToBase64String(GetStreamByteArrayData(hpf.InputStream).ToArray());

In my grid that displays the uploaded documents I have the document name, mime type and so forth. What I am trying to do is to have the name of the document in a link. When the link is clicked then the document is opened. I have no idea how to do this in an MVC app.

Can someone please advise or provide some sample source code? All help would be appreciated.

Thanks.

A: 

Making an .ashx handler that BinaryWrites the content might help. Following is one way of achieving that:

STEP 1: Load

  • Load your data into the DataTable (assuming that you have an ID column as well)
  • Add a template item of type link in your markup
  • Add a LINK column and set the records like http://yourpath/ShowContent.ashx?ID=111 (for instance, Id is the primary key) by either going through each record or when saving the records in the database.
  • Set and DataBind it to the GridView

STEP 2: Display

Upon click on a link in the GridView, it shall call the ShowContent.ashx; handle the event there and following shall happen:

  • Get the event in ShowContent.ashx
  • Get the value in the ID from query string
  • Select that record from the DataTable using the ID
  • And BinaryWrite something like following:

    byte[] content = (byte[])dataRow["COL_CONTENT"]; HttpContext.Current.Response.ContentType = dataRow["COL_CONTENT_TYPE"]; HttpContext.Current.Response.BinaryWrite(content);

Note that you may need to add your DataTable/records in the session for handy processing of records.

Enjoy the example, A Boilerplate HttpHandler

KMan
+2  A: 

Assuming that you have stored the name, mime type and contents of each document into the database you could have a controller action which will serve a file given it's unique id:

public ActionResult Download(int? id)
{
    Document document = _repository.GetDocument(id);
    if (document == null)
    {
        throw new HttpException(404, "Not found");
    }

    // For example document.ContentType = "application/pdf" and 
    // document.Name = "test.pdf"
    return File(document.Contents, document.ContentType, document.Name);
}

The Document model might look something like this:

public class Document
{
    public int Id { get; set; }
    public byte[] Contents { get; set; }
    public string ContentType { get; set; }
    public string Name { get; set; }
}

And finally you could generate links to this action in your grid:

<%: Html.ActionLink("Download", "Download", new { id = "123" })%>

If you don't have the content type and name of the document stored into the database you could pass them as action parameters:

<%: Html.ActionLink("Download", "Download", 
    new { id = "123", contentType = "application/pdf", name = "test.pdf" }) %>
Darin Dimitrov
@Darin: Thank you this works just fine.
Brendan Vogt
small question, why is the id a nullable int?
Andrei Rinea