Nov 072006
 

I frequently store documents in the database for my ASP.NET apps, eliminating web farm complications with shared drives, permissions, etc.  When uploading a file, my Document class reads the uploaded file, zips the file with SharpZipLib, and inserts/updates in the database.   When opening a file, I have always used an ASPX page that uses the Document class to unzip the file, and then changes the Content-Disposition and ContentType headers, and then does a BinaryWrite to the Response object to display the file.


I have been using Handlers a lot lately, and figured that it was time to make this process a little more elegant.  If you’ve never written a handler, it’s quite simple.  You need to make a web.config change, and add a new class that implementts IHttpHandler.  All of the work is done in ProcessRequest.  Using the default .ashx extension for the handler eliminates the need to make any changes in IIS.  I thought about changing the handler to accept all requests with known file extensions with the document ID as the filename, like 3383.pdf.  I just figured that using the default extnesion would be easier.   Laziness or efficiency, you decide.  Check out the code.


In <system.web> in web.config:



<httpHandlers>
   
<add verb=”*” path=”DocumentHandler.ashx” type=”TestingWebApp.DocumentHandler, TestingWebApp” />
</httpHandlers>


DocumentHandler.cs:



using System;
using System.Web;

namespace TestingWebApp
{
    public class DocumentHandler : IHttpHandler
    {
        private int DocumentId
        {
            get
            {
                if(System.Web.HttpContext.Current.Request.QueryString[“DocumentId”] != null && System.Web.HttpContext.Current.Request.QueryString[“DocumentId”].ToString().Length > 0)
                    return Convert.ToInt32(System.Web.HttpContext.Current.Request.QueryString[“DocumentId”]);
                else
                    throw new ApplicationException(“Document Handler requires a DocumentId”);
            }
        }

        #region IHttpHandler Members

        public void ProcessRequest(System.Web.HttpContext context)
        {
            context.Response.Cache.SetCacheability(HttpCacheability.Public);
            context.Response.BufferOutput = false;
            
            Document document = Document.GetDocumentByDocumentId(this.DocumentId);

            byte[] buffer = document.UnzippedBinary;
            context.Response.ContentType = document.ContentType;
            context.Response.OutputStream.Write(buffer, 0, buffer.Length);
        }

        public bool IsReusable
        {
            get { return true; }
        }

        #endregion
    }
}

 Posted by at 4:31 am
Nov 062006
 

The starter kit already allowed individual file upload, and batch upload from a directory which requires files to be moved to Upload directory by FTP.  The starter kit also stores the images in the database. While I prefer this method for most files, I don’t prefer it for images. I changed a few methods to store the images in an images folder, and modified the image serving handler accordingly.  The album page load time is a fraction of what it was with images in the database.


I also created an XP Publishing Wizard that allows any user with credentials to create/choose an album, and upload images from Windows XP. The beauty of the XPPW is that it can resize the images before uploading. That way all of us with 10 megapixel cameras no longer have to spend any extra time resizing to prevent reaching a web host storage quota.


A few articles helped me figure this stuff out:



Creating the wizard was easy enough.  You first need to create a registry entry in the following format:


Windows Registry Editor Version 5.00

[HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionExplorerPublishingWizardPublishingWizardProvidersYour Photo Gallery]
“displayname”=”Your Photo Gallery”
“description”=”Online Photo Albums”
“href”=”http://www.yoursite.net/XPPublish.aspx”
“icon”=”http://www.yoursite.net/favicon.ico”


Next is a single aspx page that accepts the files.  The page handles user login, album creation/selection, and accepts multiple files in a single form post.  All the hard work is done by some javascript methods that handle the XML sent from Windows XP.  The javascript looks like this:


        <script language=’javascript’>
            function startUpload()
            {
                var xml = window.external.Property(“TransferManifest”);
                var files = xml.selectNodes(“transfermanifest/filelist/file”);
                var albumId = document.getElementById(“Album”).value;

                for (i = 0; i < files.length; i++)
                {
                    var postTag = xml.createNode(1, “post”, “”);
                    postTag.setAttribute(“href”, “http://yoursite.net/XPPublish.aspx“);

                    postTag.setAttribute(“name”, “userpicture”);

                    var dataTag = xml.createNode(1, “formdata”, “”);
                    dataTag.setAttribute(“name”, “MAX_FILE_SIZE”);
                    dataTag.text = “10000000”;                    
                    postTag.appendChild(dataTag);
                    
                    var dataTag1 = xml.createNode(1, “formdata”, “”);
                    dataTag1.setAttribute(“name”, “btnUpload”);
                    dataTag1.text = “Save”;
                    postTag.appendChild(dataTag1);
                    
                    var dataTag2 = xml.createNode(1, “formdata”, “”);
                    dataTag2.setAttribute(“name”, “hidAlbumId”);
                    dataTag2.text = albumId;
                    postTag.appendChild(dataTag2);

                    files.item(i).appendChild(postTag);
                }
                
                var uploadTag = xml.createNode(1, “uploadinfo”, “”);
                uploadTag.setAttribute(“friendlyname”, “Family Photo Gallery”);
                var htmluiTag = xml.createNode(1, “htmlui”, “”);
                htmluiTag.text = “http://yoursite.net/Personal/Albums/Photos.aspx?AlbumID=” + albumId;
                uploadTag.appendChild(htmluiTag);

                xml.documentElement.appendChild(uploadTag);

                window.external.Property(“TransferManifest”) = xml;
                window.external.SetWizardButtons(true,true,true);
                document.getElementById(“divContent”).innerHtml = xml;
                window.external.FinalNext();
            }

            function OnBack()
            {
                window.external.FinalBack();
                window.external.SetWizardButtons(false,true,false);
            }

            function OnNext()
            {
                if (document.getElementById(“divLogin”))
                {
                    document.getElementById(“LoginArea_Login1_LoginButton”).click();
                }
                else
                {
                    startUpload();
                }
            }

            function OnCancel()
            {
            }

            function window.onload()
            {
                window.external.SetHeaderText(‘Photo Gallery’,’Your Photos’);
                window.external.SetWizardButtons(true,true,false);
            }
        </script>


In case you haven’t seen the XP Publishing Wizard in action, check out these screenshots:



 



 



 



 



 



 



 



 



 

 Posted by at 2:35 am
Nov 042006
 

I record only a few shows on my DVR.  While fast-forwarding through commercials during last night’s Battlestar Galactica, I saw a familiar image and had to rewind.  Ahhh… and then it appeared as a voice said “Tonight’s episode is brought to you by Microsoft Visual Studio 2005.”  Seeing that made me feel twice as dorky for watching that show.

 Posted by at 9:13 pm