Access Multipart Form Values using MultipartMemoryStreamprovider

In my ongoing articles I have provided a complete example on how to submit Multi-part form data using AJAX. You can see the many articles starting here. This article is unique in that my requirements included the need to attach a file to an email and send that email along with personal information to a different email account. Let me explain. I have a page where a user will enter in an application and then attach their resume. I don’t need to save the resume, just attach it along with the form elements and sent to Human Resources.

Now I could upload the file, save it to a specific folder and then on the server side attach the just saved file, and then delete the saved file. That seems like a backwards way of accomplishing the desired requirement. I then came across an article located here that talks about storing form data in memory stream and sense my files are not large I decided to go in this direction.

The problem is that this code is in C and I needed it in vb.net. After spending some item I was able to convert it to vb.net. The general idea is that passing the form data through this class will take the stream information and parse it into a class that can be iterated through and captured into an object. I appreciate Kiran Challa for his (her) effort. I have also attached it as an asset to this article.

NOTE: How to use it are in the header part of the file.

Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.IO
Imports System.Threading.Tasks
Imports System.Collections.ObjectModel

'This Helper Class is for breaking down Multipart Form which contains Files and data.  This was originally converted from
'the link below.  Once you add this then you can just replace your stream provider with this one and process everything the same.
'http://stackoverflow.com/questions/17072767/web-api-how-to-access-multipart-form-values-when-using-multipartmemorystreampro
'Use the following code when you are trying to process the multipart form data.

' Other web links to support this
'http://www.strathweb.com/2012/08/a-guide-to-asynchronous-file-uploads-in-asp-net-web-api-rtm/

'
'<HttpPost> _
'<ActionName("Upload")>
'Public Function PostValue() As Task(Of HttpResponseMessage)
'    ' Check if the request contains multipart/form-data.
'    If Not Request.Content.IsMimeMultipartContent() Then
'        Throw New HttpResponseException(HttpStatusCode.UnsupportedMediaType)
'    End If

'    'Read the files into Memory Stream
'    Dim provider = New InMemoryMultipartFormDataStreamProvider()
'    Dim test As System.IO.Stream
'        Dim task1 = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(Of HttpResponseMessage) _
'                  (Function(t)
'                       Try
'                           'access form data
'                           Dim formdata As NameValueCollection = provider.FormData

'                           'access files
'                           Dim files As IList(Of HttpContent) = provider.Files

'                           'Example: reading a file's stream like below
'                           Dim file1 As HttpContent = files(0)
'                           Dim file1Stream As Stream = file1.ReadAsStreamAsync().Result

'                           For Each item In provider.Contents
'                               If Not IsNothing(item.Headers.ContentDisposition.FileName) Then
'                                   ' Sets the First Name
'                                   If Not IsNothing(provider.FormData.GetValues("txtFirstName")) Then
'                                       mFirstName = provider.FormData.GetValues("txtFirstName").FirstOrDefault()
'                                   End If
'                           Next
'                   End Function)
'    Return task1
'End Function

Public Class InMemoryMultipartFormDataStreamProvider
    Inherits MultipartStreamProvider
    Private _formData As New NameValueCollection()
    Private _fileContents As New List(Of HttpContent)()

    ' Set of indexes of which HttpContents we designate as form data
    Private _isFormData As New Collection(Of Boolean)()

    ''' <summary>
    ''' Gets a <see cref="NameValueCollection"/> of form data passed as part of the multipart form data.
    ''' </summary>
    Public ReadOnly Property FormData() As NameValueCollection
        Get
            Return _formData
        End Get
    End Property

    ''' <summary>
    ''' Gets list of <see cref="HttpContent"/>s which contain uploaded files as in-memory representation.
    ''' </summary>
    Public ReadOnly Property Files() As List(Of HttpContent)
        Get
            Return _fileContents
        End Get
    End Property

    Public Overrides Function GetStream(parent As HttpContent, headers As HttpContentHeaders) As Stream
        ' For form data, Content-Disposition header is a requirement
        Dim contentDisposition As ContentDispositionHeaderValue = headers.ContentDisposition
        If contentDisposition IsNot Nothing Then
            ' We will post process this as form data
            _isFormData.Add([String].IsNullOrEmpty(contentDisposition.FileName))

            Return New MemoryStream()
        End If

        ' If no Content-Disposition header was present.
        Throw New InvalidOperationException(String.Format("Did not find required '{0}' header field in MIME multipart body part..", "Content-Disposition"))
    End Function

    ''' <summary>
    ''' Read the non-file contents as form data.
    ''' </summary>
    ''' <returns></returns>
    Public Overrides Function ExecutePostProcessingAsync() As Task
        ' Find instances of non-file HttpContents and read them asynchronously
        ' to get the string content and then add that as form data
        For index As Integer = 0 To Contents.Count - 1
            If _isFormData(index) Then
                Dim formContent As HttpContent = Contents(index)
                ' Extract name from Content-Disposition header. We know from earlier that the header is present.
                Dim contentDisposition As ContentDispositionHeaderValue = formContent.Headers.ContentDisposition
                Dim formFieldName As String = If(UnquoteToken(contentDisposition.Name), [String].Empty)

                ' Read the contents as string data and add to form data
                Dim formFieldValue As String = formContent.ReadAsStringAsync().Result
                FormData.Add(formFieldName, formFieldValue)
            Else
                _fileContents.Add(Contents(index))
            End If
        Next
    End Function

    ''' <summary>
    ''' Remove bounding quotes on a token if present
    ''' </summary>
    ''' <param name="token">Token to unquote.</param>
    ''' <returns>Unquoted token.</returns>
    Private Shared Function UnquoteToken(token As String) As String
        If [String].IsNullOrWhiteSpace(token) Then
            Return token
        End If

        If token.StartsWith("""", StringComparison.Ordinal) AndAlso token.EndsWith("""", StringComparison.Ordinal) AndAlso token.Length > 1 Then
            Return token.Substring(1, token.Length - 2)
        End If

        Return token
    End Function
End Class

InMemoryMultipartFormDataStreamProviderDownload File

Looking for quality web hosting? Look no further than Arvixe Web Hosting!

Tags: , , , , , , , , , , , , , , | Posted under ASP .NET 4.0, Programming/Coding | RSS 2.0

Author Spotlight

David Bauernschmidt

David Bauernschmidt

I live in the historical triangle of Virginia where I am married with two daughters. I have spent over 13 years working for a Fortune 500 company in the computer area. I started in VB 6.0 and by the time I ended my employment I was supervising a development team where we built many web applications. When my first daughter was born I wanted to spend more time with her so I left and became a programmer analyst for local government as well as launch my own company. Since then I have grown James River Webs into a profitable web design and application company helping small businesses create a big presence on the internet. As an employee I have created web application used by citizens and other companies. I enjoy fly fishing, and spending time with my family. I also enjoy learning new approaches and development tools when it comes to developing applications.

Leave a Reply

Your email address will not be published. Required fields are marked *


× 8 = 40

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>