ASP.NET MVC Application Building #1: Family Video Website – Upload the Videos

In this series of blog entries, I build an entire ASP.NET MVC application from start to finish. I create a Family Video Website that you can use to host home videos and photographs.

I have three young children at home, a wife, and a dog. I live in Seattle and my 95 year old grandmother lives in California. My grandmother has a Windows XP computer attached to the Internet. There are over 830 miles between grandmother and grandchildren. I desperately need a website that I can use to share my family videos and photographs.

In this blog entry, I take the first step in building a Family Video Website. In this entry, I show you how you can efficiently upload large files. I also show you how to display images within an MVC view.

Uploading Large Files

Let’s start with the controller used for uploading files. The MediaController is contained in Listing 1.

Listing 1 – MediaController.vb

Imports System.IO
 
Public Class MediaController
    Inherits ControllerBase
 
    Function Create()
        Return View()
    End Function
 
    Function Insert(ByVal title As String, ByVal Text As String)
        Dim message = String.Empty
        Dim posted = Request.Files("upload")
        If posted.ContentLength > 0 Then
            Dim filePath = Me.MediaFolder & Path.GetFileName(posted.FileName)
            posted.SaveAs(Server.MapPath(filePath))
            TempData("message") = "Saved New Media"
        End If
        Return RedirectToAction("Index", "Home")
    End Function
 
End Class

The MediaController supports the following two actions:

· Create() – Displays the form for uploading a new file

· Insert() – Stores the uploaded file to the file system

Notice that the MediaController inherits from a base controller named, appropriately enough, ControllerBase. When you discover that multiple controllers in an application share the same application code then you should seriously consider creating a common base controller. The ControllerBase controller contains the application logic for retrieving the location of the media folder from the Web configuration file (web.config file). The ControllerBase class is contained in Listing 2.

Listing 2 – ControllerBase.vb

Imports System.Web.Configuration
 
Public MustInherit Class ControllerBase
    Inherits System.Web.Mvc.Controller
 
    Private _mediaFolder As String
 
    Sub New()
        Me.New(WebConfigurationManager.AppSettings("mediaFolder"))
    End Sub
 
    Sub New(ByVal mediaFolder As String)
        _mediaFolder = mediaFolder
    End Sub
 
    Public ReadOnly Property MediaFolder() As String
        Get
            Return _mediaFolder
        End Get
    End Property
 
End Class

The ControllerBase might look complicated, but it does something really simple. The ControllerBase loads the value of mediaFolder from the appSettings section in the Web configuration file.

The view that contains the form for uploading a file is contained in Listing 3.

Listing 3 – \Media\Create.aspx

<%@ Page Language="VB" AutoEventWireup="false" CodeBehind="Create.aspx.vb" Inherits="FamilyVideos.Create" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Add New Media</title>
</head>
<body>
    <div>
    
    <span class="message"><%=ViewData("message")%></span>
    
    <h1>Upload Media</h1>
  
    <form enctype="multipart/form-data" method="post" action='<%= Url.Action("Insert") %>'>
    
    <label for="upload">File:</label>
    <input name="upload" type="file" />
    <input type="submit" value="Upload File" />
    
    </form>
    
    </div>
</body>
</html>

There are several special things that you should notice about the view in Listing 3. First, notice that the form contains an <input type=”file”> tag. This tag renders a browse widget that you can use to browse for a file on your local hard drive to upload to the remote Family Videos website (see Figure 1).

Second, notice that the <form> tag includes an enctype attribute set to the value "multipart/form-data". When uploading large files, you are required to use this special MIME encoding.

Finally, notice that the action attribute has the value <%= Url.Action(“Insert”) %>. The Url.Action() method returns a URL from an action name (and optionally a controller name). Why not just use /Media/Insert for the value of the action attribute? If your application is not the root application of a website, then the URL /Media/Insert won’t work. The URL /Media/Insert retrieves a resource located at wwwroot/Media/Insert instead of application/Media/Insert.

Figure 1 – Create View

clip_image002

The ASP.NET framework is very good about handling large file uploads. The framework buffers a large file upload to a temporary file. You can control the buffering size by modifying the httpRuntime requestLengthDiskThreshold attribute. By default, a file is buffered to the temporary file in 256 byte increments.

