<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://interactiveasp.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Phil Gilmore : Visual Studio, .NET 3.5</title><link>http://interactiveasp.net/blogs/spgilmore/archive/tags/Visual+Studio/.NET+3.5/default.aspx</link><description>Tags: Visual Studio, .NET 3.5</description><dc:language>en</dc:language><generator>CommunityServer 2008 (Build: 30417.1769)</generator><item><title>How to support file uploads in ASP.Net MVC</title><link>http://interactiveasp.net/blogs/spgilmore/archive/2009/06/03/how-to-support-file-uploads-in-asp-net-mvc.aspx</link><pubDate>Wed, 03 Jun 2009 22:57:37 GMT</pubDate><guid isPermaLink="false">b80005ef-4071-4968-b08e-765d7d71b33e:873</guid><dc:creator>Phil Gilmore</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://interactiveasp.net/blogs/spgilmore/rsscomments.aspx?PostID=873</wfw:commentRss><comments>http://interactiveasp.net/blogs/spgilmore/archive/2009/06/03/how-to-support-file-uploads-in-asp-net-mvc.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/MVCFirefoxLogo_5F00_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; margin: 10px; border-top: 0px; border-right: 0px" border="0" alt="MVCFirefoxLogo" align="left" src="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/MVCFirefoxLogo_5F00_thumb.png" width="100" height="75"&gt;&lt;/a&gt; 06/03/2009, Phil Gilmore&lt;/p&gt; &lt;p&gt;ASP.NET MVC can support file uploads.&amp;nbsp; You need two components to support file uploads.&amp;nbsp; &lt;/p&gt; &lt;ul&gt; &lt;li&gt;A form in your markup (view) which contains an &lt;em&gt;&amp;lt;input type="file"...&amp;gt;&lt;/em&gt; tag and which has the proper &lt;em&gt;enctype&lt;/em&gt; attribute.&lt;/li&gt; &lt;li&gt;A controller action which will receive the upload information and perform a task with it.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Your form can be as simple as this:&lt;/p&gt;&lt;pre class="code"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;form &lt;/span&gt;&lt;span style="color: red"&gt;action&lt;/span&gt;&lt;span style="color: blue"&gt;="/MyController/SendFile" &lt;/span&gt;&lt;span style="color: red"&gt;enctype&lt;/span&gt;&lt;span style="color: blue"&gt;="multipart/form-data" &lt;/span&gt;&lt;span style="color: red"&gt;method&lt;/span&gt;&lt;span style="color: blue"&gt;="post"&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;input &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;="file" &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;="SourceFile" &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;="SourceFile" /&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;br &lt;/span&gt;&lt;span style="color: blue"&gt;/&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;input &lt;/span&gt;&lt;span style="color: red"&gt;type&lt;/span&gt;&lt;span style="color: blue"&gt;="submit" &lt;/span&gt;&lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;="Send" &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;="btnUpload" &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;="Submit1" /&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;form&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Notice the &lt;em&gt;enctype&lt;/em&gt; attribute on the &lt;em&gt;&amp;lt;form...&amp;gt;&lt;/em&gt; tag.&amp;nbsp; This is required to support file uploads.&amp;nbsp; Notice too that the action points to our controller action which knows how to work with the uploaded file.&amp;nbsp; Lastly, you'll see the &lt;em&gt;&amp;lt;input type="file...&amp;gt;&lt;/em&gt; tag inside the form.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Here is a screen shot of the form, rendered in Firefox 3.0.&lt;/p&gt;
&lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" border="0" alt="UploadForm" src="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/UploadForm_5F00_1.png" width="236" height="111"&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The form as shown above contains only Html and is fairly universal regardless of the web framework you are using.&amp;nbsp; This means it should be familiar to you.&amp;nbsp; You have probably seen the enctype attribute on a form with its accompanying. The id attribute of the &lt;em&gt;&amp;lt;input type="file"... &amp;gt;&lt;/em&gt; tag will be mapped by the MVC framework to a property of your model or to a parameter in the action method (in this case the &lt;em&gt;SendFile&lt;/em&gt; action).&amp;nbsp; Here is an example of an action which takes the file as a parameter.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ContentResult &lt;/span&gt;SendFile(&lt;span style="color: #2b91af"&gt;HttpPostedFileBase &lt;/span&gt;SourceFile)
{

}
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;This action gets an HttpPostedFileBase object containing properties for the original local filename and the content of the file itself.&amp;nbsp; Notice that the MVC framework only maps this parameter to the file data if the parameter name (&lt;em&gt;SourceFile&lt;/em&gt;) matches the id and name parameters from the &lt;em&gt;&amp;lt;input type="file"...&amp;gt;&lt;/em&gt; tag in the form.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;If you have a strange circumstance which prohibits you from organizing your form and action in this way and MVC cannot map the file data to an HttpPostedFileBase parameter, you can retrieve it manually from the Request object.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ContentResult &lt;/span&gt;SendFile()
{
    &lt;span style="color: #2b91af"&gt;HttpPostedFileBase &lt;/span&gt;SourceFile = Request.Files[0];
    &lt;span style="color: green"&gt;//...
&lt;/span&gt;}&lt;/pre&gt;&lt;pre class="code"&gt;
&lt;/pre&gt;&lt;/blockquote&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;Here is an evaluation of the HttpPostedFileBase object as provided to the SendFile action method.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/UploadFilesQuickwatch.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" border="0" alt="UploadFilesQuickwatch" src="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/UploadFilesQuickwatch_5F00_thumb.png" width="591" height="293"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Once you have an HttpPostedFileBase object, you can work with the file data.&amp;nbsp; Here are the members of the HttpPostedFileBase class.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;protected &lt;/span&gt;HttpPostedFileBase();
&lt;span style="color: blue"&gt;public virtual int &lt;/span&gt;ContentLength { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
&lt;span style="color: blue"&gt;public virtual string &lt;/span&gt;ContentType { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
&lt;span style="color: blue"&gt;public virtual string &lt;/span&gt;FileName { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
&lt;span style="color: blue"&gt;public virtual &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Stream &lt;/span&gt;InputStream { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
&lt;span style="color: blue"&gt;public virtual void &lt;/span&gt;SaveAs(&lt;span style="color: blue"&gt;string &lt;/span&gt;filename);&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;This is pretty simple stuff.&amp;nbsp; You can save the file, read the file or get the file's name and mime type (&lt;em&gt;ContentType&lt;/em&gt;).&amp;nbsp; ContentLength is generally not necessary since the InputStream already contains the data of the correct size.&lt;/p&gt;
&lt;p&gt;Here is a working action that displays the content of any file uploaded to it.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ContentResult &lt;/span&gt;SendFile()
{
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(Request.Files.Count == 0)
        &lt;span style="color: blue"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ContentResult&lt;/span&gt;() { ContentType = &lt;span style="color: #a31515"&gt;"text/plain"&lt;/span&gt;, Content = &lt;span style="color: #a31515"&gt;"File upload failed." &lt;/span&gt;};
    &lt;span style="color: blue"&gt;else
    &lt;/span&gt;{
        &lt;span style="color: #2b91af"&gt;HttpPostedFileBase &lt;/span&gt;SourceFile = Request.Files[0];
        &lt;span style="color: #2b91af"&gt;ContentResult &lt;/span&gt;result = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ContentResult&lt;/span&gt;();
        result.ContentType = &lt;span style="color: #a31515"&gt;"text/plain"&lt;/span&gt;;

        &lt;span style="color: #2b91af"&gt;StreamReader &lt;/span&gt;reader = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;StreamReader&lt;/span&gt;(SourceFile.InputStream);
        &lt;span style="color: blue"&gt;string &lt;/span&gt;content = reader.ReadToEnd();
        result.Content = content;

        &lt;span style="color: blue"&gt;return &lt;/span&gt;result;
    }
}
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;This method doesn't use the MVC-mapped HttpPostedFileBase parameter.&amp;nbsp; This is not as elegant, but doesn't require a matching name or id on the file upload element in the form markup.&amp;nbsp; This may be useful in some cases.&lt;/p&gt;
&lt;p&gt;Lastly, entering that &amp;lt;input type="file"...&amp;gt; markup into the form can be error-prone.&amp;nbsp; While the element is not large or hard to read, it must be exact and is inconsistent with styles supporting strongly-typed views mapped to an MVC model.&amp;nbsp; Therefore it may be prudent to extend the HtmlHelper class to make this easier, cleaner and more consistent.&amp;nbsp; I have written an extension method to do this.&amp;nbsp; It has 2 overloads. &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static string &lt;/span&gt;Upload(&lt;span style="color: blue"&gt;this &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlHelper &lt;/span&gt;helper, &lt;span style="color: blue"&gt;string &lt;/span&gt;name)
{
    &lt;span style="color: blue"&gt;string &lt;/span&gt;result = &lt;span style="color: blue"&gt;string&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;"&amp;lt;input type=\"file\" id=\"{0}\" name=\"{0}\" /&amp;gt;"&lt;/span&gt;, name);
    &lt;span style="color: blue"&gt;return &lt;/span&gt;result;
}

&lt;span style="color: blue"&gt;public static string &lt;/span&gt;Upload(&lt;span style="color: blue"&gt;this &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HtmlHelper &lt;/span&gt;helper, &lt;span style="color: blue"&gt;string &lt;/span&gt;name, &lt;span style="color: blue"&gt;object &lt;/span&gt;htmlAttributes)
{
    &lt;span style="color: blue"&gt;string &lt;/span&gt;attributes;
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(htmlAttributes &lt;span style="color: blue"&gt;is &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;KeyValuePair&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt;&amp;gt;)
        attributes = (htmlAttributes &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;KeyValuePair&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt;&amp;gt;).ToAttributeString();
    &lt;span style="color: blue"&gt;else
        &lt;/span&gt;attributes = (&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RouteValueDictionary&lt;/span&gt;(htmlAttributes)).ToAttributeString();

    &lt;span style="color: blue"&gt;string &lt;/span&gt;result = &lt;span style="color: blue"&gt;string&lt;/span&gt;.Format(&lt;span style="color: #a31515"&gt;"&amp;lt;input type=\"file\" name=\"{0}\" {1} /&amp;gt;"&lt;/span&gt;, name, attributes);
    &lt;span style="color: blue"&gt;return &lt;/span&gt;result;
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Using this extension, my markup can be changed to this:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;font size="2"&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;lt;% &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;using&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; (Html.BeginForm(&lt;/font&gt;&lt;font color="#a31515" size="2"&gt;&lt;font color="#a31515" size="2"&gt;"SendFile"&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;&lt;font color="#a31515" size="2"&gt;"MyController"&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#2b91af" size="2"&gt;&lt;font color="#2b91af" size="2"&gt;FormMethod&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;.Post, &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;new&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; { id = &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;&lt;font color="#a31515" size="2"&gt;"sendFileForm"&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;, enctype = &lt;/font&gt;&lt;font color="#a31515" size="2"&gt;&lt;font color="#a31515" size="2"&gt;"multipart/form-data"&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; }))&lt;/p&gt;
&lt;p&gt;{ %&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;%&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;=&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; Html.Upload(&lt;/font&gt;&lt;font color="#a31515" size="2"&gt;&lt;font color="#a31515" size="2"&gt;"SourceFile"&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;, &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;new&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; { style=&lt;/font&gt;&lt;font color="#a31515" size="2"&gt;&lt;font color="#a31515" size="2"&gt;"width: 300px;"&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; })%&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2"&gt;&lt;font color="#a31515" size="2"&gt;br&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;/&amp;gt;&lt;/p&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;
&lt;p&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/font&gt;&lt;/font&gt;&lt;font color="#a31515" size="2"&gt;&lt;font color="#a31515" size="2"&gt;input&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#ff0000" size="2"&gt;&lt;font color="#ff0000" size="2"&gt;type&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;="submit"&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#ff0000" size="2"&gt;&lt;font color="#ff0000" size="2"&gt;value&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;="Send"&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#ff0000" size="2"&gt;&lt;font color="#ff0000" size="2"&gt;name&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;="btnUpload"&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#ff0000" size="2"&gt;&lt;font color="#ff0000" size="2"&gt;id&lt;/font&gt;&lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;="Submit1"&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt; &lt;/font&gt;&lt;font color="#0000ff" size="2"&gt;&lt;font color="#0000ff" size="2"&gt;/&amp;gt;&lt;/p&gt;&lt;/font&gt;&lt;/font&gt;&lt;font size="2"&gt;
&lt;p&gt;&amp;lt;% } %&amp;gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Personally, I don't think this is as pretty as straight HTML, but it's easier to write consistently, and if you're using MVC, your whole page probably looks like this already anyway.&amp;nbsp; It's your choice.&amp;nbsp; Either way you build the markup, the controller action is unaffected.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;None of this is very complicated but I recently had to run through it and construct a proof-of-concept for some coworkers and figured I'd publish it for the masses.&amp;nbsp; I hope it was helpful.&lt;/p&gt;&lt;/font&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://interactiveasp.net/aggbug.aspx?PostID=873" width="1" height="1"&gt;</description><category domain="http://interactiveasp.net/blogs/spgilmore/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://interactiveasp.net/blogs/spgilmore/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://interactiveasp.net/blogs/spgilmore/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://interactiveasp.net/blogs/spgilmore/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category></item><item><title>Building data sequences in C#</title><link>http://interactiveasp.net/blogs/spgilmore/archive/2009/05/19/building-data-sequences-in-c.aspx</link><pubDate>Tue, 19 May 2009 20:03:00 GMT</pubDate><guid isPermaLink="false">b80005ef-4071-4968-b08e-765d7d71b33e:768</guid><dc:creator>Phil Gilmore</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://interactiveasp.net/blogs/spgilmore/rsscomments.aspx?PostID=768</wfw:commentRss><comments>http://interactiveasp.net/blogs/spgilmore/archive/2009/05/19/building-data-sequences-in-c.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/SequenceLogo.png"&gt;&lt;img style="border-right-width: 0px; margin: 10px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" alt="SequenceLogo" src="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/SequenceLogo_5F00_thumb.png" align="left" border="0" width="258" height="112" /&gt;&lt;/a&gt; 05/19/2009, Phil Gilmore&lt;/p&gt;
&lt;p&gt;Beyond the overlap they share with enumerable collections, sequences are mostly unsupported in C#.&amp;nbsp; A notable exception are some of the static methods of the Enumerable class.&amp;nbsp; Check them out.&amp;nbsp; This support is all I need for most sequence work I do.&amp;nbsp; But the support therein is insufficient for anything complex.&amp;nbsp; To augment this support, I have written some extension methods to various CLR classes to add pseudo-support for sequences and sets.&amp;nbsp; One that seems to be especially useful is a sequence generator method.&amp;nbsp; It immediately became useful in many instances, so I thought I'd share it.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;What can I do with a sequence generator?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Generate a time-of-day list to allow users to select a time from a drop-down list, perhaps in 15-minute intervals.  &lt;/li&gt;
&lt;li&gt;Generate a list of months to allow users to select a month from a drop-down list.  &lt;/li&gt;
&lt;li&gt;Generate a list of years to allow a user to select their birth year from a drop-down list.  &lt;/li&gt;
&lt;li&gt;Generate a list of any type of sequential data for user selection.  &lt;/li&gt;
&lt;li&gt;Build an "upline" of parent-child relationships in table of hierarchical data traversed through a self-join.  &lt;/li&gt;
&lt;li&gt;Any operation that would normally be constructed using a For loop or While loop to populate a list or collection.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Why not collections and loops?&lt;/h2&gt;
&lt;p&gt;Looking at this list, you might be pondering the usefulness of this since many of these things can be achieved using a collections built in a for-loop or through various Linq maneuvers.&amp;nbsp; This is true.&amp;nbsp; Consider the example above in building an upline from a hierarchical table.&amp;nbsp; But the value of sequence generation is easier to see when considering that sequence data can be built by analyzing the last item in the sequence.&amp;nbsp; For example, you could use a For loop to iterate through your file system and build a List of mp3 filenames in your music collection.&amp;nbsp; This is more the function of a collection than a sequence.&amp;nbsp; This data already exists as separate elements that are found and stored in a collection.&amp;nbsp; If one mp3 file is deleted, the next does not change.&amp;nbsp; In a sequence where elements are related by generation, the removal or change of an element may affect the generation of the rest of the sequence.&amp;nbsp; For example, consider a sequence of incremental integers starting with 1000 and incrementing by 1 with a sequence size of 5.&amp;nbsp; The elements of this sequence would be 1000, 1001, 1002, 1003 1004.&amp;nbsp; If the first element were to change to 1002, the sequence would continue its pattern and become 1002, 1003, 1004, 1005, 1006.&amp;nbsp; The generation of elements in a sequence also does not necessarily require existing data to be collected.&amp;nbsp; Whereas a collection of mp3 filenames requires a filesystem that can be queried to retrieve these filenames, a sequence of incremental integer is generated from only a single seed element (1000 in my first example).&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Building a sequence generator:&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;T&amp;gt; CreateSequence&amp;lt;T&amp;gt;(&lt;br /&gt;    &lt;span style="color: blue"&gt;this &lt;/span&gt;T startElement, &lt;span style="color: #2b91af"&gt;Func&lt;/span&gt;&amp;lt;T, T&amp;gt; getNextElement, &lt;span style="color: #2b91af"&gt;Predicate&lt;/span&gt;&amp;lt;T&amp;gt; isLastElement)&lt;br /&gt;{&lt;br /&gt;    T currentElement = startElement;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;while &lt;/span&gt;(!isLastElement(currentElement))&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;yield return &lt;/span&gt;currentElement;&lt;br /&gt;        currentElement = getNextElement(currentElement);&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: blue"&gt;yield return &lt;/span&gt;currentElement;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The first parameter (startElement) is the object on which the method is called.&amp;nbsp; This is probably a primitive object, but can be anything.&amp;nbsp; There are no constraints on the T type parameter so reference and value types are both game.&amp;nbsp; Even literals work.&amp;nbsp; You can call this method on the literal number 1.&amp;nbsp; Of course, this is part of the syntax of C# extension methods.&amp;nbsp; When consuming this method, you do not pass the first parameter.&amp;nbsp; But it's important to understand that this is the first element in the sequence (the seed).&amp;nbsp; &lt;/p&gt;
&lt;p&gt;The getNextElement parameter (the first that you provide) is a function.&amp;nbsp; This function can be a delegate to a method, an anonymous method, or a lambda expression.&amp;nbsp; In my examples, I use a lambda expression.&amp;nbsp; The function is given the current element and is expected to return the next element in the sequence.&amp;nbsp; For simple sequences, it will probably just add or subtract some number to the current element to produce the next one.&lt;/p&gt;
&lt;p&gt;The isLastElement parameter is another function.&amp;nbsp; As each element is added to the sequence, this function is executed to determine if the end of the sequence has been reached.&amp;nbsp; If the function returns false, then the sequence continues and getNextElement will be called again to get yet another element.&amp;nbsp; If it instead returns true, the current element will be the last element added to the sequence and the CreateSequence method will return thereafter.&lt;/p&gt;
&lt;p&gt;Beware of infinite loops when using this.&amp;nbsp; If the IsLastElement function never returns true, you will encounter an infinite loop.&amp;nbsp; For this reason, it may be a good habit to use &amp;gt;= and &amp;lt;= operators instead of == operators, for example.&amp;nbsp; Even though your sequence may be simple as in our examples, better safe than sorry.&amp;nbsp; For more complicated sequences, be even more careful.&lt;/p&gt;
&lt;p&gt;The method can be refined if desired.&amp;nbsp; It may be desirable to change the isLastElement predicate from an UNTIL condition to a WHILE condition (and hence renaming it to isValidElement instead), for example.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Using the sequence generator:&lt;/h2&gt;
&lt;p&gt;Most of these examples can be done using the static methods of the Enumerable class with a little more simplicity.&amp;nbsp; But I'll still keep the examples simple.&amp;nbsp; You can build up to the hard stuff yourself.&amp;nbsp; Here is a simple example using the sequence generator method in an ASP.NET MVC web form where a TIME must be selected.&amp;nbsp; First, the code to generate the view data:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Create a sequence of times, 15 minutes apart.&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime &lt;/span&gt;referenceDate = &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;.Now.Date;&lt;br /&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;&amp;gt; availableTimes = referenceDate.CreateSequence&lt;br /&gt;(&lt;br /&gt;    x =&amp;gt; x.AddMinutes(15), &lt;br /&gt;    x =&amp;gt; x.CompareTo(referenceDate.AddDays(1).AddMinutes(-15)) &amp;gt;= 0&lt;br /&gt;).ToList();&lt;br /&gt;&lt;br /&gt;&lt;span style="color: green"&gt;// Convert times to a list of bindable objects for a dropdown list in the MVC view.&lt;br /&gt;&lt;/span&gt;ViewData[&lt;span style="color: #a31515"&gt;"DueTimesAvailable"&lt;/span&gt;] = availableTimes.Select(&lt;br /&gt;    x =&amp;gt; &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SelectListItem&lt;/span&gt;()&lt;br /&gt;    {&lt;br /&gt;        Text = x.ToString(&lt;span style="color: #a31515"&gt;"hh:mm tt"&lt;/span&gt;),&lt;br /&gt;        Value = x.ToString(&lt;span style="color: #a31515"&gt;"hh:mm tt"&lt;/span&gt;),&lt;br /&gt;        Selected = x.Equals(referenceDate)&lt;br /&gt;    }).ToList();&lt;br /&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The first block of code creates a list of datetimes starting at midnight on the current date, every 15 minutes until 11:45pm on the same day.&amp;nbsp; The second block converts these DateTimes to a List&amp;lt;SelectListItem&amp;gt; using Linq.&amp;nbsp; Here's a simple example, creating a list of month names.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; months = 1.CreateSequence(m =&amp;gt; m + 1, m =&amp;gt; m &amp;gt;= 12)&lt;br /&gt;    .Select(i =&amp;gt; System.Threading.&lt;span style="color: #2b91af"&gt;Thread&lt;br /&gt;        &lt;/span&gt;.CurrentThread.CurrentCulture&lt;br /&gt;        .DateTimeFormat.GetMonthName(i)&lt;br /&gt;    ).ToList();&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2&gt;Screen shots:&lt;/h2&gt;
&lt;p&gt;In the example above, we get month names in a sequence ("January", "Februrary", "March"...).&amp;nbsp; Below are some of these examples in action in an ASP.NET MVC page.&amp;nbsp; Notice that Months and Times are in ascending order and Years are in descending order.&amp;nbsp; They were not sorted in this way.&amp;nbsp; They were generated in those orders by either incrementing or decrementing the sequence seed.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/SequenceTime_5F00_2.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" alt="SequenceTime" src="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/SequenceTime_5F00_thumb.png" border="0" width="165" height="305" /&gt;&lt;/a&gt; &lt;a href="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/SequenceMonth.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" alt="SequenceMonth" src="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/SequenceMonth_5F00_thumb.png" border="0" width="166" height="196" /&gt;&lt;/a&gt; &lt;a href="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/SequenceYear.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" alt="SequenceYear" src="http://interactiveasp.net/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/spgilmore/SequenceYear_5F00_thumb.png" border="0" width="149" height="115" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;So where does this leave sets?&amp;nbsp; &lt;/h2&gt;
&lt;p&gt;Additional extension methods and classes can be used to treat these sequences and native Enums as sets.&amp;nbsp; Watch for more details in another blog post.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://interactiveasp.net/aggbug.aspx?PostID=768" width="1" height="1"&gt;</description><category domain="http://interactiveasp.net/blogs/spgilmore/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://interactiveasp.net/blogs/spgilmore/archive/tags/.NET+3.5/default.aspx">.NET 3.5</category><category domain="http://interactiveasp.net/blogs/spgilmore/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://interactiveasp.net/blogs/spgilmore/archive/tags/Linq/default.aspx">Linq</category></item></channel></rss>