Sunday, 11 September 2011

Uploading and Downloading files (any) into Database using nHibernate in ASP.NET


In this post, I am going to give an example of how to Upload and download files into Database using nHibernate in ASP.NET applications. Here, we can upload any type of files into the database and when we download it will save the file in a specified location. This example does not give an idea of viewing the files in the page as the file can be any format like .pdf, .doc, .mp3, .wmv etc.,

Note: As this example implemented using nHibernate, the developer should have the knowledge of nHibernate for implementing the same.

To implement this example, I have three projects in a solution for clear understanding and separation of Entities and Data components.

  1. SaveFileInDB – is WebApplication which has the User Interface screen and required functions.
  2. SaveFileInDB.Entities – is class library project, has entity classes and .hbm files for defining entity attributes with database fields.
  3. SaveFileInDB.DataAccess – is class library project, has the database related functions such as Save, Delete etc., these functions uses nHibernate for doing database operations.

Below is the screenshot how the solution looks like.

The SaveFileInDB.Entities project used for defining entities and related .hbm files. It contains three files.

  1. Document.cs – defines the class Document, which has the properties of a document.
  2. DocumentContent.cs - defines the class DocumentContent which has the actual file content. This class inherited by class Document, so by referring class DocumentContent refers to file content with its properties and referring class Document refers the file properties only. This is useful when transferring only the document properties to other layers or serializing the document properties for further use.
  3. DocumentContent.hbm.xml – has the nHibernate configuration for defining how the class name and properties linked with database table and columns. Important to remember is to make the BuildAction property of this file set to Embedded Resource.

Below code shows the content for each of the files.

Document.cs
public class Document
{
    public string Type { get; set; }
    public string Filename { get; set; }
    public string Description { get; set; }
    public long Id { get; set; }
    public Document() { }
}
DocumentContent.cs
/// <summary>
/// This class is used to hold the content of a document.
/// </summary>
public class DocumentContent : Document
{
    /// <summary>
    /// Gets or sets the view status of the document.
    /// </summary>
    /// <value>The view status of the document. It can hold any value.</value>
    public byte[] Content { get; set; }
    public DocumentContent() { }
}
DocumentContent.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="SaveFileInDB.Entities"
                   assembly="SaveFileInDB.Entities">
  <class name="DocumentContent" table="[document]" lazy="false">
    <id name="Id" column="[document_id]" type="Int64" >
      <generator class="native"/>
    </id>

    <property name="Content" column="[content]" type="BinaryBlob" />
    <property name="Type" column="[type]" type="String" length="50"/>
    <property name="Filename" column="[filename]" type="String" length="50"/>
    <property name="Description" column="[description]" type="String" length="50"/>

  </class>
</hibernate-mapping>

The DataAccess project (SaveFileInDB.DataAccess) contains a class for database functionalities. It contains a class DocumentDataAccess defining functions for uploading and downloading files into the datbase table.

