<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;A0EERX04fSp7ImA9WhRVGUo.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537</id><updated>2012-01-19T07:26:44.335-06:00</updated><category term="nerd geek" /><category term="linq linqtosql audit" /><category term="jQuery mvc session logout" /><category term="linq" /><category term="jQuery Cycle slideshow mvc asp.net" /><category term="expression" /><category term="LINQ LINQtoSQL DataContext .NET mocking" /><category term="Attribute" /><category term="ASP.NET MVC" /><title>Farm Fresh Code</title><subtitle type="html">Greetings from the Heartland.  Quality code, delivered fresh to you.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://farm-fresh-code.blogspot.com/" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/FarmFreshCode" /><feedburner:info uri="farmfreshcode" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CUMFSHY6fSp7ImA9WhRRF0g.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-4812497777781209579</id><published>2011-12-01T09:24:00.001-06:00</published><updated>2011-12-01T09:30:19.815-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-01T09:30:19.815-06:00</app:edited><title>RequireHttpsAttribute breaks my app in Cassini</title><content type="html">I was reading blog entry yesterday by Troy Hunt on &lt;a href="http://www.troyhunt.com/2011/11/owasp-top-10-for-net-developers-part-9.html" target="_blank"&gt;Transport Layer protection&lt;/a&gt;. Beyond being a good reminder of some basic security practices, it reminded me of a little trick I use to get a site to require secure HTTP for production and staging installs, but still be able to debug it locally using Cassini (which doesn’t support HTTPS).&amp;nbsp; An alternative way to run your app locally would be to use &lt;a href="http://learn.iis.net/page.aspx/868/iis-express-overview/" target="_blank"&gt;IIS Express&lt;/a&gt; with an actual certificate, self-signed or otherwise, but this way is relatively simple and has the added advantage that you know that the attribute is applied globally. &lt;br /&gt;
I take advantage of GlobalFilters introduced in MVC 3.&amp;nbsp; The default template for your &lt;em&gt;Global.asax.cs&lt;/em&gt; file has a method called &lt;em&gt;RegisterGlobalFilters&lt;/em&gt;.&amp;nbsp; I’ve cloned this method as:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RegisterProductionOnlyFilters( GlobalFilterCollection filters )
{
    filters.Add( &lt;span class="kwrd"&gt;new&lt;/span&gt; RequireHttpsAttribute() );
}&lt;/pre&gt;&lt;br /&gt;
This method is then called in &lt;em&gt;Application_Start()&lt;/em&gt; as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;var requestIsLocal = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
&lt;span class="kwrd"&gt;try&lt;/span&gt;
{
    requestIsLocal = &lt;span class="kwrd"&gt;this&lt;/span&gt;.Context.Request.IsLocal;
}
&lt;span class="rem"&gt;// if the request isn't available, we catch the exception and know we're on prod/staging&lt;/span&gt;
&lt;span class="kwrd"&gt;catch&lt;/span&gt; (NullReferenceException) { }
 
&lt;span class="kwrd"&gt;if&lt;/span&gt; (!requestIsLocal)
{
    RegisterProductionOnlyFilters( GlobalFilters.Filters );
}&lt;/pre&gt;&lt;br /&gt;
Now the &lt;em&gt;RequireHttpsAttribute&lt;/em&gt; is applied as a global filter, but only when not running on localhost. To complete security, we use &lt;em&gt;Web.config&lt;/em&gt; transformations to add &lt;strong&gt;requireSSL=”true”&lt;/strong&gt; to our auth and session cookies (all cookies created server-side, that is).&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&amp;lt;system.web&amp;gt;
    &amp;lt;authentication mode=&lt;span class="str"&gt;"Forms"&lt;/span&gt;&amp;gt;
        &amp;lt;forms requireSSL=&lt;span class="str"&gt;"true"&lt;/span&gt; xdt:Transform=&lt;span class="str"&gt;"SetAttributes(requireSSL)"&lt;/span&gt; /&amp;gt;
    &amp;lt;/authentication&amp;gt;
    &amp;lt;httpCookies requireSSL=&lt;span class="str"&gt;"true"&lt;/span&gt; xdt:Transform=&lt;span class="str"&gt;"InsertAfter(/configuration/system.web/authentication)"&lt;/span&gt; /&amp;gt;
&amp;lt;/system.web&amp;gt;
&lt;/pre&gt;&lt;br /&gt;
Voila, our actions and cookies are now protected, but only when running in our production and staging environments.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-4812497777781209579?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/W4cwi-s5KrbrQqg6VMofQfMVzI0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/W4cwi-s5KrbrQqg6VMofQfMVzI0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/W4cwi-s5KrbrQqg6VMofQfMVzI0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/W4cwi-s5KrbrQqg6VMofQfMVzI0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/sWyVST4LKRc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/4812497777781209579/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2011/12/requirehttpsattribute-breaks-my-app-in.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/4812497777781209579?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/4812497777781209579?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/sWyVST4LKRc/requirehttpsattribute-breaks-my-app-in.html" title="RequireHttpsAttribute breaks my app in Cassini" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2011/12/requirehttpsattribute-breaks-my-app-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08BQncyfip7ImA9WhRTGUg.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-7760259355830302137</id><published>2011-10-24T19:33:00.000-05:00</published><updated>2011-11-10T15:17:33.996-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-10T15:17:33.996-06:00</app:edited><title>Storing documents in a database using EntityFramework Code First</title><content type="html">Our team has been developing a workflow application that allows our Board of Regents to submit requests for information to one or more Regents institutions and allow those institutions to respond back in return. &amp;nbsp;There are a number of other requirements, but one I'd like to focus on is the need to allow the Board to upload a document that one or more institutions must download, fill in, then upload as their response. We expose the data in the application via an API that each institution can use with their own workflow applications to process requests for information internally. &amp;nbsp;We've also developed a companion application that our institution will use internally and make available to the other institutions as desired. The applications serve a limited number of users and has relatively light data requirements so we chose a database-centric approach for simplicity.&lt;br /&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
We're using EntityFramework Code First (actually, database first, code first, but that's a different post). We've been through a couple of iterations on the approach and I thought I'd share our lessons learned.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;span style="font-size: large;"&gt;First Approach&lt;/span&gt;&lt;/strong&gt; &lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
Our first approach was to use a single table per type holding both metadata and content for each type of attachment. &amp;nbsp;In our case we have three different types of documents, referred to internally as attachments, since that is how they are delivered via our web site: request attachments, response attachments, and a final response or "letter" attachment. &amp;nbsp;Using a single-table-per-type approach allows us to easily model the relationships between the main entity (Request/Response) and their related attachments (RequestAttachment and RequestLetter, and&amp;nbsp;ResponseAttachment, respectively). &amp;nbsp;Even though the table schemas are identical, we segregate them into separate tables in order to keep the relationships and the models simple.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
This approach is pretty clean. &amp;nbsp;On the model side we can refactor the code into a shared base class that all of the attachment entity models can derive from. &amp;nbsp;This fits in well with our standard model as well, in which we use an artificial primary key (identity) ID column and a Version (timestamp) column for concurrency control. &amp;nbsp;To be honest, we didn't really give this a lot of thought because it seemed a relatively straightforward mapping.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
In developing the first, Regents, application our model seemed to work very well. &amp;nbsp;There were hints, however, that our choice might not be optimal. &amp;nbsp;First, we only need the attachment metadata to render links to the attachments in our views. &amp;nbsp;However, because of the model we're forced to either have two models per table, one for metadata-only and the other for the entire model, or we must load all of the data for each request.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
Second, our "list" screens don't even reference the attachments, but our API needs to have a mechanism to "list" all requests to support synchronization between the main and client apps. &amp;nbsp; Again, we have a choice: our repository can be more complex, supporting different queries for different types of lists or we can use the same queries, but in some cases load extraneous data. &amp;nbsp;We chose to use a simpler repository and eager load attachments along with requests for information. &amp;nbsp;During development of the initial application, this seemed like a reasonable choice because the attachments tend to be small and the number of requests per "list" screen is small. &amp;nbsp;Better to do one request and get more information than needed than fire off many requests for a small amount of data was our thought.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;span style="font-size: large;"&gt;Cracks Appear&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
At the point where we started on the synchronization support in our API, it became apparent that this approach was not going to work. &amp;nbsp;To reduce the chance of inconsistent data between client and master applications, we minimize the amount of data stored in the client application, pulling the details from the master application as necessary. &amp;nbsp;To ensure consistency, client applications, at least ours, will periodically synchronize the &lt;i&gt;glue&lt;/i&gt;&amp;nbsp;that connects entities in the client with their corresponding entities in the master application.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
Unfortunately our approach to attachments meant that whenever this synchronization occurred, all of the attachments for all requests we being eagerly loaded. &amp;nbsp;The obvious fix for this was to back off to lazy loading, but this is less optimal for the master application, forcing it to make more requests whenever a "list" view is generated. &amp;nbsp;What we'd really like is to eager load the attachment metadata, but lazy load the attachment content since it is only needed at the point where an actual download of a particular attachment occurs.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;span style="font-size: large;"&gt;Current Solution&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
The approach that we settled on (for now) is to use one table per type and one shared table for all content.&amp;nbsp; The first table includes the attachment metadata, including a foreign keys to the content and the related request or response&amp;nbsp;(it acts as a join table with additional metadata).&amp;nbsp; The shared table contains only the value of the content.&amp;nbsp; The attachment metadata (join table) is eagerly loaded for most queries, but the attachment content is not.&amp;nbsp; The attachment content is only loaded when handling a download request for an attachment.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;span style="font-size: large;"&gt;Some Notes&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
There are a couple of things that you should be aware of before adopting this approach.&amp;nbsp; First, if your data is larger than ours it might be better to use either a hybrid DB/file system approach or investigate using FileStream data in MSSQL.&amp;nbsp; You can find a nice introductory article by Jacob Sebastian&amp;nbsp;at &lt;a href="http://www.simple-talk.com/sql/learn-sql-server/an-introduction-to-sql-server-filestream/" target="_blank"&gt;SimpleTalk&lt;/a&gt;&amp;nbsp;and Paul S. Randal has a nice&amp;nbsp;&lt;a href="http://msdn.microsoft.com/library/cc949109" target="_blank"&gt;white paper on MSDN&lt;/a&gt;&amp;nbsp;on using FileStream data.&amp;nbsp; Our solution fits into the sweet spot for table-based attachment storage.&amp;nbsp; Yours might not and the extra complexity of a hybrid or FileStream solution might be worth the effort. Second, all of this discussion is predicated on an ASP.NET MVC architecture and particularly one supporting an API used to synchronize with external applications.&amp;nbsp; I think the approach we are using is better than our original even for a single application, but we didn't really discover the original's drawbacks until we implemented the API.&lt;br /&gt;
&lt;br /&gt;
Please let me know if you have any suggestions for how we could improve on this or if you've found it helpful.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-7760259355830302137?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/uYSJEAfLTD-PL_kt2NpCTfZcS1U/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uYSJEAfLTD-PL_kt2NpCTfZcS1U/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/uYSJEAfLTD-PL_kt2NpCTfZcS1U/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uYSJEAfLTD-PL_kt2NpCTfZcS1U/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/5CwUsakRU0w" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/7760259355830302137/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2011/10/storing-documents-in-database-using.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/7760259355830302137?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/7760259355830302137?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/5CwUsakRU0w/storing-documents-in-database-using.html" title="Storing documents in a database using EntityFramework Code First" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2011/10/storing-documents-in-database-using.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UMSHs_eyp7ImA9WhZWE00.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-4366763661412652201</id><published>2011-05-13T11:43:00.002-05:00</published><updated>2011-05-13T11:48:09.543-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-13T11:48:09.543-05:00</app:edited><title>Sharing Razor Functions Across Views</title><content type="html">Scott Guthrie wrote recently about &lt;a href="http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx" target="_blank"&gt;using the @helper syntax&lt;/a&gt; within Razor, part of which was how to share these helpers across views.&amp;nbsp; I had a couple of functions defined in my Razor views that were repeated in various views and wondered if I could get this to work as well.&amp;nbsp; Turns out that it’s dead simple to do.&lt;br /&gt;
First, add an App_Code folder to your project (ok I know this seems like a throw-back, don’t blame me).&amp;nbsp; Next create a partial view named &lt;em&gt;Razor.cshtml&lt;/em&gt; (or something else) in the App_Code folder.&amp;nbsp; Put your function into this folder as a static method.&lt;br /&gt;
&lt;pre class="csharpcode"&gt;@&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Mvc;

@functions
{
      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt;  MvcHtmlString Checked&amp;lt;T&amp;gt;( IEnumerable&amp;lt;T&amp;gt; collection, T item)
      {
          &lt;span class="kwrd"&gt;if&lt;/span&gt; (collection != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; collection.Contains( item ))
          {
              &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MvcHtmlString( &lt;span class="str"&gt;"checked=\"checked\""&lt;/span&gt; );
          }
          &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MvcHtmlString( &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty );
      }  
}&lt;/pre&gt;
Compile your solution, then open the view where you want to use the function. Add the code, using the name of the view as the class for the method&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="editor-label"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    @Html.LabelFor( model =&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; model.RoleID )
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="editor-field"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    @foreach (var role in Model.AvailableRoles)
    {
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="role-selections"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;label&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
                 &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;input&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="checkbox"&lt;/span&gt;
                             &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="RoleID"&lt;/span&gt;
                             &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="@role.ID"&lt;/span&gt;
                             @Razor.Checked(Model.RoleID,role.ID) &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
                 @role.Name.MakeTitle()
            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;label&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; 
    }
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    @Html.ValidationMessageFor( model =&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; model.RoleID )
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
It's important to make sure you open the view after the solution has been compiled or the new class might not be visible.  Note, in the process of developing this particular example I realized that this code could easily be made into an HtmlHelper and I've since refactored to that, but it's still a good technique for making common Razor functions available across views.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-4366763661412652201?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/9Lk1jq8R44YN5dNYySsGDNCcWHY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9Lk1jq8R44YN5dNYySsGDNCcWHY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/9Lk1jq8R44YN5dNYySsGDNCcWHY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9Lk1jq8R44YN5dNYySsGDNCcWHY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/xyCrQHGaT4c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/4366763661412652201/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2011/05/sharing-razor-functions-across-views.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/4366763661412652201?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/4366763661412652201?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/xyCrQHGaT4c/sharing-razor-functions-across-views.html" title="Sharing Razor Functions Across Views" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2011/05/sharing-razor-functions-across-views.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkUARH8zfip7ImA9WhZQGEk.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-4844426654324803968</id><published>2011-04-26T13:57:00.000-05:00</published><updated>2011-04-26T13:57:25.186-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-26T13:57:25.186-05:00</app:edited><title>Default authorization filter provider</title><content type="html">Phil Haack recently posted about &lt;a href="http://haacked.com/archive/2011/04/25/conditional-filters.aspx"&gt;Conditional Filters in ASP.NET MVC3&lt;/a&gt;.&amp;nbsp; It turned out to be a very timely post because I happen to have a need that nearly matches the example in his introduction.&amp;nbsp; Nearly every action, except Login, in my current application requires that the user be authenticated.&amp;nbsp; Some actions require further authorization processing, but just about everything requires that you be logged in.&lt;br /&gt;
&lt;br /&gt;
In the past I would have built a base controller, applied the default Authorize attribute to the controller, then derived everything but my AccountController (where login lives) from the base controller.&amp;nbsp; This seemed like the safest way to ensure that all my actions are protected, but anytime I have a controller that has mixed public/private actions, I’m limited.&amp;nbsp; I can’t use the base controller or I have to introduce two base controllers – one with the common code and another that derives from it, but enforces authorization.&amp;nbsp; In addition, in each of these controllers with mixed actions I have to remember to protect access rather than permit access in exceptional cases.&amp;nbsp; Clearly the latter would be more secure since, as I age, I get more forgetful.&lt;br /&gt;
&lt;br /&gt;
Now, using a custom FilterProvider, I can get the behavior that I prefer: a default AuthorizeAttribute [filter] applied to each action UNLESS the controller or action has some other, specific AuthorizationAttribute-based “restriction” applied.&amp;nbsp; I say “restriction” because it could be that I make the action public rather than further restrict access.&amp;nbsp; It only takes three simple steps:&lt;br /&gt;
&lt;br /&gt;
First, create a DefaultAuthorizationFilterProvider.&amp;nbsp; Using Phil’s example as a template I created the following class.&amp;nbsp; Note that it implements IFilterProvider.&amp;nbsp; In GetFilters, it inspects both the controller (from the ControllerContext) and the action (from the ActionDescriptor) to see if either have an attribute that derives from AuthorizeAttribute.&amp;nbsp; If so, it simply returns an empty set of filters.&amp;nbsp; If not, it adds a default AuthorizeAttribute to the set of filters with global scope.&amp;nbsp; This will ensure that an something that derives from AuthorizeAttribute is supplied as a filter to every action.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DefaultAuthorizationFilterProvider : IFilterProvider
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerable&amp;lt;Filter&amp;gt; GetFilters( ControllerContext controllerContext, ActionDescriptor actionDescriptor )
    {
        var filters = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;Filter&amp;gt;();
        var controllerType = controllerContext.Controller.GetType();
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!controllerType.GetCustomAttributes( &lt;span class="kwrd"&gt;typeof&lt;/span&gt;( AuthorizeAttribute ), &lt;span class="kwrd"&gt;true&lt;/span&gt; ).Any()
            &amp;amp;&amp;amp; !actionDescriptor.GetCustomAttributes( &lt;span class="kwrd"&gt;typeof&lt;/span&gt;( AuthorizeAttribute ), &lt;span class="kwrd"&gt;true&lt;/span&gt; ).Any())
        {
            filters.Add( &lt;span class="kwrd"&gt;new&lt;/span&gt; Filter( &lt;span class="kwrd"&gt;new&lt;/span&gt; AuthorizeAttribute(), FilterScope.Global, &lt;span class="kwrd"&gt;null&lt;/span&gt; ) );
        }
        &lt;span class="kwrd"&gt;return&lt;/span&gt; filters;
    }
}&lt;/pre&gt;
&lt;br /&gt;
Next, just as in Phil’s post, add this FilterProvider to the collection of filter providers in the Application_Start method of Global.asax.cs.&amp;nbsp; Ours is a bit simpler because, frankly, the use case is simpler.&amp;nbsp; We don’t have complex conditions to map, just check if there is a attribute or not, we can live with the default constructor and haven’t got any set up to do.&lt;br /&gt;
&lt;pre class="csharpcode"&gt;FilterProviders.Providers.Add( &lt;span class="kwrd"&gt;new&lt;/span&gt; DefaultAuthorizationFilterProvider() );&lt;/pre&gt;
&lt;br /&gt;
Finally, we want to be able to easily permit public access.&amp;nbsp; To do that, I created a PublicAttribute class that derives from AuthorizeAttribute and overrides AuthorizeCore to simply return &lt;strong&gt;true&lt;/strong&gt; for every authorization request.&amp;nbsp; Yes, you can still set it up with Roles and Users, but they will be ignored.&amp;nbsp; I can live with that.&lt;br /&gt;
&lt;pre class="csharpcode"&gt;[AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = &lt;span class="kwrd"&gt;false&lt;/span&gt;, Inherited = &lt;span class="kwrd"&gt;true&lt;/span&gt; )]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; PublicAttribute : AuthorizeAttribute
{
    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; AuthorizeCore( System.Web.HttpContextBase httpContext )
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
    }
}&lt;/pre&gt;
&lt;br /&gt;
Now, to allow public access to an action we need to apply the PublicAttribute to the method (or controller). Note that in the following only the Login methods (GET and POST) are public.&amp;nbsp; You still need to be logged in to Logout (maybe we could make this public? meh) or to change your password.&amp;nbsp; And, look, we get to inherit from our BaseController, taking advantage of any common code or dependencies that we may have! &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AccountController : BaseController
{
    [HttpGet]
    [Public]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult Login()
    {
        ...
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Public]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult Login( LoginModel model, &lt;span class="kwrd"&gt;string&lt;/span&gt; returnUrl )
    {
       ...
    }

    [HttpGet]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult Logout()
    {
        ...
    }

    [HttpGet]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult ChangePassword()
    {
        ...
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult ChangePassword( ChangePasswordModel model )
    {
        ...
    }
}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-4844426654324803968?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/oJJumtqt8ZAt4Wf1HK3Q9ElHdng/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oJJumtqt8ZAt4Wf1HK3Q9ElHdng/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/oJJumtqt8ZAt4Wf1HK3Q9ElHdng/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oJJumtqt8ZAt4Wf1HK3Q9ElHdng/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/UnjnRsg8b-E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/4844426654324803968/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2011/04/default-authorization-filter-provider.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/4844426654324803968?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/4844426654324803968?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/UnjnRsg8b-E/default-authorization-filter-provider.html" title="Default authorization filter provider" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2011/04/default-authorization-filter-provider.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYMR38zeSp7ImA9WhZTF08.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-3465870818470401901</id><published>2011-03-21T12:06:00.000-05:00</published><updated>2011-03-21T12:06:26.181-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-21T12:06:26.181-05:00</app:edited><title>Testing for Exceptions and Expectations</title><content type="html">One of the things that I frequently have need to do is make sure that my methods throw proper exceptions when exceptional conditions occur.&amp;nbsp; .NET unit testing frameworks support typically support this using attributes.&amp;nbsp; For example:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;[Test]
[ExpectedException(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ArgumentNullException))]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ShouldThrowAnArgumentNullExceptionWhenANullParameterIsSupplied()
{
    var foo = &lt;span class="kwrd"&gt;new&lt;/span&gt; Foo();
    
    foo.Bar( &lt;span class="kwrd"&gt;null&lt;/span&gt; );
}&lt;/pre&gt;
&lt;br /&gt;
This works wonders for simple cases, but what about those cases where I want to make sure that some expectations are met.&amp;nbsp; Because the verification code comes after the invocation of the method under test, it won’t get run when an exception is thrown.&amp;nbsp; One way around this is to set up your mock objects and verify your expectations in your test initialize/cleanup methods.&amp;nbsp; This works because the cleanup code is run even for tests that throw exceptions.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; Bar MockBar { get; set; }