There are two special considerations that you must be aware of when accepting large file uploads. First, by default, an ASP.NET application won’t allow you to upload a file that is larger than 4 megabytes. Because I want to allow family members to upload videos (typically around 40 megabytes), I need to override this default setting. To allow larger uploads, you need to modify the <httpRuntime> element in the Web configuration (web.config) file to look like this:

<httpRuntime maxRequestLength="99999"/>

The other special consideration that you need to be aware of concerns directory security. The Family Video application stores all files in a folder located at the following path:

\MediaFiles\

You won’t run into any problems using this path while working with the ASP.NET Development Web Server. However, as soon as you start hosting your application on a real web server, you’ll encounter problems. The problem is that you won’t have write permissions on this folder. To provide write permissions on a folder, you must right-click the folder, select Properties, select Security and give write permissions to the right user (see Figure 2).

Who is the right user? If you are using Internet Information Services 7.0 then give write permissions to the IIS_IUSERS account. For Windows Server 2003, give write permissions to the Network Service account. Any other operating system, give write permissions to the ASPNET account.

Figure 2 – Granting Write permissions

clip_image004

I know that these permission issues are going to cause problems for me when it comes time to host the website at my Internet Hosting Provider. The only way to avoid changing the file permissions would be to store the media in a database. This latter option is not very attractive because I plan to store a lot of videos and my Internet Hosting Provider requires me to pay much more for database space than hard drive space.

Displaying Media with the Home Controller

The HomeController is used to display existing content in the MediaFiles folder. The code for the HomeController is contained in Listing 4.

Listing 4 – HomeController.vb

Imports System.IO
 
<HandleError()> _
Public Class HomeController
    Inherits ControllerBase
 
    ''' <summary>
    ''' Displays media in media folder
    ''' </summary>
    Function Index()
        ViewData("message") = TempData("message")
 
        Dim colMedia = New List(Of String)
        Dim filePaths = Directory.GetFiles(Server.MapPath(Me.MediaFolder))
        For Each filePath As String In filePaths
            colMedia.Add(Path.GetFileName(filePath))
        Next
 
        Return View(colMedia)
    End Function
 
End Class

Notice that the HomeController, just like the MediaController, inherits from the ControllerBase class. Because the HomeController inherits from the ControllerBase class, the HomeController has access to the MediaFolder property automatically.

The Index() method retrieves the list of files contained in the App_Data folder. It passes this list of files to the Index view. The Index view is contained in Listing 5.

Listing 5 -- \Home\Index.aspx

<%@ Page Language="VB" AutoEventWireup="false" CodeBehind="Index.aspx.vb" Inherits="FamilyVideos.Index" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Family Videos Home</title>
</head>
<body>
    <div>
    <div style="background-color:#FFFFE0;padding:5px"><%=ViewData("message")%></div>
 
    <% For Each fileName In ViewData.Model%>
 
    <img src='<%= ResolveUrl(ViewData("mediaFolder")) %><%= fileName %>' width="200px"/>
    
    <% Next%>
   
    <br /><br />
    
    <%=Html.ActionLink("Add New Media", "Create", "Media")%>
    
    </div>
</body>
</html>

The Index view renders all of the images contained in the MediaFiles folder (see Figure 2). It currently does not support displaying any media type other than an image. Eventually, I also want to be able to display video and audio files (I really can’t call the application a Family Video website unless I can show videos).

Notice that the ResolveUrl() method is used when rendering each link. The ResolveUrl() method is used to resolve the ~ into the correct application path.

The Index view renders a list of <img> tags that look like this:

<img src='/MediaFiles/Forest Flowers.jpg' width="200px"/>

<img src='/MediaFiles/Garden.jpg' width="200px"/>

<img src='/MediaFiles/Humpback Whale.jpg' width="200px"/>

<img src='/MediaFiles/Oryx Antelope.jpg' width="200px"/>

Figure 2 – Index View

clip_image006

What’s Next?

In the next entry, I want to add a database to the Family Videos application so that I can include a text description with each video or photograph uploaded. I have grand plans for this application, but it is important to take baby steps.

 

Download the Code

13 Comments

Comments have been disabled for this content.