The source code for DocumentDataAccess
public class DocumentDataAccess
{
    public DocumentDataAccess()
    {
    }
    private string GetConfigFilePath
    {
        get
        {
            string path = HttpContext.Current.Request.PhysicalApplicationPath;
            if (!path.EndsWith("\\"))
                path = path + "\\";

            path = path + "nhibernate.config";
            return path;
        }
    }
    /// <summary>
    /// For creating a document record in the database
    /// </summary>
    /// <param name="document">Document</param>
    /// <returns>Document</returns>
    public DocumentContent Create(DocumentContent document)
    {
        try
        {
            // Create the configuration object
            Configuration cfg = new Configuration();
            cfg.Configure(GetConfigFilePath);

            // Create the session
            ISessionFactory sessionFactory = cfg.BuildSessionFactory();

            // Create session
            using (var session = sessionFactory.OpenSession())
            {
                // Begin a transaction
                using (var tx = session.BeginTransaction())
                {
                    try
                    {
                        // Create
                        document.Id = (Int64)session.Save(document);

                        // Flush session and Commit Transaction
                        tx.Commit();
                    }
                    catch
                    {
                        // Rollback if exception thrown
                        tx.Rollback();
                        throw;
                    }
                }
            }
            // Return document
            return document;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
    /// <summary>
    /// For updating a particular document record in the database
    /// </summary>
    /// <param name="document">Document</param>
    /// <returns>Document</returns>
    public DocumentContent Update(DocumentContent document)
    {
        try
        {
            // Create the configuration object
            Configuration cfg = new Configuration();
            cfg.Configure(GetConfigFilePath);

            // Create the session
            ISessionFactory sessionFactory = cfg.BuildSessionFactory();

            // Create session
            DocumentContent oldDocument;
            using (var session = sessionFactory.OpenSession())
            {
                // Begin a transaction
                using (var tx = session.BeginTransaction())
                {
                    try
                    {
                        // Get old entity
                        oldDocument = session.CreateCriteria(typeof(DocumentContent))
                            .Add(Restrictions.Eq("Id", document.Id)).UniqueResult<DocumentContent>();

                        // Throw exception if none found
                        if (oldDocument == null)
                        {
                            throw new System.IO.FileNotFoundException(
                                string.Format("The given document with id[{0}] does not exist.", document.Id));
                        }

                        // remove it from the cache
                        session.Evict(oldDocument);

                        // Do a clean update
                        session.SaveOrUpdate(document);

                        // Flush session and Commit Transaction
                        tx.Commit();
                    }
                    catch (Exception ex)
                    {
                        // Rollback if exception thrown
                        tx.Rollback();
                        throw ex;
                    }
                }
            }

            // Return document
            return document;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
    /// <summary>
    /// For deleting a document record from the database
    /// </summary>
    /// <param name="documentId">Document Id</param>
    /// <returns>true if successful, error when failes</returns>
    public bool Delete(long documentId)
    {
        try
        {
            // Create the configuration object
            Configuration cfg = new Configuration();
            cfg.Configure(GetConfigFilePath);

            // Create the session
            ISessionFactory sessionFactory = cfg.BuildSessionFactory();

            // Create session
            DocumentContent document;
            using (var session = sessionFactory.OpenSession())
            {
                // Begin a transaction
                using (var tx = session.BeginTransaction())
                {
                    try
                    {
                        // Get old entity
                        document = session.CreateCriteria(typeof(DocumentContent))
                            .Add(Restrictions.Eq("Id", documentId)).UniqueResult<DocumentContent>();

                        // Throw exception if none found
                        if (document == null)
                        {
                            throw new System.IO.FileNotFoundException(
                                string.Format("The given document with id[{0}] does not exist.", documentId));
                        }

                        // To clean the session, because we just use the 'session.Get' method.
                        session.Clear();

                        // Delete the given entity.
                        session.Delete(document);
                        session.Flush();

                        // Flush session and Commit Transaction
                        tx.Commit();
                    }
                    catch (Exception ex)
                    {
                        // Rollback if exception thrown
                        tx.Rollback();

                       throw ex;
                    }
                }
            }

            // Return document
            return true;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
    /// <summary>
    /// Get a particular document from the database
    /// </summary>
    /// <param name="documentId">Document Id</param>
    /// <returns>document</returns>
    public DocumentContent Get(long documentId)
    {
        try
        { 
            // Create the configuration object
            Configuration cfg = new Configuration();
            cfg.Configure(GetConfigFilePath);

            // Create the session
            ISessionFactory sessionFactory = cfg.BuildSessionFactory();

            // Create session
            DocumentContent document;
            using (var session = sessionFactory.OpenSession())
            {
                // Get document
                document = session.CreateCriteria(typeof(DocumentContent)).
                   Add(Restrictions.Eq("Id", documentId)).
                   UniqueResult<DocumentContent>();
            }

            // Return document
            return document;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
    /// <summary>
    /// Get all the document from the database.
    /// </summary>
    /// <returns>List of documents</returns>
    public IList<Document> GetAll()
    {
        try
        {
            // Create the configuration object
            Configuration cfg = new Configuration();
            cfg.Configure(GetConfigFilePath);

            // Create the session
            ISessionFactory sessionFactory = cfg.BuildSessionFactory();

            // Open the session
            using (ISession session = sessionFactory.OpenSession())
            {
                // Create Criteria
                ICriteria criteria = session.CreateCriteria(typeof(Document));

                // Get Cusomers
                IList<Document> customers = criteria.List<Document>();

                return customers;
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}

The Web application has a two functionalities, uploading and downloading files, each achieved in a single user interface. The functionalities of the screen are

  1. The user can upload a file by selecting the file using FileUpload control and giving the description. Save button will trigger saving to the database.
  2. The system will save the file into the database and show the list of file name, description and the size of the file stored in the database in GridView.
  3. The user can download a particular file by selecting the hyperlink provided with the file name in the grid.
  4. The system will pop up a screen for saving the file into a location.

Below is the script for Default.aspx file.
<div>
    <strong style="font-size:larger;color:Green">Uploading and Downloading file into Database using nHibernate</strong>
 
    <div style="width:500px">File name:</div><asp:FileUpload ID="fileName" runat="server" style="width:400px;" />
    <asp:RequiredFieldValidator ID="valFileName" runat="server" ControlToValidate="fileName" EnableClientScript="false">
            Fill a valid filename
    </asp:RequiredFieldValidator>

    <div style="width:500px">Description:</div><asp:TextBox ID="txtDescription" runat="server" TextMode="MultiLine" MaxLength="50" style="width:400px;" />

    <asp:Button ID="btnAttach" runat="server" OnClick="btnAttach_Click" Text="Attach" Width="100px" />

    <asp:GridView ID="gvAttachments" runat="server" CellPadding="4" 
        AutoGenerateColumns="False" GridLines="None" 
        AllowPaging="True" ForeColor="#333333" Width="*80%" 
        onrowdeleting="gvAttachments_RowDeleting" 
        onpageindexchanging="gvAttachments_PageIndexChanging" 
        onrowdatabound="gvAttachments_RowDataBound">
        <RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
        <Columns>
            <asp:TemplateField Visible="false">
                <ItemTemplate>
                    <asp:Label ID="lblId" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "Id") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:HyperLinkField DataNavigateUrlFields="Id" DataNavigateUrlFormatString="DownloadFile.ashx?id={0}" Target="_blank"
                DataTextField="Filename" HeaderText="File Name" />
            <asp:TemplateField>
                <ItemTemplate>
                    <asp:Label ID="lblSize" runat="server" Text='0'></asp:Label>
                </ItemTemplate>
                <HeaderTemplate>
                    Size
                </HeaderTemplate>
            </asp:TemplateField>
            <asp:BoundField DataField="Description" HeaderText="Description" />
            <asp:CommandField ShowDeleteButton="True" HeaderText="Delete" />
        </Columns>
        <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
        <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
        <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
        <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
        <EditRowStyle BackColor="#999999" />
        <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
    </asp:GridView>
</div>

Default.aspx.cs
public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        BindGrid();
    }
    private void BindGrid()
    {
        DocumentDataAccess documentDataAccess = new DocumentDataAccess();
        IList<Document> attachments = documentDataAccess.GetAll();
        if (attachments.Count == 0)
        {
            attachments = new List<Document> { new Document() };
        }
        gvAttachments.DataSource = attachments;
        gvAttachments.DataBind();
    }

    protected void btnAttach_Click(object sender, EventArgs e)
    {
        if (fileName.FileBytes.Length > 0)
        {
            DocumentContent doc = new DocumentContent();
            doc.Content = fileName.FileBytes;
            doc.Filename = Path.GetFileName(fileName.FileName);
            doc.Description = txtDescription.Text;
            doc.Type = fileName.PostedFile.ContentType;
            DocumentDataAccess documentDataAccess = new DocumentDataAccess();
            doc = documentDataAccess.Create(doc);
            txtDescription.Text = "";

            BindGrid();
        }
    }

    protected void gvAttachments_RowDeleting(object sender, GridViewDeleteEventArgs e)
    {
        DocumentDataAccess documentDataAccess = new DocumentDataAccess();
        documentDataAccess.Delete(Convert.ToInt32(((Label)gvAttachments.Rows[e.RowIndex].FindControl("lblId")).Text));
        BindGrid();
    }

    protected void gvAttachments_PageIndexChanging(object sender, GridViewPageEventArgs e)
    {
        gvAttachments.PageIndex = e.NewPageIndex;
        BindGrid();
    }

    protected void gvAttachments_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            LinkButton lnkDelete = (LinkButton)e.Row.Cells[4].Controls[0];
            Label lblSize = (Label)e.Row.FindControl("lblSize");
            if (((((DocumentContent)e.Row.DataItem).Content.GetLength(0)/1024)/1024) > 0)
                lblSize.Text = (((decimal)((DocumentContent)e.Row.DataItem).Content.GetLength(0) / 1024) / 1024).ToString("##.##") + " MB";
            else
                lblSize.Text = ((decimal)((DocumentContent)e.Row.DataItem).Content.GetLength(0) / 1024).ToString("##.##") + " KB";
            lnkDelete.Attributes.Add("onclick", "return confirm('Are you sure, you want to delete?')");
        }
    }
}

To download the file from the database, we have GenericHandler file - DownloadFile.ashx. Below is the code for the same.
public class DownloadFile : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";
        DocumentDataAccess documentDataAccess = new DocumentDataAccess();

        DocumentContent documentContent = documentDataAccess.Get(long.Parse(context.Request["Id"]));
        context.Response.AppendHeader("Content-Disposition", "attachment;filename=" + documentContent.Filename);
        context.Response.ContentType = documentContent.Type;
        context.Response.BinaryWrite(documentContent.Content);
    }
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Importantly we need to have nhibernate.config, which hold all the nHibernate related configurations with the database connection string.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
  <session-factory >
    <!-- properties -->
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="connection.connection_string">Data Source=THIRUMALAI-NOTE\SQLEXPRESS;Initial Catalog=Northwind;Persist Security Info=True;Trusted_Connection=Yes;Pooling=yes;connection lifetime=300;</property>
    <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name="show_sql">false</property>
    <!-- mapping files -->
    <mapping assembly="SaveFileInDB.Entities" />
  </session-factory>
</hibernate-configuration>

Note: By default, the FileUpload control allows us uploading file up to 4 MB. So to upload files more than 4 MB (4096 KB), required to add the below node in the Web.Config under <system.web> node.
<system.web>
    <httpRuntime maxRequestLength="1048576" executionTimeout="3600" />
</system.web>
Here, maxRequestLength attribute specifies the size of the file can be uploaded and executionTimeout attribute specifies the number of seconds allowed for upload operation.

For more information, please refer the following msdn link
http://msdn.microsoft.com/en-us/library/aa479405.aspx

The output of the screen for the code provided:


Download the source code in C# here and in VB here.

1 Response to “Uploading and Downloading files (any) into Database using nHibernate in ASP.NET”

  • Anonymous says:
    23 April 2015 at 14:30

    Be your own boss with pleasure builder dot com

Post a Comment