[TestInitialize]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; MyTestInitialize()
{
    &lt;span class="kwrd"&gt;this&lt;/span&gt;.MockBar = MockRepository.GenerateMock&amp;lt;Bar&amp;gt;();
}

[TestCleanup]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt;  MyTestCleanup()
{
    &lt;span class="kwrd"&gt;this&lt;/span&gt;.MockBar.VerifyAllExpectations();
}

&lt;pre class="csharpcode"&gt;[Test]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ShouldThrowAnArgumentNullExceptionWhenANullParameterIsSupplied()
{
    &lt;span class="rem"&gt;// Baz should never be called when Bar is passed a null parameter&lt;/span&gt;
    this.MockBar.Expect( b =&amp;gt; b.Baz() ).Repeat.Never();

    var foo = &lt;span class="kwrd"&gt;new&lt;/span&gt; Foo();

    foo.Bar( &lt;span class="kwrd"&gt;null&lt;/span&gt; );  
}&lt;/pre&gt;
&lt;/pre&gt;
This works well when your tests share similar dependencies.&amp;nbsp; You could even extend this so that each test sets up its own or uses shared private methods to set up groups of expectations and the verification step checks to make sure that a mock object exists before it verifies it’s expectations.&amp;nbsp; This is a valid way solve the problem, but one I’ve found that can get excessively complicated and comes with code smells (you end up with a fair amount of conditional logic in the cleanup code).&lt;br /&gt;
&lt;br /&gt;
An alternative to this is to not use the &lt;strong&gt;ExpectedException&lt;/strong&gt; attribute, but to build the logic of catching and validating the exception into your test.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;[Test]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ShouldThrowAnArgumentNullExceptionWhenANullParameterIsSupplied()
{
    var mockBar = MockRepository.GenerateMock&amp;lt;Bar&amp;gt;();

    &lt;span class="rem"&gt;// Baz should never be called when Bar is passed a null parameter&lt;/span&gt;
    mockBar.Expect( b =&amp;gt; b.Baz() ).Repeat.Never();

    var foo = &lt;span class="kwrd"&gt;new&lt;/span&gt; Foo();

    &lt;span class="kwrd"&gt;try&lt;/span&gt;
    {
        foo.Bar( &lt;span class="kwrd"&gt;null&lt;/span&gt; );
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; AssertFailedException(); &lt;span class="rem"&gt;// test fails due to no exception thrown&lt;/span&gt;
    }
    &lt;span class="kwrd"&gt;catch&lt;/span&gt; (ArgumentNullException) &lt;span class="rem"&gt;// only catch the one exception we expect&lt;/span&gt;
    {
    }

    mockBar.VerifyAllExpectations();   
}&lt;/pre&gt;
&lt;br /&gt;
This is, in a word, ugly. It has the advantage of flexibility and keeping the expectation code specific and local to the current test. You could also, if you wanted, refactor to share expectation set up/verification between tests. There's still a code smell here: you're repeating a pattern whenever you want this type of test, but I think it's more in keeping with the single responsibility principle since you're cleanup code really is only concerned with clean up that necessarily affects all tests and isn't being abused to (selectively) run verification on each test's mocks. If only we could make it a little less ugly by encapsulating the pattern. Voila! A couple of helper classes to the rescue! &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AssertionFailedException : Exception
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; AssertionFailedException() : &lt;span class="kwrd"&gt;base&lt;/span&gt;() { }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; AssertionFailedException( &lt;span class="kwrd"&gt;string&lt;/span&gt; message )
        : &lt;span class="kwrd"&gt;base&lt;/span&gt;( message ) { }
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AssertException
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; IsThrown&amp;lt;T&amp;gt;( Action action ) &lt;span class="kwrd"&gt;where&lt;/span&gt; T : Exception
    {
        &lt;span class="kwrd"&gt;try&lt;/span&gt;
        {
            action();
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; AssertionFailedException( &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format( &lt;span class="str"&gt;"An expected exception of type {0} was not thrown"&lt;/span&gt;, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(T).Name ) );
        }
        &lt;span class="kwrd"&gt;catch&lt;/span&gt; (T)
        {
        }
    }
}&lt;/pre&gt;
&lt;br /&gt;
Now we have a much cleaner way to assert that an exception has been thrown without polluting our clean up methods. In cases where it isn't appropriate, because our tests don’t share a lot of dependencies, to use the test initialization/cleanup methods to create and enforce our expecations, this mechanism works very well. As usual, you are still able to refactor your setup/verification for dependent objects as needed for tests that use the same code. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;[Test]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ShouldThrowAnArgumentNullExceptionWhenANullParameterIsSupplied()
{
    var mockBar = MockRepository.GenerateMock&amp;lt;Bar&amp;gt;();

    &lt;span class="rem"&gt;// Baz should never be called when Bar is passed a null parameter&lt;/span&gt;
    mockBar.Expect( b =&amp;gt; b.Baz() ).Repeat.Never();

    var foo = &lt;span class="kwrd"&gt;new&lt;/span&gt; Foo();

    AssertException.IsThrown&amp;lt;ArgumentNullException&amp;gt;( () =&amp;gt; foo.Bar( &lt;span class="kwrd"&gt;null&lt;/span&gt; ) );

    mockBar.VerifyAllExpectations();   
}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-3465870818470401901?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/SSV_vt-rwW8CIK3LIdh-YC70ggs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SSV_vt-rwW8CIK3LIdh-YC70ggs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/SSV_vt-rwW8CIK3LIdh-YC70ggs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/SSV_vt-rwW8CIK3LIdh-YC70ggs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/ryQAtvsifwY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/3465870818470401901/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2011/03/testing-for-exceptions-and-expectations.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/3465870818470401901?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/3465870818470401901?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/ryQAtvsifwY/testing-for-exceptions-and-expectations.html" title="Testing for Exceptions and Expectations" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2011/03/testing-for-exceptions-and-expectations.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEENQHg9cSp7ImA9WhdXF0Q.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-7948983310424535115</id><published>2011-03-15T11:07:00.004-05:00</published><updated>2011-08-31T08:18:11.669-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-31T08:18:11.669-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET MVC" /><category scheme="http://www.blogger.com/atom/ns#" term="Attribute" /><title>Revisiting custom authorization in ASP.NET MVC</title><content type="html">Several months ago I &lt;a href="http://farm-fresh-code.blogspot.com/2009/11/customizing-authorization-in-aspnet-mvc.html"&gt;blogged about custom attributes&lt;/a&gt; based on the AuthorizeAttribute class in ASP.NET MVC. One of the bits that I got wrong or, at least, not as right as I would like, is caching. I didn’t extend the caching to allow it to take into account the new tests for authorization that I’d developed. The end result of this was that if you derived your permission to access the method based on the new test, you always got served a fresh page. It was never delivered from the cache.&lt;br /&gt;
&lt;br /&gt;
In my application, this didn’t cause too much of a performance it. In fact, most of the actions protected in such a way are explicitly not cached anyway so the drawback rarely (if ever, I haven’t checked all the methods) came into play. I got asked about it recently on a StackOverflow answer so I thought I’d take a stab at improving the cache handling to account for the new tests.&lt;br /&gt;
&lt;br /&gt;
There are a couple of things you need to be aware of. First, the code in OnCacheAuthorization must be thread-safe. Instances of the attribute are reused for multiple requests. In particular, this means that you cannot store information from the request in the attribute and expect it to remain inviolate during the life of the attribute. Another request may come along later and overwrite your stored request data and cause your code to return incorrect results. Since we’re talking about authorization this is a serious problem since it could lead to users getting access to information they should not be able to see.&lt;br /&gt;
&lt;br /&gt;
Second, you need to be careful not to reuse the request data associated with the request that creates the cached entry. While there is a mechanism that allows you to pass data to the CacheValidationHandler method I created in the first post, you need to be careful to only pass data that actually applies to all requests, since you wouldn’t want to depend on the data being the same in the request that is served up from the cache. It may be an entirely different user making that request.&lt;br /&gt;
&lt;br /&gt;
Our attribute still derives from AuthorizeAttribute, with the same modifications due to the fact that it is specific to a particular request and so doesn’t make sense to apply it at the class level or have multiples.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt; AttributeUsage( AttributeTargets.Method, Inherited = &lt;span class="kwrd"&gt;true&lt;/span&gt;, AllowMultiple = &lt;span class="kwrd"&gt;false&lt;/span&gt; )]
 &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RoleOrOwnerAuthorizationAttribute : AuthorizationAttribute
 {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; IDataContextFactory ContextFactory { get; set; }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; routeParameter = &lt;span class="str"&gt;"id"&lt;/span&gt;;
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// The name of the routing parameter to use to identify the owner of the data (user id) in question.  Default is "id".&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; RouteParameter
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.routeParameter; }
            set { &lt;span class="kwrd"&gt;this&lt;/span&gt;.routeParameter = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        ...
}&lt;/pre&gt;
The constructors, including reliance on my data context factory and its constructor injection, remain the same as well as the methods that I’ve refactored from the original AuthorizeAttribute. Notice, though, that I've made them virtual now in case we want to derive from this attribute.&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; IDataContextFactory ContextFactory { get; set; }

&lt;span class="kwrd"&gt;public&lt;/span&gt; RoleOrOwnerAuthorizationAttribute()
    : &lt;span class="kwrd"&gt;this&lt;/span&gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt; )
{
}

&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CacheValidateHandler( HttpContext context, &lt;span class="kwrd"&gt;object&lt;/span&gt; data, &lt;span class="kwrd"&gt;ref&lt;/span&gt; HttpValidationStatus validationStatus )
{
    validationStatus = OnCacheAuthorization( &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpContextWrapper( context ) );
}

 &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetCachePolicy( AuthorizationContext filterContext )
{
    &lt;span class="rem"&gt;// ** IMPORTANT **&lt;/span&gt;
    &lt;span class="rem"&gt;// Since we're performing authorization at the action level, the authorization code runs&lt;/span&gt;
    &lt;span class="rem"&gt;// after the output caching module. In the worst case this could allow an authorized user&lt;/span&gt;
    &lt;span class="rem"&gt;// to cause the page to be cached, then an unauthorized user would later be served the&lt;/span&gt;
    &lt;span class="rem"&gt;// cached page. We work around this by telling proxies not to cache the sensitive page,&lt;/span&gt;
    &lt;span class="rem"&gt;// then we hook our custom authorization code into the caching mechanism so that we have&lt;/span&gt;
     &lt;span class="rem"&gt;// the final say on whether a page should be served from the cache.&lt;/span&gt;
    HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
    cachePolicy.SetProxyMaxAge( &lt;span class="kwrd"&gt;new&lt;/span&gt; TimeSpan( 0 ) );
    cachePolicy.AddValidationCallback( CacheValidateHandler, &lt;span class="kwrd"&gt;null&lt;/span&gt; &lt;span class="rem"&gt;/* data */&lt;/span&gt;);
}&lt;/pre&gt;
Now I introduce a new, inner class CurrentRequest to help in abstracting the different between the authorization request that creates the cached copy and subsequent cache requests that need to be served from the cache, or not. It stores the OwnerID of the item being requested and the current Username of the user making the request. Our IsOwner method will be refactored to use this class instead of the AuthorizationContext for this data. Note that it has three constructors; the default constructor will be used for unit testing since I won’t always want to mock up either an AuthorizationContext or an HttpContextBase object in my tests.&amp;nbsp; The other constructors are used for requests made from OnAuthorization and OnCacheAuthorization, respectively.&amp;nbsp; Note the real difference is what context we have available to the code. In the first case we can use RouteValues to extract the OwnerID, in the second, we use the Request parameters directly.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CurrentRequest
{

    &lt;span class="kwrd"&gt;public&lt;/span&gt; CurrentRequest()
    {
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.OwnerID = -1;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; CurrentRequest( AuthorizationContext filterContext, &lt;span class="kwrd"&gt;string&lt;/span&gt; routeParameter )
        : &lt;span class="kwrd"&gt;this&lt;/span&gt;()
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext.RouteData.Values.ContainsKey( routeParameter ))
        {
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.OwnerID = Convert.ToInt32( filterContext.RouteData.Values[routeParameter] );
        }

        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Username = filterContext.HttpContext.User.Identity.Name;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; CurrentRequest( HttpContextBase httpContext, &lt;span class="kwrd"&gt;string&lt;/span&gt; routeParameter )
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty( routeParameter ))
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (httpContext.Request.Params[routeParameter] != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                &lt;span class="kwrd"&gt;this&lt;/span&gt;.OwnerID = GetOwnerID( httpContext.Request.Params[routeParameter] );
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.Equals( &lt;span class="str"&gt;"id"&lt;/span&gt;, routeParameter, StringComparison.OrdinalIgnoreCase ))
            {
                &lt;span class="rem"&gt;// id may be last element in path if not included as a parameter&lt;/span&gt;
                &lt;span class="kwrd"&gt;this&lt;/span&gt;.OwnerID = GetOwnerID( httpContext.Request.Path.Split( &lt;span class="str"&gt;'/'&lt;/span&gt; ).Last() );
            }
        }

        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Username = httpContext.User.Identity.Name;
    }

    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetOwnerID( &lt;span class="kwrd"&gt;string&lt;/span&gt; id )
    {
        &lt;span class="kwrd"&gt;int&lt;/span&gt; ownerID;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;int&lt;/span&gt;.TryParse( id, &lt;span class="kwrd"&gt;out&lt;/span&gt; ownerID ))
        {
            ownerID = -1;
        }
        &lt;span class="kwrd"&gt;return&lt;/span&gt; ownerID;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; OwnerID { get; set; }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Username { get; set; }
}&lt;/pre&gt;
&lt;br /&gt;
&lt;em&gt;NOTE: An earlier version of this post did not handle getting the route parameter from the HttpContext properly, if the route parameter was the "id" property.&amp;nbsp; This version relies on the default route set up to place&amp;nbsp;the id parameter at the end of the path but, with that caveat, now handles an "id" parameter properly.&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
The OnAuthorization method changes slightly to use this new class. Instead of simply passing the AuthorizationContext, we pass a CurrentRequest object constructed from it using the RouteParameter on the attribute.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnAuthorization( AuthorizationContext filterContext )
{
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;"filterContext"&lt;/span&gt; );
    }

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (AuthorizeCore( filterContext.HttpContext ))
    {
        SetCachePolicy( filterContext );
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (!filterContext.HttpContext.User.Identity.IsAuthenticated)
    {
        &lt;span class="rem"&gt;// auth failed, redirect to login page&lt;/span&gt;
        filterContext.Result = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpUnauthorizedResult();
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext.HttpContext.User.IsInRole( &lt;span class="str"&gt;"SuperUser"&lt;/span&gt; ) || IsOwner( &lt;span class="kwrd"&gt;new&lt;/span&gt; CurrentRequest( filterContext, &lt;span class="kwrd"&gt;this&lt;/span&gt;.RouteParameter ) ))
    {
        SetCachePolicy( filterContext );
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt;
    {
        ViewDataDictionary viewData = &lt;span class="kwrd"&gt;new&lt;/span&gt; ViewDataDictionary();
        viewData.Add( &lt;span class="str"&gt;"Message"&lt;/span&gt;, &lt;span class="str"&gt;"You do not have sufficient privileges for this operation."&lt;/span&gt; );
        filterContext.Result = &lt;span class="kwrd"&gt;new&lt;/span&gt; ViewResult { MasterName = &lt;span class="kwrd"&gt;this&lt;/span&gt;.MasterName, ViewName = &lt;span class="kwrd"&gt;this&lt;/span&gt;.ViewName, ViewData = viewData };
    }
}&lt;/pre&gt;
This allows us to simplify IsOwner significantly as the CurrentRequest class now takes care of unpacking the data from the request. Note how we are able to use the ContextFactory (it’s thread-safe) to create a new data context within the method, ensuring that we don’t conflict with other threads that may be using the attribute. The data context itself needn’t be thread-safe since we create a new one each time and it’s local to the method.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsOwner( CurrentRequest requestData )
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt; (var dc = &lt;span class="kwrd"&gt;this&lt;/span&gt;.ContextFactory.GetDataContextWrapper())
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; dc.Table&amp;lt;User&amp;gt;().Where( p =&amp;gt; p.UserName == requestData.Username &amp;amp;&amp;amp; p.UserID == requestData.OwnerID ).Any();
    }
}&lt;/pre&gt;
&lt;br /&gt;
Lastly, we need to hook our IsOwner check into the authorization system.&amp;nbsp; We do this by overriding OnCacheAuthorization and doing our check when the base class method would normally invalidate the request because the user is not in the correct role. When they are allowed by the role, we needn’t perform our check.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; HttpValidationStatus OnCacheAuthorization( HttpContextBase httpContext )
{
    var status = &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnCacheAuthorization( httpContext );
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (status == HttpValidationStatus.IgnoreThisRequest &amp;amp;&amp;amp; IsOwner( &lt;span class="kwrd"&gt;new&lt;/span&gt; CurrentRequest( httpContext, &lt;span class="kwrd"&gt;this&lt;/span&gt;.RouteParameter ) ))
    {
        status = HttpValidationStatus.Valid;
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; status;
}&lt;/pre&gt;&lt;br /&gt;
Note here that we use the constructor on CurrentRequest that takes an HttpContextBase (wrapper around HttpContext) instead because that's all we have available to use when being evaluated by the caching system. Because we've abstracted IsOwner to use this object, it doesn't need to know how we got the values that it will be checking.&lt;br /&gt;
&lt;br /&gt;
Now the owners of the data will have the same cache-based performance as the administrative users who access the data via their roles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-7948983310424535115?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/fuctH6LFiy7YGS1mpzT7Ea8ASas/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fuctH6LFiy7YGS1mpzT7Ea8ASas/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/fuctH6LFiy7YGS1mpzT7Ea8ASas/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fuctH6LFiy7YGS1mpzT7Ea8ASas/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/a4RrSKYP3jQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/7948983310424535115/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2011/03/revisiting-custom-authorization-in.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/7948983310424535115?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/7948983310424535115?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/a4RrSKYP3jQ/revisiting-custom-authorization-in.html" title="Revisiting custom authorization in ASP.NET MVC" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>5</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2011/03/revisiting-custom-authorization-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04BR307fyp7ImA9WxFaEEg.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-1238970094573699119</id><published>2010-07-13T15:11:00.001-05:00</published><updated>2010-07-13T15:12:36.307-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-13T15:12:36.307-05:00</app:edited><title>Tweeting taxis</title><content type="html">I was talking with some folks from Canada at an event I recently attended during the Desire2Learn Fusion 2010 conference in Chicago.  One of the things they pointed out was that, in Chicago, you hear constant taxi horns.  Now, sitting in my hotel room, I can't seem to block them out. &lt;br /&gt;&lt;br/&gt;

I think taxi cab drivers have developed a code with which they communicate via their horns.  It has nothing to do with the warning "beep" that you and I use, or even the "angry beeeeppp" that you occasionally hear (and fear).  No, I think they've taken "tweet"ing literally and let each other know what they think of their passengers, their current destination, what they're doing after work...all manner of things through the subtle shifts in tone and length of the beep.  How else do you explain that I hear constant taxi horns outside my hotel room, but have not yet heard or seen a single crash to go along with any of them.  Moreover, you hear them even when there are only two w-i-d-e-l-y separated taxis on the same street.&lt;br /&gt;&lt;br /&gt;

I suppose it could be extremely defensive and safe driving habits, but when was the last time you thought to apply that description to a taxi driver?  I think it's safer to assume that it's not as primitive a signaling system as you and I are used to.  There's much more than simple emotional content blasting across the streets of Chicago;  who needs 140 characters to get your message across when you have a few seconds of car horn.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-1238970094573699119?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/GqZnIqKwMOGsWfpbO7ovI44h3Es/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GqZnIqKwMOGsWfpbO7ovI44h3Es/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/GqZnIqKwMOGsWfpbO7ovI44h3Es/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/GqZnIqKwMOGsWfpbO7ovI44h3Es/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/mDhFkOu6PD8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/1238970094573699119/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2010/07/tweeting-taxis.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/1238970094573699119?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/1238970094573699119?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/mDhFkOu6PD8/tweeting-taxis.html" title="Tweeting taxis" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2010/07/tweeting-taxis.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4HSHk9fSp7ImA9WxBVGUg.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-1385027976185786492</id><published>2010-02-23T14:59:00.002-06:00</published><updated>2010-02-23T15:02:19.765-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-23T15:02:19.765-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="expression" /><category scheme="http://www.blogger.com/atom/ns#" term="linq" /><title>Expressions, functions, and case sensitivity</title><content type="html">&lt;p&gt;I've been developing a LINQ library with some useful classes and extensions to support, primarily, testability with my &lt;a href="http://farm-fresh-code.blogspot.com/2009/04/adventures-in-mocking-and-faking-linq.html"&gt;LINQ-based data layers.&lt;/a&gt; To this end, I have an &lt;strong&gt;IDataContextWrapper &lt;/strong&gt;interface and a &lt;strong&gt;DataContextWrapper&amp;lt;T&amp;gt;&lt;/strong&gt; generic implementation (where &lt;strong&gt;T&lt;/strong&gt; derives from &lt;strong&gt;DataContext&lt;/strong&gt;). I notice in my use of this code I was making calls looking like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;var user = &lt;span class="kwrd"&gt;this&lt;/span&gt;.ContextWrapper&lt;br /&gt;               .Table&amp;lt;User&amp;gt;()&lt;br /&gt;               .SingleOrDefault( u =&amp;gt; u.Username == username );&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Here, Table&amp;lt;T&amp;gt;() is the method on the wrapper that returns the strongly typed Table corresponding to the type T from the wrapped DataContext.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I thought to myself, this would be a lot shorter if I simply added a method to my wrapper class to get the single (or first) matching element from the table. So I proceeded, in my naive way, to add such a method.&lt;br /&gt;&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; T SingleOrDefault&amp;lt;T&amp;gt;( Func&amp;lt;T,&lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt; selector )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.db.GetTable&amp;lt;T&amp;gt;().SingleOrDefault( selector );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Then simplify my code from above, slightly, to:&lt;br /&gt;&lt;/p&gt;&lt;pre class="csharpcode"&gt;var user = &lt;span class="kwrd"&gt;this&lt;/span&gt;.ContextWrapper&lt;br /&gt;               .SingleOrDefault&amp;lt;User&amp;gt;( u =&amp;gt; u.Username == username );&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;I did the same for &lt;strong&gt;Single()&lt;/strong&gt;, &lt;strong&gt;FirstOrDefault()&lt;/strong&gt;, and &lt;strong&gt;First()&lt;/strong&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;After awhile I started getting reports of spurious errors in some code that is dependent on this library. Perhaps, you can see the subtle error lurking in the above. Here'a hint: the failures that were being reported all had to do with usernames that had uppercase characters in the database, but were typed in as lowercase in the login box.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;It turns out that the extension method &lt;strong&gt;SingleOrDefault()&lt;/strong&gt; that takes a &lt;strong&gt;Func&amp;lt;T,bool&amp;gt;&lt;/strong&gt; performs the function, not by translation to SQL (duh), but by loading up the table and applying the function to each result in turn to filter the matches. What I really needed to use was the signature that takes an &lt;strong&gt;Expression&amp;lt;Func&amp;lt;T,bool&amp;gt;&amp;gt;&lt;/strong&gt;. This allows the expression to be translated to SQL and performs the query in the same a case insensitive way as the original query.&lt;/p&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; T SingleOrDefault&amp;lt;T&amp;gt;( Expression&amp;lt;Func&amp;lt;T,&lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; selector )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.db.GetTable&amp;lt;T&amp;gt;().SingleOrDefault( selector );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The most interesting bit is that I didn't need to change my calling code at all, as the lambda expression maps equally well onto the &lt;strong&gt;Func&amp;lt;T,bool&amp;gt;&lt;/strong&gt; or the &lt;strong&gt;Expression&amp;lt;Func&amp;lt;T,bool&amp;gt;&amp;gt;&lt;/strong&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Just another subtle thing to remember when using or extending the LINQ classes.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-1385027976185786492?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/tGRXNNSWuAhzy5opKByeIAD8jjc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tGRXNNSWuAhzy5opKByeIAD8jjc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/tGRXNNSWuAhzy5opKByeIAD8jjc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/tGRXNNSWuAhzy5opKByeIAD8jjc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/VkY_qJLyQz0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/1385027976185786492/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2010/02/expressions-functions-and-case.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/1385027976185786492?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/1385027976185786492?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/VkY_qJLyQz0/expressions-functions-and-case.html" title="Expressions, functions, and case sensitivity" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2010/02/expressions-functions-and-case.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYCRno7fip7ImA9WxFTFEo.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-353949362677909024</id><published>2010-01-27T09:03:00.003-06:00</published><updated>2010-04-05T08:29:27.406-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-05T08:29:27.406-05:00</app:edited><title>ASP.NET MVC links for jQuery tabs</title><content type="html">&lt;p&gt;&lt;/p&gt;  &lt;p&gt;To work fully, including the loading indicator when using AJAX tab loading, jQuery expects your tab set up to be something like:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&amp;lt;div id=&lt;span class="str"&gt;&amp;quot;tabs&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;ul&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;a href=&lt;span class="str"&gt;&amp;quot;/controller/action1&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;span&amp;gt;Tab 1&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;a href=&lt;span class="str"&gt;&amp;quot;/controller/action2&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;span&amp;gt;Tab 2&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;a href=&lt;span class="str"&gt;&amp;quot;/controller/action3&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;span&amp;gt;Tab 3&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;    &amp;lt;/ul&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;br /&gt;Note that the standard HtmlHelper extension for a link has trouble producing the correct anchor tag. If you specify HTML in the link text, it will be encoded on output. This is decidedly not what you want.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;After several project where I used jQuery to wrap the anchor text in a span on page load, I decided that it would be just as easy (perhaps easier) to simply add a new extension named &lt;strong&gt;TabLink&lt;/strong&gt; to my existing collection of extensions and simply generate the anchors with the embedded span for tab links.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; TabLink( &lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlHelper helper, &lt;span class="kwrd"&gt;string&lt;/span&gt; text, &lt;span class="kwrd"&gt;string&lt;/span&gt; action )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; TabLink( helper, text, action, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt; );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; TabLink( &lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlHelper helper, &lt;span class="kwrd"&gt;string&lt;/span&gt; text, &lt;span class="kwrd"&gt;string&lt;/span&gt; action, &lt;span class="kwrd"&gt;string&lt;/span&gt; controller )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; TabLink( helper, text, action, controller, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt; );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; TabLink( &lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlHelper helper, &lt;span class="kwrd"&gt;string&lt;/span&gt; text, &lt;span class="kwrd"&gt;string&lt;/span&gt; action, &lt;span class="kwrd"&gt;string&lt;/span&gt; controller, &lt;span class="kwrd"&gt;object&lt;/span&gt; htmlAttributes )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; TabLink( helper, text, action, controller, &lt;span class="kwrd"&gt;null&lt;/span&gt;, htmlAttributes );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; TabLink( &lt;span class="kwrd"&gt;this&lt;/span&gt; HtmlHelper helper, &lt;span class="kwrd"&gt;string&lt;/span&gt; text, &lt;span class="kwrd"&gt;string&lt;/span&gt; action, &lt;span class="kwrd"&gt;string&lt;/span&gt; controller, &lt;span class="kwrd"&gt;object&lt;/span&gt; routeValues, &lt;span class="kwrd"&gt;object&lt;/span&gt; htmlAttributes )&lt;br /&gt;{&lt;br /&gt;    var urlHelper = &lt;span class="kwrd"&gt;new&lt;/span&gt; UrlHelper( helper.ViewContext.RequestContext );&lt;br /&gt;&lt;br /&gt;    var anchorBuilder = &lt;span class="kwrd"&gt;new&lt;/span&gt; TagBuilder( &lt;span class="str"&gt;&amp;quot;a&amp;quot;&lt;/span&gt; );&lt;br /&gt;    anchorBuilder.Attributes.Add( &lt;span class="str"&gt;&amp;quot;href&amp;quot;&lt;/span&gt;, urlHelper.Action( action, controller, routeValues ) );&lt;br /&gt;    anchorBuilder.MergeAttributes( &lt;span class="kwrd"&gt;new&lt;/span&gt; ParameterDictionary( htmlAttributes ), &lt;span class="kwrd"&gt;true&lt;/span&gt; );&lt;br /&gt;&lt;br /&gt;    var spanBuilder = &lt;span class="kwrd"&gt;new&lt;/span&gt; TagBuilder( &lt;span class="str"&gt;&amp;quot;span&amp;quot;&lt;/span&gt; );&lt;br /&gt;    spanBuilder.SetInnerText( text );&lt;br /&gt;&lt;br /&gt;    anchorBuilder.InnerHtml = spanBuilder.ToString( TagRenderMode.Normal );&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; anchorBuilder.ToString( TagRenderMode.Normal );&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Used as:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&amp;lt;div id=&lt;span class="str"&gt;&amp;quot;tabs&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;ul&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;%= Html.TabLink( &lt;span class="str"&gt;&amp;quot;action1&amp;quot;&lt;/span&gt; ) %&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;%= Html.TabLink( &lt;span class="str"&gt;&amp;quot;action2&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;controller&amp;quot;&lt;/span&gt; ) %&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;%= Html.TabLink( &lt;span class="str"&gt;&amp;quot;action3&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;controller&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; { id = &lt;span class="str"&gt;&amp;quot;tab3&amp;quot;&lt;/span&gt; } %&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;        &amp;lt;li&amp;gt;&amp;lt;%= Html.TabLink( &lt;span class="str"&gt;&amp;quot;action4&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;controller&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; { page = 1 }, &lt;span class="kwrd"&gt;new&lt;/span&gt; { id = &lt;span class="str"&gt;&amp;quot;tab4&amp;quot;&lt;/span&gt; } %&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;    &amp;lt;/ul&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&amp;gt;&lt;br /&gt;    $(&lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;         $(&lt;span class="str"&gt;'#tabs'&lt;/span&gt;).tabs();&lt;br /&gt;    });&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-353949362677909024?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/aWCWUEj2qQv4_awMscW0muzbK60/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/aWCWUEj2qQv4_awMscW0muzbK60/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/aWCWUEj2qQv4_awMscW0muzbK60/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/aWCWUEj2qQv4_awMscW0muzbK60/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/AM_5uEzubGk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/353949362677909024/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2010/01/aspnet-mvc-links-for-jquery-tabs.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/353949362677909024?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/353949362677909024?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/AM_5uEzubGk/aspnet-mvc-links-for-jquery-tabs.html" title="ASP.NET MVC links for jQuery tabs" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2010/01/aspnet-mvc-links-for-jquery-tabs.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8ESXg4fCp7ImA9WhdXF0Q.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-439017501568784265</id><published>2009-11-02T12:59:00.008-06:00</published><updated>2011-08-31T08:20:08.634-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-31T08:20:08.634-05:00</app:edited><title>Customizing authorization in ASP.NET MVC</title><content type="html">I've seen, and answered, a few questions on &lt;a href="http://stackoverflow.com/"&gt;StackOverflow&lt;/a&gt; about specific authorization scenarios that fall outside the bounds of what the standard &lt;b&gt;AuthorizeAttribute&lt;/b&gt; can handle. I've run into a couple of different situations where I've needed to do this with my own apps as well. One specific case is where you have a relationship between the entity being referred to by the controller action and the user. In this case, the user is the &lt;i&gt;owner&lt;/i&gt; of the data and should have rights regardless of their role relationship with the data. To allow access under these circumstances, I extended the AuthorizeAttribute, creating a RoleOrOwnerAuthorizationAttribute class that takes this ownership relation into account. I use this attribute to control access to the user's own data (stored in my user table).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Pre-requisites&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;In order for this attribute to work it needs a few things. First, it needs to know what parameter in the route data corresponds with the id found in the table we are looking at. Second, it needs a way to access your database to find if there is a row that matches both the username of the current user and the id specified in the request. For the former, I use a property on the class that defaults to the string "id". For the latter, I use a ContextFactory which is constructor-injected, but defaults to a factory for the app's data context.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;How it works&lt;/h3&gt;&lt;br /&gt;&lt;h4&gt;Derive from AuthorizeAttribute&lt;/h4&gt;The class derives from AuthorizeAttribute. I do apply a different set of AttributeUsage properties to the class as I don't want to support multiple instances of this method. Note that you can use it in conjunction with the standard AuthorizeAttribute and achieve similar effects where you scope the class at one authorization level and narrow it down. You need to be careful, though, as class-level attributes may prevent this attribute from allowing owner access. Note that it also doesn't make sense to apply this attribute at the class level itself since it requires a specific id parameter for each method. &lt;pre class="csharpcode"&gt;&lt;br /&gt;[AttributeUsage( AttributeTargets.Method, Inherited = &lt;span class="kwrd"&gt;true&lt;/span&gt;, AllowMultiple = &lt;span class="kwrd"&gt;false&lt;/span&gt; )]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RoleOrOwnerAuthorizationAttribute : AuthorizeAttribute&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; routeParameter = &lt;span class="str"&gt;"id"&lt;/span&gt;;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// The name of the routing parameter to use to identify the owner of the data (participant id) in question.  Default is "id".&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; RouteParameter&lt;br /&gt;    {&lt;br /&gt;         get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.routeParameter; }&lt;br /&gt;         set { &lt;span class="kwrd"&gt;this&lt;/span&gt;.routeParameter = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;}&lt;/pre&gt;&lt;h4&gt;Constructor Injection&lt;/h4&gt;&lt;br /&gt;For the factory implementation and to allow easier unit testing I use constructor injection with a default instance.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; RoleOrOwnerAuthorizationAttribute()&lt;br /&gt;    : &lt;span class="kwrd"&gt;this&lt;/span&gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt; )&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; RoleOrOwnerAuthorizationAttribute( IDataContextFactory factory )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.ContextFactory = factory ?? &lt;span class="kwrd"&gt;new&lt;/span&gt; MyDataContextFactory();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The IDataContextFactory actually produces a DataContextWrapper, which I &lt;a href="http://farm-fresh-code.blogspot.com/2009/04/adventures-in-mocking-and-faking-linq.html"&gt;wrote about earlier&lt;/a&gt; when discussing how to mock and fake the LINQtoSQL data context.&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IDataContextFactory&lt;br /&gt;{&lt;br /&gt;    IDataContextWrapper GetDataContextWrapper();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyDataContextFactory : IDataContextFactory&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; IDataContextWrapper GetDataContextWrapper()&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; DataContextWrapper&amp;lt;MyDataContext&amp;gt;();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;Override OnAuthorization&lt;br /&gt;&lt;/h4&gt;&lt;blockquote&gt;&lt;br /&gt;Note I've refactored some code from the original AuthorizeAttribute that will be used when handling caching. The original attribute doesn't provide a mechanism to tie into this code directly so I've provided an implementation that is used when overriding OnAuthorization so that caching is handled properly. This code is copied almost verbatim from the AuthorizeAttribute -- it would be nice if they'd refactor so I could simply use it.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CacheValidateHandler( HttpContext context, &lt;span class="kwrd"&gt;object&lt;/span&gt; data, &lt;span class="kwrd"&gt;ref&lt;/span&gt; HttpValidationStatus validationStatus )&lt;br /&gt;{&lt;br /&gt;    validationStatus = OnCacheAuthorization( &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpContextWrapper( context ) );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetCachePolicy( AuthorizationContext filterContext )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="rem"&gt;// ** IMPORTANT **&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// Since we're performing authorization at the action level, the authorization code runs&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// after the output caching module. In the worst case this could allow an authorized user&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// to cause the page to be cached, then an unauthorized user would later be served the&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// cached page. We work around this by telling proxies not to cache the sensitive page,&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// then we hook our custom authorization code into the caching mechanism so that we have&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// the final say on whether a page should be served from the cache.&lt;/span&gt;&lt;br /&gt;    HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;&lt;br /&gt;    cachePolicy.SetProxyMaxAge( &lt;span class="kwrd"&gt;new&lt;/span&gt; TimeSpan( 0 ) );&lt;br /&gt;    cachePolicy.AddValidationCallback( CacheValidateHandler, &lt;span class="kwrd"&gt;null&lt;/span&gt; &lt;span class="rem"&gt;/* data */&lt;/span&gt;);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Now, all that remains is to provide the implementation. The implementation first runs AuthorizeCore from the parent class. If it succeeds, then we don't need to check for ownership. It then checks if the user is authenticated, if not, we return a redirect to the login page. Finally it checks if the user is the owner of the related data. If that succeeds, we continue on, otherwise we deliver an error message to the user. This latter is unlike the normal AuthorizeAttribute, which would redirect to the login page. In this case, though, the user is authenticated and simply does not have enough privilege.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnAuthorization( AuthorizationContext filterContext )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;"filterContext"&lt;/span&gt; );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (AuthorizeCore( filterContext.HttpContext ))&lt;br /&gt;    {&lt;br /&gt;        SetCachePolicy( filterContext );&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (!filterContext.HttpContext.User.Identity.IsAuthenticated)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;// auth failed, redirect to login page&lt;/span&gt;&lt;br /&gt;        filterContext.Result = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpUnauthorizedResult();&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (IsOwner( filterContext ))&lt;br /&gt;    {&lt;br /&gt;        SetCachePolicy( filterContext );&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        ViewDataDictionary viewData = &lt;span class="kwrd"&gt;new&lt;/span&gt; ViewDataDictionary();&lt;br /&gt;        viewData.Add( &lt;span class="str"&gt;"Message"&lt;/span&gt;, &lt;span class="str"&gt;"You do not have sufficient privileges for this operation."&lt;/span&gt; );&lt;br /&gt;        filterContext.Result = &lt;span class="kwrd"&gt;new&lt;/span&gt; ViewResult { ViewName = "Error", ViewData = viewData };&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsOwner( AuthorizationContext filterContext )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (IAuditableDataContextWrapper dc = &lt;span class="kwrd"&gt;this&lt;/span&gt;.ContextFactory.GetDataContextWrapper())&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;int&lt;/span&gt; id = -1;&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext.RouteData.Values.ContainsKey( &lt;span class="kwrd"&gt;this&lt;/span&gt;.RouteParameter ))&lt;br /&gt;        {&lt;br /&gt;            id = Convert.ToInt32( filterContext.RouteData.Values[&lt;span class="kwrd"&gt;this&lt;/span&gt;.RouteParameter] );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; userName = filterContext.HttpContext.User.Identity.Name;&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; dc.Table&amp;lt;Users&amp;gt;().Where( u =&amp;gt; u.UserName == userName &amp;amp;&amp;amp; u.UserID == id ).Any();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;h3&gt;Usage&lt;/h3&gt;&lt;br /&gt;Now we have an attribute that allows the user or anyone in a suitable role to have access to a controller action based on the current user and the routing parameter used to specify which user's data should be operated on.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[RoleOrOwnerAuthorization( Roles = &lt;span class="str"&gt;"Admin"&lt;/span&gt;, RouteParameter = &lt;span class="str"&gt;"userID"&lt;/span&gt; )]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult UpdateContact( &lt;span class="kwrd"&gt;int&lt;/span&gt; userID )&lt;br /&gt;{&lt;br /&gt;    ...&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-439017501568784265?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Dpbo-jEUNREub6UzYAeqa_t5H2Q/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Dpbo-jEUNREub6UzYAeqa_t5H2Q/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Dpbo-jEUNREub6UzYAeqa_t5H2Q/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Dpbo-jEUNREub6UzYAeqa_t5H2Q/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/H-rORln-XJY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/439017501568784265/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2009/11/customizing-authorization-in-aspnet-mvc.html#comment-form" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/439017501568784265?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/439017501568784265?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/H-rORln-XJY/customizing-authorization-in-aspnet-mvc.html" title="Customizing authorization in ASP.NET MVC" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>6</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2009/11/customizing-authorization-in-aspnet-mvc.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8HRXk5eip7ImA9WxNXFEw.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-7011241768989339966</id><published>2009-10-01T11:00:00.001-05:00</published><updated>2009-10-01T11:00:34.722-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-01T11:00:34.722-05:00</app:edited><title>Mocking the HtmlHelper class with Rhino.Mocks</title><content type="html">In developing HtmlHelper extensions, it's very useful to be able to pass in a mock HtmlHelper.  It's not particularly difficult, though I spent a fair amount of time trying to get the Response method, ApplyAppPathModifier to properly return a correct path based on it's value.  I finally gave up and decided to simply mock it out by allowing you to supply the path you want it to return via parameters.  The current version only works with simple paths of the form /controller/action/id since that's all I needed.  Here's the code I'm using to mock out the HtmlHelper for my extensions tests.  Add it to your static mocks class.  &lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; HtmlHelper CreateMockHelper( &lt;span class="kwrd"&gt;string&lt;/span&gt; routeController,&lt;br /&gt;                                           &lt;span class="kwrd"&gt;string&lt;/span&gt; routeAction,&lt;br /&gt;                                           &lt;span class="kwrd"&gt;object&lt;/span&gt; routeID )&lt;br /&gt;{&lt;br /&gt;    RouteData routeData = &lt;span class="kwrd"&gt;new&lt;/span&gt; RouteData();&lt;br /&gt;    routeData.Values[&lt;span class="str"&gt;"controller"&lt;/span&gt;] = routeController;&lt;br /&gt;    routeData.Values[&lt;span class="str"&gt;"action"&lt;/span&gt;] = routeAction;&lt;br /&gt;    routeData.Values[&lt;span class="str"&gt;"id"&lt;/span&gt;] = routeID;&lt;br /&gt;&lt;br /&gt;    var httpContext = MockRepository.GenerateStub&amp;lt;HttpContextBase&amp;gt;();&lt;br /&gt;    var viewContext = MockRepository.GenerateStub&amp;lt;ViewContext&amp;gt;();&lt;br /&gt;    var httpRequest = MockRepository.GenerateStub&amp;lt;HttpRequestBase&amp;gt;();&lt;br /&gt;    var httpResponse = MockRepository.GenerateStub&amp;lt;HttpResponseBase&amp;gt;();&lt;br /&gt;&lt;br /&gt;    httpContext.Stub( c =&amp;gt; c.Request ).Return( httpRequest ).Repeat.Any();&lt;br /&gt;    httpContext.Stub( c =&amp;gt; c.Response ).Return( httpResponse ).Repeat.Any();&lt;br /&gt;    httpResponse.Stub( r =&amp;gt; r.ApplyAppPathModifier( Arg&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;.Is.Anything ) )&lt;br /&gt;                .Return( &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format( &lt;span class="str"&gt;"/{0}/{1}/{2}"&lt;/span&gt;, routeController, routeAction, routeID ) );&lt;br /&gt;&lt;br /&gt;    viewContext.HttpContext = httpContext;&lt;br /&gt;    viewContext.RequestContext = &lt;span class="kwrd"&gt;new&lt;/span&gt; RequestContext( httpContext, routeData );&lt;br /&gt;    viewContext.RouteData = routeData;&lt;br /&gt;    viewContext.ViewData = &lt;span class="kwrd"&gt;new&lt;/span&gt; ViewDataDictionary();&lt;br /&gt;    viewContext.ViewData.Model = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    var helper = &lt;span class="kwrd"&gt;new&lt;/span&gt; HtmlHelper( viewContext, &lt;span class="kwrd"&gt;new&lt;/span&gt; ViewPage() );&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (helper.RouteCollection.Count == 0)&lt;br /&gt;    {&lt;br /&gt;        helper.RouteCollection.MapRoute(&lt;br /&gt;            &lt;span class="str"&gt;"Default"&lt;/span&gt;,                                              &lt;span class="rem"&gt;// Route name&lt;/span&gt;&lt;br /&gt;            &lt;span class="str"&gt;"{controller}/{action}/{id}"&lt;/span&gt;,                           &lt;span class="rem"&gt;// URL with parameters&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;new&lt;/span&gt; { controller = &lt;span class="str"&gt;"Home"&lt;/span&gt;, action = &lt;span class="str"&gt;"Index"&lt;/span&gt;, id = &lt;span class="str"&gt;""&lt;/span&gt; }  &lt;span class="rem"&gt;// Parameter defaults&lt;/span&gt;&lt;br /&gt;        );&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; helper;&lt;br /&gt;}&lt;/pre&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-7011241768989339966?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/9i5vVNIvD3Gf8-hHzgxwTw0Kl4M/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9i5vVNIvD3Gf8-hHzgxwTw0Kl4M/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/9i5vVNIvD3Gf8-hHzgxwTw0Kl4M/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/9i5vVNIvD3Gf8-hHzgxwTw0Kl4M/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/nmldL9ectNU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/7011241768989339966/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2009/10/mocking-htmlhelper-class-with.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/7011241768989339966?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/7011241768989339966?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/nmldL9ectNU/mocking-htmlhelper-class-with.html" title="Mocking the HtmlHelper class with Rhino.Mocks" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2009/10/mocking-htmlhelper-class-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkABQXozeip7ImA9WxNREEU.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-3267821687187002062</id><published>2009-08-12T17:23:00.002-05:00</published><updated>2009-09-04T12:19:10.482-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-04T12:19:10.482-05:00</app:edited><title>jQuery Theme Manager Plugin</title><content type="html">&lt;p&gt;Inspired by &lt;a href="http://stackoverflow.com/questions/1266275/automatic-jquery-stylesheet-switcher"&gt;this question&lt;/a&gt; on Stack Overflow, I decided to make a jQuery plug-in to handle switching themes on a web site that I'm working on. I based the plugin on the &lt;a href="http://net.tutsplus.com/demos/03_jQueryStyleSwitcher/demo/index.php#"&gt;code referenced in the question&lt;/a&gt; which is by James Padolsey. One of the requirements for the plugin is that it should work with a variety of different elements. I'm using it with a select, but I believe it would work with anchors and hidden inputs as it only depends on the name of the style sheet being located either in an href attribute or the value of the element. For select elements it relies on the value. &lt;/p&gt;&lt;p&gt;The plugin handles two different types of event triggers. If you are using a select, it will trigger on the change event. If you are using something else, it will trigger on the click event. To handle the case outlined in the question, I'd set up the style sheets choices using hidden inputs. I'd then add a click handler for each of these and have an interval timer that rotates among the hidden inputs, triggering the click event on the input corresponding with the current style. I haven't actually tried it, but I'm pretty sure it will work. :-) &lt;/p&gt;&lt;p&gt;The plugin assumes that you can switch styles by simply changing the url of a single stylesheet. If your theme isn't contained in a single stylesheet, you'll have to adapt the code to get it to work for you. The plugin is reasonably configurable. If you supply a loadingImg (full or relative url), it will use the Fade effect, otherwise it will use the Slide effect. I prefer the slide effect as it seems to work better when the stylesheet loads quickly. &lt;/p&gt;&lt;h3&gt;Options and Defaults&lt;/h3&gt;&lt;p&gt;&lt;dl&gt;&lt;dt&gt;loadingImg: null&lt;/dt&gt;&lt;dd&gt;No image will be shown. Supply an absolute or relative url (to the page) if you want a loading image. If this is non-null a Fade effect will be used for the overlay, otherwise a Slide effect is used.&lt;/dd&gt;&lt;dt&gt;bgColor: 'black'&lt;/dt&gt;&lt;dd&gt;This can be a hex value '#000' or a name, as shown&lt;/dd&gt;&lt;dt&gt;overlayID: 'reThemeOverlay'&lt;/dt&gt;&lt;dd&gt;The name of the overlay DIV, don't reuse an existing one&lt;/dd&gt;&lt;dt&gt;baseUrl: '/content/styles'&lt;/dt&gt;&lt;dd&gt;The CSS files supplied in the selector will be relative to this&lt;/dd&gt;&lt;dt&gt;styleSheet: 'theme'&lt;/dt&gt;&lt;dd&gt;The id of the stylesheet that will be replaced.&lt;/dd&gt;&lt;dt&gt;zIndex: 32767&lt;/dt&gt;&lt;dd&gt;The relative position in the z plane for the overlay. This needs to be large enough so that it covers all of the rest of the elements on the page.&lt;/dd&gt;&lt;dt&gt;speed: 'slow'&lt;/dt&gt;&lt;dd&gt;You can use any value available to the fadeIn/Out or slideIn/Out methods&lt;/dd&gt;&lt;dt&gt;delay: 0&lt;/dt&gt;&lt;dd&gt;This is the number of milliseconds you want plugin to wait after it thinks the stylesheet has been loaded before it begins the reveal. When combined with the speed parameter, setting this can improve the animation effect.&lt;/dd&gt;&lt;/dl&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;The plugin uses a simple heuristic to determine when the new stylesheet has been loaded. After the overlay has been applied, it first sets the href property of the stylesheet with the new url (note: if the name you supply doesn't end in .css, the extension will be supplied). Then it loads the stylesheet using an AJAX get request, with the reveal code executed by the callback on the get. Once the get completes -- presumably the other request has completed as well and the styles have been updated -- it then triggers the reveal after delaying for the specified amount of time. &lt;/p&gt;&lt;h3&gt;Example Usage&lt;/h3&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt; &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt; var theme = ViewData[&lt;span class="str"&gt;"theme"&lt;/span&gt;] &lt;span class="kwrd"&gt;as&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (theme.IsNothing())&lt;br /&gt;    {&lt;br /&gt;        theme = &lt;span class="str"&gt;"smoothness/jquery-ui-theme"&lt;/span&gt;;&lt;br /&gt;    } &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/javascript"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        $(&lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;            $(&lt;span class="str"&gt;'#themeSelector'&lt;/span&gt;)&lt;br /&gt;                   .find(&lt;span class="str"&gt;'option'&lt;/span&gt;)&lt;br /&gt;                   .each( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                       &lt;span class="kwrd"&gt;var&lt;/span&gt; $&lt;span class="kwrd"&gt;this&lt;/span&gt; = $(&lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;br /&gt;                       &lt;span class="kwrd"&gt;if&lt;/span&gt; ($&lt;span class="kwrd"&gt;this&lt;/span&gt;.val() == &lt;span class="str"&gt;'&amp;lt;%= theme %&amp;gt;'&lt;/span&gt;) {&lt;br /&gt;                           $&lt;span class="kwrd"&gt;this&lt;/span&gt;.attr(&lt;span class="str"&gt;'selected'&lt;/span&gt;,&lt;span class="str"&gt;'selected'&lt;/span&gt;);&lt;br /&gt;                       }&lt;br /&gt;                   });&lt;br /&gt;                      &lt;br /&gt;            $(&lt;span class="str"&gt;'#themeSelector'&lt;/span&gt;).retheme({&lt;br /&gt;                baseUrl: &lt;span class="str"&gt;'&amp;lt;%= Url.Content( "~/Content/styles/themes" ) %&amp;gt;'&lt;/span&gt;,&lt;br /&gt;                wait: 1000&lt;br /&gt;            }).change( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                $.post( &lt;span class="str"&gt;'&amp;lt;%= Url.Action( "SetTheme", "Participant" ) %&amp;gt;'&lt;/span&gt;, { theme: $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).val() }, &lt;span class="kwrd"&gt;function&lt;/span&gt;(data) {&lt;br /&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!data.Status) {&lt;br /&gt;                        alert(&lt;span class="str"&gt;'Failed to update preferences'&lt;/span&gt;);&lt;br /&gt;                    }&lt;br /&gt;                }, &lt;span class="str"&gt;'json'&lt;/span&gt;);&lt;br /&gt;            });&lt;br /&gt;           &lt;br /&gt;            $(&lt;span class="str"&gt;'#themeUI'&lt;/span&gt;).show();&lt;br /&gt;        });&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="themeUI"&lt;/span&gt; &lt;span class="attr"&gt;style&lt;/span&gt;&lt;span class="kwrd"&gt;="position: absolute; right: 0px; margin-right: 5px; top: 0px; margin-top: 5px; display: none;"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;label&lt;/span&gt; &lt;span class="attr"&gt;for&lt;/span&gt;&lt;span class="kwrd"&gt;="themeSelector"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Theme:&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;label&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;select&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="themeSelector"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="cupertino/jquery-ui-theme"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Cupertino&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="overcast/jquery-ui-theme"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Overcast&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="peppergrinder/jquery-ui-theme"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Pepper Grinder&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="smoothness/jquery-ui-theme"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Smoothness (default)&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="southstreet/jquery-ui-theme"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;South Street&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="ui-darkness/jquery-ui-theme"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;UI Darkness&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="vader/jquery-ui-theme"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Vader&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;option&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;select&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Code&lt;/h3&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;;(&lt;span class="kwrd"&gt;function&lt;/span&gt;($) {&lt;br /&gt;&lt;br /&gt;    $.fn.extend({&lt;br /&gt;        retheme: &lt;span class="kwrd"&gt;function&lt;/span&gt;(options,callback) {&lt;br /&gt;            options = $.extend( {}, $.Retheme.defaults, options );&lt;br /&gt;           &lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (options.loadingImg) {&lt;br /&gt;               &lt;span class="kwrd"&gt;var&lt;/span&gt; preLoad = &lt;span class="kwrd"&gt;new&lt;/span&gt; Image();&lt;br /&gt;               preLoad.src = options.loadingImg;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.each(&lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                &lt;span class="kwrd"&gt;new&lt;/span&gt; $.Retheme(&lt;span class="kwrd"&gt;this&lt;/span&gt;,options,callback);&lt;br /&gt;            });&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    });&lt;br /&gt;   &lt;br /&gt;    $.Retheme = &lt;span class="kwrd"&gt;function&lt;/span&gt;( ctl, options, callback ) {&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (options.styleSheet.match(/^\w/)) {&lt;br /&gt;            options.styleSheet = &lt;span class="str"&gt;'#'&lt;/span&gt; + options.styleSheet;&lt;br /&gt;        }&lt;br /&gt;        $(ctl).filter(&lt;span class="str"&gt;'select'&lt;/span&gt;).change( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;            loadTheme( themeSelector(&lt;span class="kwrd"&gt;this&lt;/span&gt;), options );&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (callback) callback.apply(&lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;        });&lt;br /&gt;        $(ctl).filter(&lt;span class="str"&gt;':not(select)'&lt;/span&gt;).click( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;            loadTheme( themeSelector(&lt;span class="kwrd"&gt;this&lt;/span&gt;), options  );&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (callback) callback.apply(&lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;        });&lt;br /&gt;    };&lt;br /&gt;   &lt;br /&gt;    &lt;span class="kwrd"&gt;function&lt;/span&gt; themeSelector(ctl) {&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; $&lt;span class="kwrd"&gt;this&lt;/span&gt; = $(ctl);&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; theme = $&lt;span class="kwrd"&gt;this&lt;/span&gt;.attr(&lt;span class="str"&gt;'href'&lt;/span&gt;);&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!theme) {&lt;br /&gt;            theme = $&lt;span class="kwrd"&gt;this&lt;/span&gt;.val();&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; theme;&lt;br /&gt;    }&lt;br /&gt;   &lt;br /&gt;    &lt;span class="kwrd"&gt;function&lt;/span&gt; loadTheme( theme, options ) {&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; themeHref = options.baseUrl + &lt;span class="str"&gt;'/'&lt;/span&gt; + theme;&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!themeHref.match(/\.css$/)) {&lt;br /&gt;            themeHref += &lt;span class="str"&gt;'.css'&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;       &lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; styleSheet = $(options.styleSheet);&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; counter = options.maxTries;&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; bg = options.bgColor;&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (options.loadingImg) {&lt;br /&gt;            bg += &lt;span class="str"&gt;' url('&lt;/span&gt; + options.loadingImg + &lt;span class="str"&gt;') no-repeat center'&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; speed = options.speed;&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; delay = options.delay;&lt;br /&gt;       &lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; $body = $(&lt;span class="str"&gt;'body'&lt;/span&gt;);&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; overlay = $(&lt;span class="str"&gt;'&amp;lt;div id="'&lt;/span&gt; + options.overlayID + &lt;span class="str"&gt;'"&amp;gt;&amp;lt;/div&amp;gt;'&lt;/span&gt;).appendTo($body);&lt;br /&gt;        $body.css( { height: &lt;span class="str"&gt;'100%'&lt;/span&gt; } );&lt;br /&gt;        overlay.css({&lt;br /&gt;                display: &lt;span class="str"&gt;'none'&lt;/span&gt;,&lt;br /&gt;                position: &lt;span class="str"&gt;'absolute'&lt;/span&gt;,&lt;br /&gt;                top:0,&lt;br /&gt;                left: 0,&lt;br /&gt;                width: &lt;span class="str"&gt;'100%'&lt;/span&gt;,&lt;br /&gt;                height: &lt;span class="str"&gt;'100%'&lt;/span&gt;,&lt;br /&gt;                zIndex: options.zIndex,&lt;br /&gt;                background: bg&lt;br /&gt;        })&lt;br /&gt;        .stop( &lt;span class="kwrd"&gt;true&lt;/span&gt; );&lt;br /&gt;       &lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (options.loadingImg) {&lt;br /&gt;            overlay.fadeIn( speed, &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                styleSheet.attr( &lt;span class="str"&gt;'href'&lt;/span&gt;, themeHref );&lt;br /&gt;                $.get( themeHref, &lt;span class="kwrd"&gt;function&lt;/span&gt;() {  &lt;span class="rem"&gt;// basically load it twice, but that will make sure it's been applied before we reveal&lt;/span&gt;&lt;br /&gt;                    setTimeout( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                        overlay.fadeOut( speed, &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                            $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).remove();&lt;br /&gt;                        });&lt;br /&gt;                    }, delay );&lt;br /&gt;                });&lt;br /&gt;            });&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;else&lt;/span&gt; {&lt;br /&gt;            overlay.slideDown( speed, &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                styleSheet.attr( &lt;span class="str"&gt;'href'&lt;/span&gt;, themeHref );&lt;br /&gt;                $.get( themeHref, &lt;span class="kwrd"&gt;function&lt;/span&gt;() {  &lt;span class="rem"&gt;// basically load it twice, but that will make sure it's been applied before we reveal&lt;/span&gt;&lt;br /&gt;                    setTimeout( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                        overlay.slideUp( speed, &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                            $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).remove();&lt;br /&gt;                        });&lt;br /&gt;                    }, delay );&lt;br /&gt;                });&lt;br /&gt;            });&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;     &lt;br /&gt;    $.Retheme.defaults = {&lt;br /&gt;        loadingImg: &lt;span class="kwrd"&gt;null&lt;/span&gt;,&lt;br /&gt;        bgColor: &lt;span class="str"&gt;'black'&lt;/span&gt;,&lt;br /&gt;        overlayID: &lt;span class="str"&gt;'reThemeOverlay'&lt;/span&gt;,&lt;br /&gt;        baseUrl: &lt;span class="str"&gt;'/content/styles'&lt;/span&gt;,&lt;br /&gt;        styleSheet: &lt;span class="str"&gt;'theme'&lt;/span&gt;,&lt;br /&gt;        zIndex: 32767,&lt;br /&gt;        speed: &lt;span class="str"&gt;'slow'&lt;/span&gt;,&lt;br /&gt;        delay: 0&lt;br /&gt;    };&lt;br /&gt;   &lt;br /&gt;})(jQuery);&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Demo&lt;/h3&gt;&lt;br /&gt;A simple demo that uses both a select element and buttons to choose themes can be found at &lt;a href="http://myweb.uiowa.edu/timv/retheme-demo"&gt;http://myweb.uiowa.edu/timv/retheme-demo&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Fixed&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Added a callback parameter so you can execute your own code after the theme has been loaded. Note that&lt;br /&gt;the callback will be invoked prior to the reveal animation.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The plugin now prevents the default action associated with the trigger element. If you want the default action to be taken, you'll need to reapply it via the callback mechanism.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;To Do&lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;I'd like to refactor the reveal code so that I don't have to repeat it for the different effects. I think I'd have to figure out the different animation parameters for each effect and set them up, but I'm too lazy to do that for now.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Fix the hand-coded style of the select control and apply it as a class. This was just for a proof-of-concept, but it should be refactored.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-3267821687187002062?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/4uaiKTPEENMD4eT1JDmzBySUbEw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/4uaiKTPEENMD4eT1JDmzBySUbEw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/4uaiKTPEENMD4eT1JDmzBySUbEw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/4uaiKTPEENMD4eT1JDmzBySUbEw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/YqDkavF-Yqc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/3267821687187002062/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2009/08/jquery-theme-manager-plugin.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/3267821687187002062?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/3267821687187002062?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/YqDkavF-Yqc/jquery-theme-manager-plugin.html" title="jQuery Theme Manager Plugin" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2009/08/jquery-theme-manager-plugin.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQNRXs5eCp7ImA9WxJVGUo.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-5351834683792968448</id><published>2009-07-07T08:20:00.003-05:00</published><updated>2009-07-07T08:29:54.520-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-07T08:29:54.520-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="nerd geek" /><title>How nerdy are you?</title><content type="html">I was watching a videos series with our Bible study the other night on the topic of historical revisionism.  As an example of how meaning does not arise ex nihilo (out of nothing), but is informed by our historical experiences, the lecturer showed a series of numbers and asked what they meant.  One sequence began with "1" -- everyone in the video, and in my head, I too said "that's the number one."  The next number in the sequence was "11" -- of which I thought, that's 3.&lt;br /&gt;&lt;br /&gt;That would make me nerdy;  I know that there are only 10 kinds of people in the world.  I'm in the set that understands binary.&lt;br /&gt;&lt;br /&gt;That wasn't really the "trick" of the sequence.  The sequence ended with "911" -- which everyone identified as "9-1-1", not "nine hundred eleven" and "9/11", both of which have a completely different meaning than they did only a few years ago.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-5351834683792968448?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/6TXZa4hKk0P825vMTT1UWFHOUgI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6TXZa4hKk0P825vMTT1UWFHOUgI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/6TXZa4hKk0P825vMTT1UWFHOUgI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6TXZa4hKk0P825vMTT1UWFHOUgI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/hIMetHAM_jQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/5351834683792968448/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2009/07/how-nerdy-are-you.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/5351834683792968448?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/5351834683792968448?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/hIMetHAM_jQ/how-nerdy-are-you.html" title="How nerdy are you?" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2009/07/how-nerdy-are-you.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4ER386eip7ImA9WxJXF0k.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-7647596376880483673</id><published>2009-06-11T13:23:00.004-05:00</published><updated>2009-06-11T13:28:26.112-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-11T13:28:26.112-05:00</app:edited><title>Collapsible tables: handling ranges of elments with jQuery</title><content type="html">In the past week or so I've answered a couple of questions on &lt;a href="http://stackoverflow.com/"&gt;StackOverflow&lt;/a&gt; about how to handle operations ranges of elements before/after a particular element. One recent question had to do with &lt;a href="http://stackoverflow.com/questions/982522"&gt;collapsible tables&lt;/a&gt; and I thought I'd share my answer to that question as general technique for this type of operation.&lt;br /&gt;&lt;br /&gt;The basic idea is that you have a series of elements that you want to do something with within a larger series of similar elements. For example, you have a table consisting of some rows that are "headers" and some that are "row". You want to be able to operate on the sub-range without applying the same operations to the entire range or elements outside the subrange.&lt;br /&gt;&lt;br /&gt;One way to do this is to use classes to mark your elements with context. Then use the &lt;strong&gt;each&lt;/strong&gt; method, with &lt;strong&gt;prevAll&lt;/strong&gt; and &lt;strong&gt;nextAll&lt;/strong&gt; operations on the given element to iterate through the range of elements, performing the desired operation until you come to an element that has a class (context) that marks the end of the range.&lt;br /&gt;&lt;br /&gt;For example, consider the following table: &lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;table&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='header'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;th&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;header 1&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;th&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='row'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;row 1-1&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='row'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;row 1-2&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='row'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;row 1-3&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='header'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;th&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;header 2&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;th&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='row'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;row 2-1&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='row'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;row 2-2&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='row'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;row 2-3&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='header'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;th&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;header 3&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;th&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='row'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;row 3-1&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='row'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;row 3-2&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;='row'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;row 3-3&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;table&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When you click on a row, you want all the rows in the local range (between the headers) to collapse. When you click on a header (for a collapsed set of rows) you want it to re-expand.&lt;br /&gt;&lt;br /&gt;To accomplish this, create a click handler for the rows with class &lt;strong&gt;row&lt;/strong&gt;, that hides itself and both the previous and next rows until it encounters a row with class &lt;strong&gt;header&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;$(&lt;span class="str"&gt;'table tr.row'&lt;/span&gt;).click( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;    $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).hide();&lt;br /&gt;    $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).prevAll(&lt;span class="str"&gt;'tr'&lt;/span&gt;).each( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; ($(&lt;span class="kwrd"&gt;this&lt;/span&gt;).hasClass(&lt;span class="str"&gt;'header'&lt;/span&gt;)) {&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;        $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).hide();&lt;br /&gt;    });&lt;br /&gt;    $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).nextAll(&lt;span class="str"&gt;'tr'&lt;/span&gt;).each( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; ($(&lt;span class="kwrd"&gt;this&lt;/span&gt;).hasClass(&lt;span class="str"&gt;'header'&lt;/span&gt;)) {&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;        $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).hide();&lt;br /&gt;    });&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And to re-expand the collapsed rows, create a click handler for the rows with class &lt;strong&gt;header&lt;/strong&gt;, that iterates through the next row siblings of the header, showing each row until it encounters another row with class &lt;strong&gt;header&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;$(&lt;span class="str"&gt;'table tr.header'&lt;/span&gt;).click( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;    $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).nextAll(&lt;span class="str"&gt;'tr'&lt;/span&gt;).each( &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; ($(&lt;span class="kwrd"&gt;this&lt;/span&gt;).hasClass(&lt;span class="str"&gt;'header'&lt;/span&gt;)) {&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;        $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).show();&lt;br /&gt;    });&lt;br /&gt;});&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-7647596376880483673?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/HekwcaZpPfO5b1B-K8vJLqQTfvU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HekwcaZpPfO5b1B-K8vJLqQTfvU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/HekwcaZpPfO5b1B-K8vJLqQTfvU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HekwcaZpPfO5b1B-K8vJLqQTfvU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/J_2NKxw4XFc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/7647596376880483673/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2009/06/collapsible-tables-handling-ranges-of.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/7647596376880483673?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/7647596376880483673?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/J_2NKxw4XFc/collapsible-tables-handling-ranges-of.html" title="Collapsible tables: handling ranges of elments with jQuery" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2009/06/collapsible-tables-handling-ranges-of.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ADQnwyeyp7ImA9WxJbF04.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-2173332688420560424</id><published>2009-05-16T08:02:00.010-05:00</published><updated>2009-07-27T16:56:13.293-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-27T16:56:13.293-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="jQuery mvc session logout" /><title>Client-side session termination</title><content type="html">One of the most annoying things about session timeout, especially in a web site that uses AJAX, is that often the user is unaware of it.  They come back to their computer after an extended time away, the page is right there as they left it, but when they start interacting with it, it exhibits strange behavior.  &amp;quot;Why is the login page showing up where my report ought to be?&amp;quot;  Or &amp;quot;Where did my data go?  I just clicked the sort by name column and all of my data disappeared.&amp;quot;&lt;br /&gt;&lt;br /&gt;  Of course, we developers know what happened.  Our AJAX code got caught in the authentication/authorization trap because the session expired.   The automatic methods we've set up to prevent unauthenticated users from accessing our site worked too well and the AJAX request got redirected as well.&lt;br /&gt;&lt;br /&gt;  Rather than build session awareness into all of my AJAX code, I've decided to take a different tack.  I've created a jQuery plugin that works client-side to warn the user that their session is about to expire and, absent a confirmation to continue the session, redirects the user to the logout action of my MVC web site to formally end the session.&lt;br /&gt;&lt;br /&gt;  &lt;span style="font-weight:bold;"&gt;Requirements&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  I had a few requirements for my plugin.  First, it needed to work with jQuery, obviously.  In fact I had some existing non-jQuery code that I converted to a jQuery plugin.  I did this partly as a learning experience in developing jQuery plugins and partly because I wanted to declutter the global javascript scope.  It also reduces the complexity of my master page as I moved the code to its own javascript file (it's an intranet application so I'm not particularly concerned about adding to the number of requests being made).&lt;br /&gt;&lt;br /&gt;  Second, I wanted the plugin to use a dialog to inform the user of the imminent expiration of their session and allow them to continue it if they wanted or end it immediately.  To this end, the plugin requires that the developer supply a URL that can be accessed to continue the session and another that will end the session: &lt;span style="font-style: italic;"&gt;refreshUrl&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;logoutUrl&lt;/span&gt;.  In my use I picked an existing lightweight page as the refresh url, though you could create a separate action.  I use sliding windows so any request to the server will reset the server-side session timer so this worked for me.   If your requirements are more complex a separate action may be preferable.  For the logout, I used the same logout action that's connected to the logout button.   Additional data can be added to the URLs by appending query parameters.  The plugin only supports the GET method at this time.&lt;br /&gt;&lt;br /&gt;Since I'm already using jQuery UI, my plugin relies on the j&lt;a href="http://docs.jquery.com/UI/API/1.7/Dialog"&gt;Query UI Dialog&lt;/a&gt; widget.  To this end the plugin requires that you have an element on the page that will function as the prompt dialog.  The plugin is actually chained off this element.  It will add &lt;span style="font-weight:bold;"&gt;OK&lt;/span&gt; and &lt;span style="font-weight:bold;"&gt;Logout&lt;/span&gt;buttons to the dialog.&lt;br /&gt;&lt;br /&gt;  Third, I wanted the session timeout and dialog wait times to be configurable so that I could supply actual timeout values from the real session via ViewData.  I decided to provide sensible, for me, defaults based on the default ASP.NET session timeout of 18 minutes and 1.5 minutes, respectively.  That is, the dialog will pop up after 18 minutes of &amp;quot;inactivity&amp;quot; and after an additional 1.5 minutes of &amp;quot;inactivity&amp;quot; the logout action will be invoked. &lt;br /&gt;&lt;br /&gt;  Since the default timeout for an ASP.NET session is 20 minutes, this means that the client-side will terminate the session 30 seconds before the server-side.  This prevents the logout action itself from being redirected to the logon page.  Strange things can happen if you're not careful about this.  You don't want the redirection to end up with the logon page redirecting back to the logout action as can happen if your logout action requires authentication.  This is a strictly a problem for my plugin, but I decided to avoid the potential complication by ending the session early.  Developers need to be aware that whatever value you they supply for the timeouts will be adjusted so that the actual invocation of the timeout will occur 30 seconds prior to the supplied session timeout value.&lt;br /&gt;&lt;br /&gt;  Lastly, I wanted the plugin to restart its timers on any interaction with the server, rather than on client-side interaction.  I decided that it was too much overhead and additional complexity to reset the timers on client-side interaction.  To do so I would have to detect all events on the page and periodically &amp;quot;phone home&amp;quot; to ensure that the server side session was refreshed.  I did, however, want to reset the timers on AJAX interactivity so the plugin inserts some default behavior into the ajaxStart chain that does this.&lt;br /&gt;&lt;br /&gt;  &lt;span style="font-weight:bold;"&gt;Implementation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  I use the jQuery &lt;a href="http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/"&gt;autocomplete plugin&lt;/a&gt; as my implementation template.  I felt that it provided a clean and easy to understand implementation.  Below is my current code with a sample implementation.  &lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="rem"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt; * Autologout - jQuery plugin 0.1&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt; *&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt; * Copyright (c) 2009 Tim Van Fosson&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt; *&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt; * Dependencies: jQuery 1.3.2, jQuery UI 1.7.1, bgiframe (by default)&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt; *&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;;(&lt;span class="kwrd"&gt;function&lt;/span&gt;($) {&lt;br /&gt;    &lt;br /&gt;    $.fn.extend({&lt;br /&gt;        autologout: &lt;span class="kwrd"&gt;function&lt;/span&gt;(refreshUrl, logoutUrl, options) {&lt;br /&gt;            options = $.extend( {}, $.Autologout.defaults, options );&lt;br /&gt;            &lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.each(&lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                &lt;span class="kwrd"&gt;new&lt;/span&gt; $.Autologout(&lt;span class="kwrd"&gt;this&lt;/span&gt;, refreshUrl, logoutUrl, options);&lt;br /&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;            });&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    });&lt;br /&gt;&lt;br /&gt;    $.Autologout = &lt;span class="kwrd"&gt;function&lt;/span&gt;( prompt, refreshUrl, logoutUrl, options ) {&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; logoutTimer = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; sessionTimer = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; dialogWait = Math.max( 0, Number( options.sessionDialogWait * 60000 ) );      &lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; timeout = Math.max( 30000, (Number(options.sessionTimeout) * 60000) - dialogWait) - 30000;&lt;br /&gt;        &lt;br /&gt;        $(prompt).dialog( {&lt;br /&gt;            autoOpen: &lt;span class="kwrd"&gt;false&lt;/span&gt;,&lt;br /&gt;            bgiframe: options.bgiframe,&lt;br /&gt;            modal: &lt;span class="kwrd"&gt;true&lt;/span&gt;,&lt;br /&gt;            buttons: {&lt;br /&gt;                OK: &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                    $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).dialog(&lt;span class="str"&gt;'close'&lt;/span&gt;);&lt;br /&gt;                    $.get( refreshUrl, resetTimers, &lt;span class="str"&gt;'html'&lt;/span&gt; );&lt;br /&gt;                },&lt;br /&gt;                Logout: sessionExpired&lt;br /&gt;            },&lt;br /&gt;            open: &lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (options.pageSelector) {&lt;br /&gt;                    &lt;span class="kwrd"&gt;var&lt;/span&gt; height = $(options.pageSelector).outerHeight();&lt;br /&gt;                    $('.ui-widget-overlay').animate( { 'height' : height }, 'fast' );&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }).ajaxStart( &lt;span class="kwrd"&gt;function&lt;/span&gt;() { resetTimers(); } );&lt;br /&gt;        &lt;br /&gt;        resetTimers();&lt;br /&gt;            &lt;br /&gt;        &lt;span class="kwrd"&gt;function&lt;/span&gt; resetTimers()&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (logoutTimer) clearTimeout(logoutTimer);&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (sessionTimer) clearTimeout(sessionTimer);&lt;br /&gt;            &lt;br /&gt;            sessionTimer = setTimeout( sessionExpiring, timeout  );&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        &lt;span class="kwrd"&gt;function&lt;/span&gt; sessionExpiring()&lt;br /&gt;        {&lt;br /&gt;             logoutTimer = setTimeout( sessionExpired, dialogWait );&lt;br /&gt;             $(prompt).dialog(&lt;span class="str"&gt;'open'&lt;/span&gt;);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        &lt;span class="kwrd"&gt;function&lt;/span&gt; sessionExpired()&lt;br /&gt;        {&lt;br /&gt;            window.location.href = logoutUrl;&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    $.Autologout.defaults = {&lt;br /&gt;        sessionTimeout: 20,&lt;br /&gt;        sessionDialogWait: 1.5,&lt;br /&gt;        bgiframe: &lt;span class="kwrd"&gt;true&lt;/span&gt;,&lt;br /&gt;        pageSelector: &lt;span class="kwrd"&gt;null&lt;/span&gt;&lt;br /&gt;    };&lt;br /&gt;    &lt;br /&gt;})(jQuery);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; Note that I've added in the ability to specify a selector for your page content.  In instances where the content is generated dynamically on the page, I've found that the dialog overlay can be too small for the generated content.  If you specify a selector for an element that takes up the entire page, the overlay will be resized when the dialog is shown so that it covers all the content.&lt;br /&gt;&lt;br /&gt;Sample implementation -- from my master page.  Notice how I only include the code on the page if the request is authenticated.  It shouldn't be run on any page that doesn't have an authenticated session, obviously.&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &amp;lt;% &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.Request.IsAuthenticated)&lt;br /&gt;       {&lt;br /&gt;           &lt;span class="kwrd"&gt;double&lt;/span&gt; sessionDialogWait = 1.5;&lt;br /&gt;           &lt;span class="kwrd"&gt;double&lt;/span&gt; sessionTimeout = 30;&lt;br /&gt;           &lt;span class="kwrd"&gt;if&lt;/span&gt; (ViewData[&lt;span class="str"&gt;"sessionTimeout"&lt;/span&gt;] != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;           {&lt;br /&gt;               sessionTimeout = Convert.ToDouble( ViewData[&lt;span class="str"&gt;"sessionTimeout"&lt;/span&gt;] );&lt;br /&gt;           }&lt;br /&gt;    %&amp;gt;&lt;br /&gt;    &amp;lt;%= Html.Javascript( Url.Content( &lt;span class="str"&gt;"~/Scripts/autologout.js"&lt;/span&gt; ) ) %&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;script type=&lt;span class="str"&gt;"text/javascript"&lt;/span&gt;&amp;gt;&lt;br /&gt;    $(document).ready( function() {&lt;br /&gt;        $(&lt;span class="str"&gt;'#sessionEndDialog'&lt;/span&gt;).autologout( &lt;span class="str"&gt;'&amp;lt;%= Url.Action( "About", "Home" ) %&amp;gt;'&lt;/span&gt;, &lt;span class="str"&gt;'&amp;lt;%= Url.Action( "Logout", "Account" ) %&amp;gt;'&lt;/span&gt;, {&lt;br /&gt;            sessionTimeout : Number(&lt;span class="str"&gt;'&amp;lt;%= sessionTimeout %&amp;gt;'&lt;/span&gt;),&lt;br /&gt;            sessionDialogWait: Number(&lt;span class="str"&gt;'&amp;lt;%= sessionDialogWait %&amp;gt;'&lt;/span&gt;)&lt;br /&gt;        });&lt;br /&gt;    });&lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;% } %&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;...snip...&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="sessionEndDialog"&lt;/span&gt; &lt;span class="attr"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;="Session Expiring"&lt;/span&gt; &lt;span class="attr"&gt;style&lt;/span&gt;&lt;span class="kwrd"&gt;="display: none;"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        Your session is about to expire. Click OK to renew your session or Logout to logout&lt;br /&gt;        of the application.&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-2173332688420560424?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/eNySHiAacOewCLd082wOMttzvfg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eNySHiAacOewCLd082wOMttzvfg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/eNySHiAacOewCLd082wOMttzvfg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eNySHiAacOewCLd082wOMttzvfg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/uInziGpD_a8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/2173332688420560424/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2009/05/client-side-session-termination.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/2173332688420560424?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/2173332688420560424?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/uInziGpD_a8/client-side-session-termination.html" title="Client-side session termination" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>5</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2009/05/client-side-session-termination.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4FQHc4fyp7ImA9WxJREE0.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-8426149692855107209</id><published>2009-05-10T18:11:00.010-05:00</published><updated>2009-05-10T19:48:31.937-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-10T19:48:31.937-05:00</app:edited><title>Tales of UI Mock ups</title><content type="html">I'm not, or perhaps I should say, I wasn't a big fan of using tools for UI mock ups.&lt;br /&gt;&lt;br /&gt;Most of the time I prefer to do my mockups on a whiteboard.  Mocking up a UI on a whiteboard has several advantages.  First, &lt;strong&gt;the client&lt;/strong&gt; knows that it's not the real UI.  It's amazing, to me anyway, how important that really is.  The minute you have something that looks real, you start focusing the details of the interface.  Early on, when the mock up is most useful, you don't want to spend much time worrying about the particular details -- how many pixels away from this input element the text is or the exact color of that background.&lt;br /&gt;&lt;br /&gt;I find that it's helpful to draw a picture of how the interface &lt;em&gt;might&lt;/em&gt; work when trying to explain my ideas of how it &lt;em&gt;could&lt;/em&gt; work.  My feeling is that making the UI mockup too real at this point runs the risk of changing the focus from the function of the application to the look of the application.  Now, there are aspects of the interface that both strongly affect functionality and are driven by it.  For example, drop down lists are excellent ways to present a small number of fixed choices to a user, but fixating on a drop down list can drive the design of the interface in ways that may not be appropriate if the number of potential inputs is very large.  Knowing what you need to accomplish at this point is much more important that deciding how you are going to accomplish it.  Conversely, once you know the parameters of what you are trying to accomplish, some of the UI interface components are constrained.&lt;br /&gt;&lt;br /&gt;Second,  &lt;strong&gt;I know&lt;/strong&gt; that it's not the real interface.  You may not have this problem, but I tend to be a perfectionist.  For me, using a tool holds the temptation for me to start fixating on the details of the interface.  I start worrying about the color scheme -- trying various combinations and shadings to get just the right look -- or spending time getting this particular element to line up with that one or center under another.  Now there is a time to focus on that, assuming that it's important to the customer, but mock up time is probably not the time for this.  I'd really prefer to get a version or two in front of the customer to use before I start spending a lot of time trying to perfect the look and feel.&lt;br /&gt;&lt;br /&gt;Because I follow an agile philosophy, I expect that feedback on the early versions will drive the functionality and the interface in ways that we may not have expected when conceiving the initial application requirements.  The further we get into development, the more stable the interface will, or should, become.   Once the interface has stabilized it makes more sense to spend effort on getting the look and feel perfected.  That's not to say that significant effort doesn't go into developing the interface, but I prefer that it be done as I'm developing the actual interface not the mock up.   I prefer to use the mock up as a design guideline, not a finished product that needs to simply be translated into the application.&lt;br /&gt;&lt;br /&gt;In addition, I really like the extremely low cost of using a whiteboard.  I don't have to worry about access to the computer on my desk with the application.  I don't have to spend a lot of time in advance preparing different versions, anticipating the possible the directions the feature discussion will take.&lt;br /&gt;&lt;br /&gt;Unfortunately, there's one or two very big disadvantages to the whiteboard: it's hard to keep the artifacts you develop there in a format that is both permanent and modifiable.   This is especially true if the whiteboard is not in your office.  I often take pictures of the whiteboard and store them in my development wiki along with my stories, but I can only refer back to these.  If I want to make changes, I need to redraw the mock up each time, take a picture, and store it.  It's also very difficult to share a whiteboard, at least, a &lt;em&gt;plain, ol' whiteboard&lt;/em&gt;, such as the ones we have in our office, with people who aren't in the same building.&lt;br /&gt;&lt;br /&gt;I recently ran into a problem along this line with the&lt;a href="http://farm-fresh-code.blogspot.com/2009/04/jquery-cycle-adding-player-controls-to.html"&gt; jQuery slideshow&lt;/a&gt; I wrote about earlier.  I wasn't happy with the location of my slideshow controls: centered over the top of the image.  Whenever the image orientation or size change in the slideshow, the controls would move on the page.  It was disconcerting to say the least.   Rather than change the actual interface, I decided to mock up some alternatives to see how it would work visually before committing to changing code.&lt;br /&gt;&lt;br /&gt;I could have done this on a whiteboard and, in the past, I probably would have.  I decided to try out a new tool, however, that I had found out about on &lt;a href="http://stackoverflow.com"&gt;StackOverflow&lt;/a&gt;.  That tool is &lt;a href="http://www.balsamiq.com/"&gt;Balsamiq Mockups&lt;/a&gt; from Balsamlq Studios.  Balsamiq Mockups basically allows you to sketch out a user interface in a way that mimics a hand-drawn interface.  You can save the interface, open it up again later, and modify it if you want.  Balsamiq has versions of their tool for Confluence, Jira, and xWiki, as well as a desktop version.&lt;br /&gt;&lt;br /&gt;I decided to download a copy of their desktop version and draw up my interface.  Unfortunately, the trial version didn't include the ability to save and I didn't make a screenshot, but I was really pleased with how quickly I was able to mock up a look alike to the existing interface and make my control changes.  Once I did I was able to see that the controls, now anchored in a 2x3 block on the upper left of the images, worked well visually.  I went ahead with the changes and, more to the point, decided to convince my manager to try the version for Confluence, which I also use as a permanent extension of my development practices.  I have a lot of hopes for Balsamiq Mockups.  It seems to encompass the best features of hand-drawn mock ups - we can focus on the elements, not the details and there's not a lot of investment/cost to developing them -- and allows me to save and share them for later use.&lt;br /&gt;&lt;br /&gt;Below are a couple of mock ups developed with the trial version of the tool for Confluence.  Neither of these took more than a few minutes to work up.  They are embedded in the wiki with my development stories and available to the customer from the web.  Notice how in the second mock up, I've replaced the image placeholder in the header with one of the standard icons.  You can check out the actual interface at &lt;a href="http://osl.iowa.uiowa.edu/dancemarathon"&gt;http://osl.iowa.uiowa.edu/dancemarathon&lt;/a&gt; for comparison.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;Original Gallery&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Sfoy8NUpvKk/SgdzFr7wsZI/AAAAAAAAAA4/JsPAwOuPy-U/s1600-h/mockup_Original+Gallery.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 320px;" src="http://4.bp.blogspot.com/_Sfoy8NUpvKk/SgdzFr7wsZI/AAAAAAAAAA4/JsPAwOuPy-U/s400/mockup_Original+Gallery.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5334358825173561746" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;Updated Gallery Showing New Menu Item&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_Sfoy8NUpvKk/SgdzlMlZjCI/AAAAAAAAABA/0JoBMYPk6Q0/s1600-h/mockup_New+with+Donate+Menu+item.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 335px;" src="http://3.bp.blogspot.com/_Sfoy8NUpvKk/SgdzlMlZjCI/AAAAAAAAABA/0JoBMYPk6Q0/s400/mockup_New+with+Donate+Menu+item.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5334359366514084898" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We're still early in develop on this application so we haven't invested a lot in the public interface.  The application is still mostly oriented toward the administrative functions required for managing the Dance Marathon event.  I fully expect to get much more use out of the tool as we work on the Donor and other public parts of the application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-8426149692855107209?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/oU-DsErSrstbhRdnCXHYXBIhC8Y/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oU-DsErSrstbhRdnCXHYXBIhC8Y/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/oU-DsErSrstbhRdnCXHYXBIhC8Y/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oU-DsErSrstbhRdnCXHYXBIhC8Y/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/ZiJ1Nefj8gs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/8426149692855107209/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2009/05/tales-of-ui-mock-ups.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/8426149692855107209?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/8426149692855107209?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/ZiJ1Nefj8gs/tales-of-ui-mock-ups.html" title="Tales of UI Mock ups" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_Sfoy8NUpvKk/SgdzFr7wsZI/AAAAAAAAAA4/JsPAwOuPy-U/s72-c/mockup_Original+Gallery.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2009/05/tales-of-ui-mock-ups.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0IDSH45cSp7ImA9WxBXEE0.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-7992583130630239111</id><published>2009-05-05T15:51:00.009-05:00</published><updated>2010-01-20T10:39:39.029-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-20T10:39:39.029-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linq linqtosql audit" /><title>Auditing inserts and updates using LINQ to SQL</title><content type="html">Any time you have an application where multiple people fill different roles in the application, you probably have a need to audit at least some of the changes that those people can make in your database. Sometimes this might be for security purposes; other times you may want to be able to quickly restore the state of a particular row or rows in the database. I often do auditing for these purposes. Recently I discovered another use, which undoubtedly others discovered before me, but it's sometimes helpful to provide notifications based on changes in the database. An audit log can provide the history for these types of triggers.&lt;br /&gt;&lt;br /&gt;The application I'm currently working on, a tracking application for the &lt;a href="http://www.dancemarathon.org/"&gt;Dance Marathon&lt;/a&gt; [not my site] student group at the Unversity of Iowa, has some of these auditing needs. Since I'm using LINQ to SQL as my ORM, I chose to implement my auditing code-side in submit changes. To this end, I created an &lt;strong&gt;AuditableDataContextBase &lt;/strong&gt;class that derives from &lt;strong&gt;DataContext &lt;/strong&gt;and will be the base class for my LINQ to SQL data context. The context has an CurrentUser property that holds the identity of the current user. This property is set in the factory method that creates my data context. &lt;strong&gt;AuditUser &lt;/strong&gt;is actually pretty simple: &lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AuditUser&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; ID { get; set; }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name { get; set; }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; AuditUser()&lt;br /&gt;    {&lt;br /&gt;        ID = 0;&lt;br /&gt;        Name = &lt;span class="str"&gt;"system"&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; AuditUser( Participant participant )&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (participant == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;"participant"&lt;/span&gt; );&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.ID = participant.ParticipantID;&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Name = participant.DisplayName;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The &lt;strong&gt;Participant&lt;/strong&gt; class is my user entity class for the application.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The factory method that creates the data context is also pretty simple, although, it actually returns a wrapper around the data context. I described a little bit about the wrapper in my &lt;a href="http://farm-fresh-code.blogspot.com/2009/04/adventures-in-mocking-and-faking-linq.html"&gt;previous post&lt;/a&gt;. Because the "current user" depends on the context of the request and must make a call into the database to get a user entity to use in constructing the &lt;strong&gt;AuditUser&lt;/strong&gt; object, intject a copy of the wrapper into the a utility method use to extract the user's identity from the web context and retrieve the appropriate entity from the database. Here's the interface and base class that does most of the work.&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ICurrentUserUtility&lt;br /&gt;{&lt;br /&gt;    AuditUser GetAuditUser();&lt;br /&gt;    AuditUser GetAuditUser( IAuditableDataContextWrapper dataContext );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CurrentUserUtilityBase : ICurrentUserUtility&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; HttpContextBase WebContext;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;protected&lt;/span&gt; CurrentUserUtilityBase( HttpContextBase httpContext )&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.WebContext = httpContext ?? (HttpContext.Current != &lt;span class="kwrd"&gt;null&lt;/span&gt; ? &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpContextWrapper( HttpContext.Current ) : &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; AuditUser GetAuditUser();&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; AuditUser GetAuditUser( IAuditableDataContextWrapper dataContext )&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.WebContext != &lt;span class="kwrd"&gt;null&lt;/span&gt;&lt;br /&gt;            &amp;amp;&amp;amp; &lt;span class="kwrd"&gt;this&lt;/span&gt;.WebContext.User != &lt;span class="kwrd"&gt;null&lt;/span&gt;&lt;br /&gt;            &amp;amp;&amp;amp; &lt;span class="kwrd"&gt;this&lt;/span&gt;.WebContext.User.Identity != &lt;span class="kwrd"&gt;null&lt;/span&gt;&lt;br /&gt;            &amp;amp;&amp;amp; &lt;span class="kwrd"&gt;this&lt;/span&gt;.WebContext.User.Identity != WindowsIdentity.GetAnonymous())&lt;br /&gt;        {&lt;br /&gt;            var participant = dataContext.Table&amp;lt;Participant&amp;gt;()&lt;br /&gt;                                         .Where( p =&amp;gt; p.UserName == &lt;span class="kwrd"&gt;this&lt;/span&gt;.WebContext.User.Identity.Name )&lt;br /&gt;                                         .Select( p =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; AuditUser { ID = p.ParticipantID, Name = p.DisplayName } )&lt;br /&gt;                                         .SingleOrDefault();&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (participant != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; participant;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; AuditUser();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Each implementing class is associated with a particular data context type and thus I can have different utility classes for each data context. Note that because I'm implementing an interface I need not take advantage of the base class implementation and could have a utility that derived the user's identity from something other than the web context. This will be important later on when I have Windows services that perform updates on an automated basis so that I can inject a well-known id for auditing purposes. Here's the implementation for the data context that holds my user data.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CurrentUserUtility : CurrentUserUtilityBase&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; CurrentUserUtility()&lt;br /&gt;        : &lt;span class="kwrd"&gt;this&lt;/span&gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt; )&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; CurrentUserUtility( HttpContextBase httpContext )&lt;br /&gt;        : &lt;span class="kwrd"&gt;base&lt;/span&gt;( httpContext )&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; AuditUser GetAuditUser()&lt;br /&gt;    {&lt;br /&gt;        IDataContextFactory factory = &lt;span class="kwrd"&gt;new&lt;/span&gt; MasterEventDataContextFactory();&lt;br /&gt;        &lt;span class="kwrd"&gt;using&lt;/span&gt; (IAuditableDataContextWrapper wrapper = factory.GetDataContextWrapper())&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetAuditUser( wrapper );&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The wrapper class encapsulates the actual data context and simply delegates actions to it (the wrapper exists to make the data context testable, so it's not very complicated). The interesting bit is in the base data context. The SubmitChanges method constructs an &lt;strong&gt;AuditUtility&lt;/strong&gt; that does the actual auditing and uses the ChangeSet to know what it needs to audit. I want to audit both failure and success, so I catch any exceptions throw by the base SubmitChanges method and the presence or absence of the exception to determine whether the operation was successful. Once the changes have been made, methods on the AudityUtility are used to log the various types of changes from the ChangeSet.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SubmitChanges( System.Data.Linq.ConflictMode failureMode )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (AuditUtility auditor = &lt;span class="kwrd"&gt;new&lt;/span&gt; AuditUtility( &lt;span class="kwrd"&gt;this&lt;/span&gt;.CurrentUser ))&lt;br /&gt;    {&lt;br /&gt;        ChangeSet changes = &lt;span class="kwrd"&gt;this&lt;/span&gt;.GetChangeSet();&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;bool&lt;/span&gt; success = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;        Exception caughtException = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.SubmitChanges( failureMode );&lt;br /&gt;            success = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception e)&lt;br /&gt;        {&lt;br /&gt;            caughtException = e;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; deleted &lt;span class="kwrd"&gt;in&lt;/span&gt; changes.Deletes)&lt;br /&gt;        {&lt;br /&gt;            auditor.AuditEntity( deleted, ChangeAction.Delete, success );&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; inserted &lt;span class="kwrd"&gt;in&lt;/span&gt; changes.Inserts)&lt;br /&gt;        {&lt;br /&gt;            auditor.AuditEntity( inserted, ChangeAction.Insert, success );&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; updated &lt;span class="kwrd"&gt;in&lt;/span&gt; changes.Updates)&lt;br /&gt;        {&lt;br /&gt;            auditor.AuditEntity( updated, ChangeAction.Update, success );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (caughtException != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt; caughtException;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The AuditUtility&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Finally, we come to the class that actually creates the audit records, the AuditUtility. The AuditUtility works by using an AuditContextAttribute that decorates classes that need to be audited. It assumes that for each class so decorated, there is an [Audit.&lt;classname&gt;] table in the data context containing the audit entities. This audit class has the schema of the decorated class with the exception that the "id" parameter of the decorated class is not an auto-generated column and it has additional AuditID (primary key, identity column), ModifiedByID (int), ModifiedByName (varchar), ModifiedAt (datetime), Modification (varchar), and Success (bit) columns.&lt;br /&gt;&lt;br /&gt;The AuditContextAttribute specifies both that the class is able to be audited and specifies the type of the audit entity to use. It gets applied to a partial class implementation for the entities that need to be audited.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[AuditContext( AuditType = &lt;span class="kwrd"&gt;typeof&lt;/span&gt;( Audit_Event ) )]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Event&lt;br /&gt;{&lt;br /&gt;   ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AuditContextAttribute : Attribute&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Type AuditType { get; set; }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; tableProperty;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; TableProperty&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty( &lt;span class="kwrd"&gt;this&lt;/span&gt;.tableProperty ))&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;this&lt;/span&gt;.tableProperty = &lt;span class="kwrd"&gt;this&lt;/span&gt;.AuditType.Name;&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.tableProperty;&lt;br /&gt;        }&lt;br /&gt;        set { &lt;span class="kwrd"&gt;this&lt;/span&gt;.tableProperty = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The AuditUtility class has a couple of utility methods. GetAuditContext is used to extract the AuditContextAttribute from an entity, if it exists. CopyColumns is used to copy the common columns, as indicated by the ColumnAttribute on the decorated entity class, from the decorated entity to the audit entity. The latter uses reflection over the public properties of the two classes. Note that we skip any timestamp columns. The timestamp column on the audit entity reflects its version, not the version of the decorated entity.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; AuditContextAttribute GetAuditContext( &lt;span class="kwrd"&gt;object&lt;/span&gt; entity )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; entity.GetType().GetCustomAttributes( &lt;span class="kwrd"&gt;typeof&lt;/span&gt;( AuditContextAttribute ), &lt;span class="kwrd"&gt;false&lt;/span&gt; )&lt;br /&gt;                           .Cast&amp;lt;AuditContextAttribute&amp;gt;()&lt;br /&gt;                           .SingleOrDefault();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CopyColumns( &lt;span class="kwrd"&gt;object&lt;/span&gt; from, &lt;span class="kwrd"&gt;object&lt;/span&gt; to )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (from == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;"from"&lt;/span&gt; );&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (to == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;"to"&lt;/span&gt; );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    var fromType = from.GetType();&lt;br /&gt;    var toType = to.GetType();&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var fromProperty &lt;span class="kwrd"&gt;in&lt;/span&gt; fromType.GetProperties())&lt;br /&gt;    {&lt;br /&gt;        var attribute = fromProperty.GetCustomAttributes( &lt;span class="kwrd"&gt;typeof&lt;/span&gt;( ColumnAttribute ), &lt;span class="kwrd"&gt;false&lt;/span&gt; )&lt;br /&gt;                                    .Cast&amp;lt;ColumnAttribute&amp;gt;()&lt;br /&gt;                                    .FirstOrDefault();&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (attribute != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; !attribute.IsVersion)&lt;br /&gt;        {&lt;br /&gt;            var toProperty = toType.GetProperty( fromProperty.Name );&lt;br /&gt;            toProperty.SetValue( to, fromProperty.GetValue( from, &lt;span class="kwrd"&gt;null&lt;/span&gt; ), &lt;span class="kwrd"&gt;null&lt;/span&gt; );&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The AuditUtility class has two constructors. The first is used by the actual code, the second by my unit tests. The second allows me to inject a fake data context which is useful for testing. Notice that the AuditUtility implements IDisposable, however, when the data context is passed in, we don't need or want to dispose of the injected context. My IDisposable implementation checks the NeedDispose property before it attempts to dispose of the AuditDataContext (the context containing the audit entities). When used normally, this context will be created by the utility and disposed when the Dispose method is called. Also notice that we always inject the current user, an AuditUser object. This object is used to set the ModifiedByID and ModifiedByName columns in the audit entity.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; AuditUtility( AuditUser currentUser )&lt;br /&gt;    : &lt;span class="kwrd"&gt;this&lt;/span&gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt;, currentUser )&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; AuditUtility( IDataContextWrapper auditDataContext, AuditUser currentUser )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.CurrentUser = currentUser ?? &lt;span class="kwrd"&gt;new&lt;/span&gt; AuditUser();&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (auditDataContext == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.AuditDataContext = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataContextWrapper&amp;lt;MasterEventAuditingDataContext&amp;gt;();&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.NeedDispose = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.AuditDataContext = auditDataContext;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Lastly, we have the method that pulls everything together, AuditEntity. This method takes the entity to audit, the action that was attempted, and the status of the action. It creates an appropriate audit entity for the entity being audited and populates its values based on the entity parameter. Each audit entity is required to implement IAuditEntity. Basically, IAuditEntity defines a method that is used to set the auditing properties on the entity. It would be nice to be able to provide this in a base class, unfortunately the properties that you need to modify belong to each LINQ-to-SQL designer generated class so they can't be put in a base class. The easiest thing to do is to violate DRY and repeat the code in each audit entity.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="preproc"&gt;#region&lt;/span&gt; IAuditEntity Members&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetAuditProperties( &lt;span class="kwrd"&gt;int&lt;/span&gt; participantID, &lt;span class="kwrd"&gt;string&lt;/span&gt; participantName, ChangeAction action, &lt;span class="kwrd"&gt;bool&lt;/span&gt; success )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.ModifiedAt = DateTime.Now;&lt;br /&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.ModifiedByID = participantID;&lt;br /&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.ModifiedByName = participantName;&lt;br /&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.Modification = Enum.Format( &lt;span class="kwrd"&gt;typeof&lt;/span&gt;( ChangeAction ), action, &lt;span class="str"&gt;"g"&lt;/span&gt; );&lt;br /&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.Success = success;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;The method defined by IAuditEntity is used in conjuntion with the private helper methods to make the audit entity and store it using the AuditDataContext.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AuditEntity( &lt;span class="kwrd"&gt;object&lt;/span&gt; entity, ChangeAction action, &lt;span class="kwrd"&gt;bool&lt;/span&gt; success )&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (entity == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException( &lt;span class="str"&gt;"entity"&lt;/span&gt; );&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (action != ChangeAction.None) &lt;span class="rem"&gt;// only audit inserts, deletes, and updates&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        AuditContextAttribute auditContext = GetAuditContext( entity );&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (auditContext != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            var auditTable = &lt;span class="kwrd"&gt;this&lt;/span&gt;.AuditDataContext.Table( auditContext.AuditType );&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (auditTable != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;                {&lt;br /&gt;                    IAuditEntity auditEntity = Activator.CreateInstance( auditContext.AuditType ) &lt;span class="kwrd"&gt;as&lt;/span&gt; IAuditEntity;&lt;br /&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (auditEntity != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;                    {&lt;br /&gt;                        CopyColumns( entity, auditEntity );&lt;br /&gt;                        auditEntity.SetAuditProperties( &lt;span class="kwrd"&gt;this&lt;/span&gt;.CurrentUser.ID, &lt;span class="kwrd"&gt;this&lt;/span&gt;.CurrentUser.Name, action, success );&lt;br /&gt;                        auditTable.InsertOnSubmit( auditEntity );&lt;br /&gt;                        &lt;span class="kwrd"&gt;this&lt;/span&gt;.AuditDataContext.SubmitChanges();&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                &lt;span class="kwrd"&gt;catch&lt;/span&gt; { }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;strong&gt;Alternative IAuditEntity (Updated)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As an alternative you might want to define the audit properties (ModifiedAt, ...) on the IAuditEntity interface and define the SetAuditProperties() method as an extension on IAuditEntity. This way you can define the method just once -- as long as you want it to work the same way for all audited entities. All of your additional audit properties will need to be the same for all audit entities. In practice I have found this to be the case, however, and I now define set up my auditing this way.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IAuditEntity&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;int&lt;/span&gt; ModifiedByID { get; set; }&lt;br /&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; ModifiedByName { get; set; }&lt;br /&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; Modification { get; set; }&lt;br /&gt;    &lt;span class="kwrd"&gt;bool&lt;/span&gt; Success { get; set; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AuditEntityExtensions&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetAuditProperties( &lt;span class="kwrd"&gt;this&lt;/span&gt; IAuditEntity source, &lt;span class="kwrd"&gt;int&lt;/span&gt; modifiedByID, &lt;span class="kwrd"&gt;string&lt;/span&gt; modifiedByName, ChangeAction action, &lt;span class="kwrd"&gt;bool&lt;/span&gt; success )&lt;br /&gt;    {&lt;br /&gt;        source.ModifiedByID = modifiedByID;&lt;br /&gt;        source.ModifiedByName = modifiedByName;&lt;br /&gt;        source.Modification = Enum.Format( &lt;span class="kwrd"&gt;typeof&lt;/span&gt;( ChangeAction ), action, &lt;span class="str"&gt;"g"&lt;/span&gt; );&lt;br /&gt;        source.Success = success;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Some Final Notes&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In order to make sure that the audit records stay intact, as a final measure, I add triggers to each of the audit tables that run on UPDATE and DELETE. These triggers simply rollback the transaction. This prevents my application and any users from removing or changing the audit records accidentally. For my integration tests, I do disable the triggers so that the test data can be removed from my test database instance.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'd be interested in hearing your solutions to the same or similar problems. Eventually, I may need to add select/read auditing to the application as well. Unfortunately, I haven't been able to think a way to do this except by implementing the OnLoad partial method in each of my entity classes. To do insert/update/delete auditing the only change to my entities is to decorate them with the AuditContextAttribute. Doing select/read auditing will require more intrusive methods I'm afraid.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-7992583130630239111?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/FMWdJfCzM7LTSbSUN8mFwDem67U/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FMWdJfCzM7LTSbSUN8mFwDem67U/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/FMWdJfCzM7LTSbSUN8mFwDem67U/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/FMWdJfCzM7LTSbSUN8mFwDem67U/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/aqGav30kQIY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/7992583130630239111/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2009/05/auditing-inserts-and-updates-using-linq.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/7992583130630239111?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/7992583130630239111?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/aqGav30kQIY/auditing-inserts-and-updates-using-linq.html" title="Auditing inserts and updates using LINQ to SQL" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2009/05/auditing-inserts-and-updates-using-linq.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQFQHc4fCp7ImA9WxJTGEk.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-8820182620582041265</id><published>2009-04-26T14:34:00.011-05:00</published><updated>2009-04-27T10:48:31.934-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-27T10:48:31.934-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="LINQ LINQtoSQL DataContext .NET mocking" /><title>Adventures in mocking and faking the LINQ to SQL data context</title><content type="html">Andrew Tokeley has an excellent &lt;a href="http://andrewtokeley.net/archive/2008/07/06/mocking-linq-to-sql-datacontext.aspx"&gt;blog post&lt;/a&gt; on mocking the LINQ to SQL data context, as implemented by his friend Stuart Clark. I've made heavy use of the code he posted in developing my own data context wrapper. In the process of testing my ASP.NET MVC application, though, I've found that a few enhancements can make this concept even more effective.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold"&gt;Faking Data&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Clark's DataContextWrapper makes it possible to mock the LINQ to SQL data context. This is a tremendous advantage when developing unit tests that make use of the data context. Andrew's implementation is, however, more of a fake implementation rather than a mock. A fake implementation implements the same interface, but uses a simpler mechanism to accomplish the same tasks. A mock implementation, on the other hand, does not attempt to actually perform the same actions, but simply &lt;em&gt;pretends&lt;/em&gt; to. Another difference is that the mock implementation typically tracks calls to its methods so that they can be verified, whereas a fake implementation is typically a simple stand-in for the actual implementation.&lt;br /&gt;&lt;br /&gt;I decided early on, though, that I wanted to fake the data in addition to mocking the data context so this was actually ideal for me. Because so much of my application interacts with the database, I wanted to be able to use a DataContextWrapper that acted as much like the real database as possible. My feeling is that using a fake database would make it conceptually easier to write tests as if I were directly interacting with the database without having to consider all of the interactions that would go on under the hood. I suspect that there are many who would disagree with me, but I find that I work better with this model. One advantage is that I can simply reuse the fake data over and over again, yet when necessary I can still mock the DataContextWrapper, for example when I need one of its methods to throw an exception.  When faking data I found that the fake implementation of the DataContextWrapper needed a few tweaks to make it really usable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold"&gt;Inserting Data&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The fake DataContextWrapper, as implemented by Stuart, adds the entity in the InsertOnSubmit method. However, the real LINQ To SQL data context doesn't insert the data into the database until SubmitChanges is called. Since I wanted my fake context to work as much like the real context as possible, I decided to implement a mechanism to keep track of the inserted data until SubmitChanges is called rather than add the entity to the fake table implementation during InsertOnSubmit.  Likewise, it doesn't make much sense to use a relational database unless your data is related. Nearly all applications have entities that are related to each other. LINQ to SQL implements this using EntityRef (for one-to-one relationships) and EntitySets (for one-to-many relationships). The natural way to add related data in LINQ to SQL is to add it to the EntityRef or EntitySet representing the association.&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;   &lt;span class="kwrd"&gt;var&lt;/span&gt; context = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataContextWrapper&amp;amp;lt;MyDataContext&amp;amp;gt;();&lt;br /&gt;   &lt;span class="kwrd"&gt;var&lt;/span&gt; masterEntity = &lt;span class="kwrd"&gt;new&lt;/span&gt; MasterEntity { ... };&lt;br /&gt;   masterEntity.RelatedEntities.Add( &lt;span class="kwrd"&gt;new&lt;/span&gt; RelatedEntity { ... } );&lt;br /&gt;   context.InsertOnSubmit( masterEntity );&lt;br /&gt;   context.SubmitChanges();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Without some special consideration, though, a mock DataContextWrapper doesn't support adding new related entities this way. I found myself writing code like this, instead, to pass my tests.&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;   &lt;span class="kwrd"&gt;var&lt;/span&gt; context = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataContextWrapper&amp;amp;lt;MyDataContext&amp;amp;gt;();&lt;br /&gt;   &lt;span class="kwrd"&gt;var&lt;/span&gt; masterEntity = &lt;span class="kwrd"&gt;new&lt;/span&gt; MasterEntity { ... };&lt;br /&gt;   &lt;span class="kwrd"&gt;var&lt;/span&gt; relatedEntity = &lt;span class="kwrd"&gt;new&lt;/span&gt; RelatedEntity&lt;br /&gt;   {&lt;br /&gt;      MasterEntity = masterEntity,&lt;br /&gt;      ...&lt;br /&gt;   }&lt;br /&gt;   masterEntity.RelatedEntities.Add( relatedEntity );&lt;br /&gt;   context.InsertOnSubmit( masterEntity );&lt;br /&gt;   context.InsertOnSubmit( relatedEntity );&lt;br /&gt;   context.SubmitChanges();&lt;/pre&gt;&lt;span style="font-style: italic"&gt;&lt;br /&gt;  &lt;blockquote&gt;Note the difference between an actual context and the wrapper's implementation of InsertOnSubmit. I highly prefer the wrapper's implementation.&lt;/blockquote&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Clearly, to get the code I wanted, I needed to make my fake DataContextWrapper be able to detect when a newly inserted entity has related data and insert it as well. This would enable me to pass my tests without having to write extra code for the fake implementation. In order to do this I search the related entities for each of the entities stored in the fake tables for entities that are not in the appropriate table. These entities get added to the set of entities that need to be inserted into the fake implementation during the insert phase of SubmitChanges.&lt;br /&gt;&lt;br /&gt;To do this I need a few helper methods for my FakeDataContextWrapper.  These methods will iterate through an object's referenced objects and, if they aren't already in the fake data, schedule them to be added during the insert phase of SubmitChanges.&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddReferencedObjects( &lt;span class="kwrd"&gt;object&lt;/span&gt; entity )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; set &lt;span class="kwrd"&gt;in&lt;/span&gt; GetEntitySets( entity ))&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; item &lt;span class="kwrd"&gt;in&lt;/span&gt; set)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;this&lt;/span&gt;.mockDatabase.Tables[item.GetType()].Contains( item ))&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;this&lt;/span&gt;.Added.Add( item );&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; reference &lt;span class="kwrd"&gt;in&lt;/span&gt; GetEntityRefs( entity ))&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;this&lt;/span&gt;.mockDatabase.Tables[reference.GetType()].Contains( reference ))&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Added.Add( reference );&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; IEnumerable&amp;lt;IEnumerable&amp;gt; GetEntitySets( &lt;span class="kwrd"&gt;object&lt;/span&gt; entity )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; property &lt;span class="kwrd"&gt;in&lt;/span&gt; entity.GetType().GetProperties())&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (property.PropertyType.Name.Contains( &lt;span class="str"&gt;"EntitySet"&lt;/span&gt; ))&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;var&lt;/span&gt; value = property.GetValue( entity, &lt;span class="kwrd"&gt;null&lt;/span&gt; );&lt;br /&gt;            &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; value &lt;span class="kwrd"&gt;as&lt;/span&gt; IEnumerable;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; IEnumerable&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; GetEntityRefs( &lt;span class="kwrd"&gt;object&lt;/span&gt; entity )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; property &lt;span class="kwrd"&gt;in&lt;/span&gt; entity.GetType().GetProperties())&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (property.PropertyType.Name.Contains( &lt;span class="str"&gt;"EntityRef"&lt;/span&gt; ))&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; property.GetValue( entity, &lt;span class="kwrd"&gt;null&lt;/span&gt; );&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Then we add a few lines of code to our SubmitChanges implementation to take care of actually updating the fake data when entities are added/updated/deleted.  Notice how we make sure that all of the new objects to be inserted get added before the insert phase.  The phases run, in order, insert, delete, update -- though one could probably  switch the first two. As of yet, though, we don't have any need to address updates.&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;var directlyAdded = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;( &lt;span class="kwrd"&gt;this&lt;/span&gt;.Added );&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; obj &lt;span class="kwrd"&gt;in&lt;/span&gt; directlyAdded)&lt;br /&gt;{&lt;br /&gt;    AddReferencedObjects( obj );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; list &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.mockDatabase.Tables.Values)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var obj &lt;span class="kwrd"&gt;in&lt;/span&gt; list)&lt;br /&gt;    {&lt;br /&gt;        AddReferencedObjects( obj );&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; obj &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.Added)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.mockDatabase.Tables[obj.GetType()].Add( obj );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;this&lt;/span&gt;.Added.Clear();&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; obj &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.Deleted)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;this&lt;/span&gt;.mockDatabase.Tables[obj.GetType()].Remove( obj );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;this&lt;/span&gt;.Deleted.Clear();&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold"&gt;Validation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I decided to use Scott Guthrie's &lt;a href="http://weblogs.asp.net/scottgu/archive/2008/09/02/asp-net-mvc-preview-5-and-form-posting-scenarios.aspx"&gt;validation techniques&lt;/a&gt; on LINQ to SQL entities. To this end, I have a IValidatedEntity interface that my entities implement that defines a GetRuleViolations() method where my business rules are validated. In addition, I implement the OnValidate partial method, which calls GetRuleViolations to ensure that my entities are valid prior to saving them to the database. Unfortunately Andrew's mock context doesn't address the validation requirements. I decided to implement validation in the SubmitChanges method so that my fake DataContextWrapper would also perform validation just like the real context.&lt;br /&gt;&lt;br /&gt;One issue that I ran into, however, is that the real data context tracks the changes that are made to existing entities so that it knows which ones need to be updated. It only updates those entities that have changed. Rather than add this complexity to the fake implementation, I decided instead to simply validate all entities as if they were being updated during the update phase of SubmitChanges. This incurs a little extra processing overhead for each unit test that touches code that does a SubmitChanges but the advantage is that the fake implementation is simpler.&lt;br /&gt;&lt;br /&gt;I use reflection to find the OnValidate method for each entity and invoke it with the proper ChangeAction. Finally, in order to get the actual exception, instead of the exception thrown by the reflection calls, I wrap the entire SubmitChanges code in a try-catch block and throw the InnerException on errors.&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SubmitChanges( ConflictMode failureMode )&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; directlyAdded = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;( &lt;span class="kwrd"&gt;this&lt;/span&gt;.Added );&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; obj &lt;span class="kwrd"&gt;in&lt;/span&gt; directlyAdded)&lt;br /&gt;        {&lt;br /&gt;            AddReferencedObjects( obj );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; list &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.mockDatabase.Tables.Values)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; obj &lt;span class="kwrd"&gt;in&lt;/span&gt; list)&lt;br /&gt;            {&lt;br /&gt;                AddReferencedObjects( obj );&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; obj &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.Added)&lt;br /&gt;        {&lt;br /&gt;            MethodInfo validator = obj.GetType().GetMethod( &lt;span class="str"&gt;"OnValidate"&lt;/span&gt;,&lt;br /&gt;                                                            BindingFlags.Instance | BindingFlags.NonPublic );&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (validator != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                validator.Invoke( obj, &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;[] { ChangeAction.Insert } );&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.mockDatabase.Tables[obj.GetType()].Add( obj );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Added.Clear();&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; obj &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.Deleted)&lt;br /&gt;        {&lt;br /&gt;            MethodInfo validator = obj.GetType().GetMethod( &lt;span class="str"&gt;"OnValidate"&lt;/span&gt;,&lt;br /&gt;                                                            BindingFlags.Instance | BindingFlags.NonPublic );&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (validator != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                validator.Invoke( obj, &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;[] { ChangeAction.Delete } );&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.mockDatabase.Tables[obj.GetType()].Remove( obj );&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Deleted.Clear();&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (KeyValuePair&amp;lt;Type, IList&amp;gt; tablePair &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.mockDatabase.Tables)&lt;br /&gt;        {&lt;br /&gt;            MethodInfo validator = tablePair.Key.GetMethod( &lt;span class="str"&gt;"OnValidate"&lt;/span&gt;,&lt;br /&gt;                                                            BindingFlags.Instance | BindingFlags.NonPublic );&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (validator != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;var&lt;/span&gt; obj &lt;span class="kwrd"&gt;in&lt;/span&gt; tablePair.Value)&lt;br /&gt;                {&lt;br /&gt;                    validator.Invoke( obj, &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;[] { ChangeAction.Update } );&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;catch&lt;/span&gt; (TargetInvocationException e)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; e.InnerException;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;I've made a few other tweaks to the entire set of classes that support mocking the data context.  I'll write about those later when I tackle automating auditing for LINQ to SQL.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-8820182620582041265?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/OQUjdDI7Ml1c3zhNTZmVwslsxIc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OQUjdDI7Ml1c3zhNTZmVwslsxIc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/OQUjdDI7Ml1c3zhNTZmVwslsxIc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OQUjdDI7Ml1c3zhNTZmVwslsxIc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/_3lMqlHnvdg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/8820182620582041265/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2009/04/adventures-in-mocking-and-faking-linq.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/8820182620582041265?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/8820182620582041265?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/_3lMqlHnvdg/adventures-in-mocking-and-faking-linq.html" title="Adventures in mocking and faking the LINQ to SQL data context" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2009/04/adventures-in-mocking-and-faking-linq.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMMSX85cSp7ImA9WxJTFU0.&quot;"><id>tag:blogger.com,1999:blog-9200551703084243537.post-1606439112636550283</id><published>2009-04-23T11:29:00.018-05:00</published><updated>2009-04-23T12:41:28.129-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-23T12:41:28.129-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="jQuery Cycle slideshow mvc asp.net" /><title>jQuery Cycle: Adding player controls to a slide show</title><content type="html">I'm working on a web site for a local student organization, &lt;a href="http://osl.iowa.uiowa.edu/dancemarathon"&gt;Dance Marathon&lt;/a&gt;, to help them track people who participant or donate to their fundraising activities. On the front page of the web site I have a slideshow that rotates through a series of photos from previous events. I'm using the jQuery &lt;a href="http://malsup.com/jquery/cycle/"&gt;Cycle plugin &lt;/a&gt;for this. I wanted to add some player controls so that the end user can control the operation of the slideshow.&lt;br /&gt;&lt;br /&gt;The site uses the &lt;a href="http://www.famfamfam.com/archive/silk-icons-thats-your-lot/"&gt;FamFamFam Silk&lt;/a&gt; icon set by Mark James, so I decided to use the control icons for my player controls. These icons are released and used under a Creative Commons Attribution 3.0 license. I highly recommend these icons.&lt;br /&gt;&lt;br /&gt;I wanted to support the full range of player controls: Goto First Slide, Previous Slide, Stop Show, Play Show, Next Slide, and Goto Last Slide. Fortunately, the Cycle plugin allows me to pause and resume the slide show as well as choose a specific slide to show. Turns out that this is really all that is necessary to support those features. I also appreciate that the Silk icons include both blue and gray versions of the control icons. This allows me to give the user some visual feedback on which control is currently selected. By default the play control will be the active control on page load.&lt;br /&gt;&lt;br /&gt;The Cycle plugin is very easy to set up. Simply create a DIV and assign it a class (or id). I used:&lt;br /&gt;&lt;br /&gt;&lt;div style="FONT-SIZE: 85%; FONT-FAMILY: courier new"&gt;&lt;br /&gt;&amp;lt;div class="pics"&amp;gt;&amp;lt;div&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Next generate the set of images that you want to include in your slideshow. I'm using ASP.NET MVC so I pass down an IEnumerable&amp;lt;ImageDescriptor&amp;gt;, where ImageDescriptor is a class containing Url and AltText properties for the images to include. This enumeration is produced in my controller by reading a specific subdirectory of my images directory.&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;&lt;pre&gt;public ActionResult Index()&lt;br /&gt;{&lt;br /&gt;    ViewData["Title"] = "Home Page";&lt;br /&gt;    ViewData["Message"] = this.LocalStrings.WelcomeMessage;&lt;br /&gt;&lt;br /&gt;    List&lt;ImageDescriptor&gt; images = new List&lt;ImageDescriptor&gt;();&lt;br /&gt;    string homeImagePath = Server.MapPath( "~/Content/images/home-images" );&lt;br /&gt;    foreach (string imageFile in Directory.GetFiles( homeImagePath ))&lt;br /&gt;    {&lt;br /&gt;        string fileName = Path.GetFileName( imageFile );&lt;br /&gt;        string url = Url.Content( "~/Content/images/home-images/" + fileName );&lt;br /&gt;        images.Add( new ImageDescriptor { Url = url } );&lt;br /&gt;    }&lt;br /&gt;    return View( images  );&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Because my images are of different sizes, I decided to place the controls above the slideshow. The cycle plugin, by default, reserves enough space, by setting fixed width/height on the DIV, to show all of the slides. Since some of my images are oriented vertically and others horizontally, placing the controls below the slideshow would make it appear too far below the horizontal images. I'd prefer it below, so I'm still working on making this work for both orientations. If you have any ideas, let me know.&lt;br /&gt;&lt;br /&gt;First, the view includes the player controls DIV so that they appear above the slideshow.&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;div id="controls" class="hidden"&amp;gt;&lt;br /&gt;    &amp;lt;img id="startButton"&lt;br /&gt;         src='&amp;lt;%= Url.Content( "~/Content/images/icons/control_start.png" ) %&amp;gt;'&lt;br /&gt;         alt="Beginning"&lt;br /&gt;         title="Beginning" /&amp;gt;&lt;br /&gt;    &amp;lt;img id="prevButton"&lt;br /&gt;         src='&amp;lt;%= Url.Content( "~/Content/images/icons/control_rewind.png" ) %&amp;gt;'&lt;br /&gt;         alt="Previous"&lt;br /&gt;         title="Previous" /&amp;gt;&lt;br /&gt;    &amp;lt;img id="stopButton"&lt;br /&gt;         src='&amp;lt;%= Url.Content( "~/Content/images/icons/control_stop.png" ) %&amp;gt;'&lt;br /&gt;         alt="Stop"&lt;br /&gt;         title="Stop" /&amp;gt;&lt;br /&gt;    &amp;lt;img id="playButton" src='&amp;lt;%= Url.Content( "~/Content/images/icons/control_play_blue.png" ) %&amp;gt;'&lt;br /&gt;         alt="Play"&lt;br /&gt;         title="Play" /&amp;gt;&lt;br /&gt;    &amp;lt;img id="nextButton"&lt;br /&gt;         src='&amp;lt;%= Url.Content( "~/Content/images/icons/control_fastforward.png" ) %&amp;gt;'&lt;br /&gt;         alt="Next"&lt;br /&gt;         title="Next" /&amp;gt;&lt;br /&gt;    &amp;lt;img id="endButton"&lt;br /&gt;         src='&amp;lt;%= Url.Content( "~/Content/images/icons/control_end.png" ) %&amp;gt;'&lt;br /&gt;         alt="End"&lt;br /&gt;         title="End" /&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Next I include the code to generate the gallery. This has been simplified from the actual code. Note that I make all but the first image hidden, as well as the player controls, when the page first loads in case Javascript is not enabled. This helps the page to downgrade gracefully if the user won't be able to use the gallery.  Note that Image is my own HtmlHelper extension, although, I think that there is a similar one in MvcFutures.  ParameterDictionary is also my own class, but it functions similar to RouteValueDictionary so you could use that instead.&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;div class='pics'&amp;gt;&lt;br /&gt;    &amp;lt;% var klass = "";&lt;br /&gt;       foreach (ImageDescriptor image in Model)&lt;br /&gt;       {&lt;br /&gt;           var htmlOptions = image.HtmlOptions ?? new ParameterDictionary();&lt;br /&gt;           var url = Url.Content( image.Url );&lt;br /&gt;     %&amp;gt;&lt;br /&gt;    &amp;lt;%= Html.Image( url,&lt;br /&gt;                    image.AltText,&lt;br /&gt;                    htmlOptions.Merge( new { @class = klass } ))%&amp;gt&lt;br /&gt;    &amp;lt;%      &lt;br /&gt;            klass = "hidden";&lt;br /&gt;        }&lt;br /&gt;     %&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Finally, we come to the magic that makes it all work -- the Javascript code. We need to include jQuery and the Cycle plugin.  These go in the header for the view.  Note That I'm also using an HtmlHelper extension here to generate the script tags.&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;%= Html.Javascript( Url.Content( "~/Scripts/jquery-1.3.2.min.js" ) ) %&amp;gt;&lt;br /&gt;&amp;lt;%= Html.Javascript( Url.Content( "~/Scripts/cycle/jquery.cycle.all.min.js" ) ) %&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Remember that we want the controls positioned over the center of whatever image is displayed.  The gallery div will be sized to fit the largest image, but the images may be of different sizes.  I played with a number of different options, but finally decided to simply set the left margin of the player controls based on the image size and the size of the controls themselves.  This is handled dynamically using the following function.  This function will be set as the &lt;em&gt;before&lt;/em&gt; callback on the Cycle plugin.&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;&lt;pre&gt;function positionControls( curr, next, options, forward )&lt;br /&gt;{&lt;br /&gt;   if (controlWidth == 0)&lt;br /&gt;   {&lt;br /&gt;        $('#controls &gt; img').each( function() {&lt;br /&gt;            controlWidth = controlWidth + $(this).width();&lt;br /&gt;        });&lt;br /&gt;   }&lt;br /&gt;   var nextWidth = $(next).width();&lt;br /&gt;   var leftMargin = (nextWidth - controlWidth) / 2;&lt;br /&gt;   if (leftMargin &lt; 0) leftMargin = 0;&lt;br /&gt;   $('#controls').css( 'marginLeft', leftMargin + 'px' );&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Also, remember that we want to have the clicked control highlighted as a visual indicator to the user.  The easiest way to do this is to have the click handler for each of the controls set the image urls based on which control is clicked using the following function.&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;&lt;pre&gt;function iconSelected(img)&lt;br /&gt;{&lt;br /&gt;   $('#controls &gt; img').each( function() {&lt;br /&gt;       this.src = this.src.replace( /_blue/, '' );&lt;br /&gt;   });&lt;br /&gt;   img.src = img.src.replace( /.png$/,'_blue.png' );&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Now to tie it all together, we remove the &lt;em&gt;hidden&lt;/em&gt; class from all the elements, set up the Cycle plugin, and install the click handlers for the controls.  Note that the Cycle plugin has native support for &lt;em&gt;Previous&lt;/em&gt; and &lt;em&gt;Next&lt;/em&gt; slide options, though it doesn't pause the show after advancing.  We'll need to set up the other behaviors, however, and add some additional behavior to the &lt;em&gt;Previous&lt;/em&gt; and &lt;em&gt;Next&lt;/em&gt; controls.&lt;br /&gt;&lt;br /&gt;I'm going to use the default &lt;em&gt;fade&lt;/em&gt; effect for the Cycle plugin and set it up to use &lt;em&gt;random&lt;/em&gt; display of the images.  I'll precalculate the position of the last image in the set to use for the Goto Last Slide control.  All controls, except, Play, will &lt;em&gt;pause&lt;/em&gt; the slideshow after performing their respective behavior.  Play simply &lt;em&gt;resumes&lt;/em&gt; the show when clicked.&lt;br /&gt;&lt;span style="font-family:courier new;font-size:85%;"&gt;&lt;br /&gt;&lt;pre&gt;    var controlWidth = 0;&lt;br /&gt;    var lastImage = 0;&lt;br /&gt;    $(document).ready( function() {&lt;br /&gt;        $('#controls').removeClass('hidden');&lt;br /&gt;        &lt;br /&gt;        var gallery = $('.pics');&lt;br /&gt;        gallery.cycle( { fx: 'fade',&lt;br /&gt;                         random: true,&lt;br /&gt;                         prev: '#prevButton',&lt;br /&gt;                         next: '#nextButton', &lt;br /&gt;                         before: positionControls  } );&lt;br /&gt;&lt;br /&gt;        gallery.children('img').removeClass('hidden');&lt;br /&gt;&lt;br /&gt;        lastImage = gallery.children('img').size() - 1;&lt;br /&gt;        if (lastImage &lt; 0) lastImage = 0;&lt;br /&gt;&lt;br /&gt;        $('#stopButton').click( function() {&lt;br /&gt;            gallery.cycle('pause');&lt;br /&gt;            iconSelected(this);&lt;br /&gt;        });&lt;br /&gt;        $('#playButton').click( function() {&lt;br /&gt;            gallery.cycle('resume',true);&lt;br /&gt;            iconSelected(this);&lt;br /&gt;        });&lt;br /&gt;        $('#prevButton,#nextButton').click( function() {&lt;br /&gt;            gallery.cycle('pause');&lt;br /&gt;            iconSelected(this);   &lt;br /&gt;        });&lt;br /&gt;        $('#startButton').click( function() {&lt;br /&gt;            gallery.cycle('pause');&lt;br /&gt;            gallery.cycle(0);&lt;br /&gt;            iconSelected(this);&lt;br /&gt;        });&lt;br /&gt;        $('#endButton').click( function() {&lt;br /&gt;            gallery.cycle('pause');&lt;br /&gt;            gallery.cycle(lastImage);&lt;br /&gt;            iconSelected(this);&lt;br /&gt;        });&lt;br /&gt;    });&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;I'm pretty pleased with how this turned out, though I want to keep exploring options for position the player controls.  It is disconcerting when they jump around as the image sizes change.  Floating them left, though, looks odd to me.  I'd love to hear your idea.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9200551703084243537-1606439112636550283?l=farm-fresh-code.blogspot.com' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/UzZOJmy0dCV90Rj-JzmFST4j-Ec/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UzZOJmy0dCV90Rj-JzmFST4j-Ec/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/UzZOJmy0dCV90Rj-JzmFST4j-Ec/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/UzZOJmy0dCV90Rj-JzmFST4j-Ec/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/FarmFreshCode/~4/6pIf-OuVZhE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://farm-fresh-code.blogspot.com/feeds/1606439112636550283/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://farm-fresh-code.blogspot.com/2009/04/jquery-cycle-adding-player-controls-to.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/1606439112636550283?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/9200551703084243537/posts/default/1606439112636550283?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FarmFreshCode/~3/6pIf-OuVZhE/jquery-cycle-adding-player-controls-to.html" title="jQuery Cycle: Adding player controls to a slide show" /><author><name>tvanfosson</name><uri>http://www.blogger.com/profile/04716379255368704897</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://1.bp.blogspot.com/-GmwpU_XQIQQ/TxgZ1IG-O9I/AAAAAAAAAH0/HUGBQE5T3AY/s220/workpic.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://farm-fresh-code.blogspot.com/2009/04/jquery-cycle-adding-player-controls-to.html</feedburner:origLink></entry></feed>

