tag:blogger.com,1999:blog-24308569499341178812024-03-13T12:48:30.131-05:00Technical DifficultiesC#? Why, I can barely see at all!Anonymoushttp://www.blogger.com/profile/00751154354014174645noreply@blogger.comBlogger33125tag:blogger.com,1999:blog-2430856949934117881.post-29204793072503188442014-07-26T11:35:00.001-05:002014-07-26T11:35:34.867-05:00Easier object matching in TDD with SpecsFor<p>I love using <a href="http://specsfor.com/">SpecsFor</a> to write tests. However, there’s a function in the library called ShouldLookLikePartial that works on anonymous objects, that has always left a little to be desired. Recently I decided to fix it, and with the next release of SpecsFor, my change will be in! This involved me diving into some expression parsing, which was much easier than I thought it would be. I also thought it was pretty interesting, so I decided to share what I dug up. Read on if you’re interested! </p> <h1>The Problem</h1> <p>One common thing you do when testing is assert that your result (say a view model) looks like you expect. But lets say your result involves a new domain object being created and saved. You want to verify its properties are set correctly, but there’s probably some fields you don’t care about (like an ID).</p> <p>Originally, you would use the ShouldLookLikePartial method in SpecsFor. </p> <pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">[<span class="User Types" style="color: #4ec9b0">Test</span>]<br /><span class="keyword" style="color: #569cd6">public</span> <span class="keyword" style="color: #569cd6">void</span> <span class="identifier">then_only_certain_properties_are_set</span>()<br />{<br />    <span class="identifier">SUT</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">ShouldLookLikePartial</span>(<span class="keyword" style="color: #569cd6">new</span> { <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"blah"</span> });<br />}</pre>
<p>This accepts an anonymous object, so it only compares what you’ve defined. However, you’ve lost one of the big advantages of a statically typed language. Your tests are no longer refactor friendly. We want our feedback cycle to tell us ASAP when something is wrong. If you renamed a field, your code would still build. It wouldn’t fail until you ran your tests. With tools like ReSharper, renaming a field is typically very safe, but we’ve just made it a little more brittle. </p>
<h1>The Solution</h1>
<p>I worked with <a href="http://trycatchfail.com/blog/">Matt Honeycutt</a> (owner and creator of <a href="http://specsfor.com/">SpecsFor</a>) to come up with the syntax we wanted - which is pretty much “works just like the old Partial version, except you declare your type now”. So that’s what I did! </p>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">[<span class="User Types" style="color: #4ec9b0">Test</span>]<br /><span class="keyword" style="color: #569cd6">public</span> <span class="keyword" style="color: #569cd6">void</span> <span class="identifier">then_only_certain_properties_are_set</span>()<br />{<br />    <span class="identifier">SUT</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">ShouldLookLike</span>(() <span class="operator" style="color: #b4b4b4">=></span> <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span> { <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"blah"</span> });<br />}</pre>
<h1> </h1>
<p>It works with more than just a simple object though. We can even test nested complex objects:</p>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="identifier">SUT</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">ShouldLookLike</span>(() <span class="operator" style="color: #b4b4b4">=></span> <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span></pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="User Types" style="color: #4ec9b0"></span>             {</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">                 <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"Test"</span>,</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">                 <span class="identifier">Awesomeness</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="number" style="color: #b5cea8">11</span>,</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">                 <span class="identifier">Nested</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span></pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="User Types" style="color: #4ec9b0"></span>                 {</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">                     <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"nested 1 test"</span>,</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">                     <span class="identifier">Nested</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span></pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="User Types" style="color: #4ec9b0"></span>                     {</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">                         <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"ULTRA NEST COMBO KILL"</span>,<br />                        <span class="identifier">Awesomeness</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="number" style="color: #b5cea8">69</span> <span class="comment" style="color: #57a64a">//thanks, Bill & Ted, real mature.</span></pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="comment" style="color: #57a64a"></span>                     }</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">                 }</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">             })</pre>
<p>As well as IEnumerables:</p>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="identifier">list</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">ShouldLookLike</span>(() <span class="operator" style="color: #b4b4b4">=></span> <span class="keyword" style="color: #569cd6">new</span>[]<br />                {<br />                    <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span><br />                        {<br />                            <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"one"</span>,<br />                            <span class="identifier">Awesomeness</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="number" style="color: #b5cea8">1</span><br />                        },<br />                    <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span><br />                        {<br />                            <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"two"</span>,<br />                            <span class="identifier">Awesomeness</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="number" style="color: #b5cea8">2</span><br />                        }<br />                })</pre>
<p>And you can of course mix and match all that:</p>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="identifier">SUT</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">ShouldLookLike</span>(() <span class="operator" style="color: #b4b4b4">=></span> <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span><br />            {<br />                <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"Test"</span>,<br />                <span class="identifier">Awesomeness</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="number" style="color: #b5cea8">11</span>,<br />                <span class="identifier">Nested</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span><br />                {<br />                    <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"nested 1 test"</span>,<br />                    <span class="identifier">NestedArray</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="keyword" style="color: #569cd6">new</span> []<br />                        {<br />                            <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span><br />                                {<br />                                    <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"level 1 nested 1"</span>,<br />                                    <span class="identifier">Awesomeness</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="number" style="color: #b5cea8">11</span><br />                                },<br />                            <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span><br />                                {<br />                                    <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"level 1 nested 2"</span>,<br />                                    <span class="identifier">NestedArray</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="keyword" style="color: #569cd6">new</span> []<br />                                        {<br />                                            <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span><br />                                                {<br />                                                    <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"lets get nested son"</span><br />                                                }<br />                                        }<br />                                }<br />                        },<br />                    <span class="identifier">Nested</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span><br />                    {<br />                        <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"ULTRA NEST COMBO KILL"</span>,<br />                        <span class="identifier">Awesomeness</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="number" style="color: #b5cea8">69</span>, <span class="comment" style="color: #57a64a">//thanks, Bill & Ted, real mature.</span><br />                        <span class="identifier">NestedArray</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="keyword" style="color: #569cd6">new</span> []<br />                            {<br />                                <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span><br />                                    {<br />                                        <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"nested array 1"</span>,<br />                                    },<br />                                <span class="keyword" style="color: #569cd6">new</span> <span class="User Types" style="color: #4ec9b0">TestObject</span><br />                                    {<br />                                        <span class="identifier">Name</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="string" style="color: #d69d85">"nested array 2"</span><br />                                    }<br />                            }<br />                    }<br />                }<br />            })</pre>
<p> </p>
<h1>The How</h1>
<p>Well, the simplest way to see how is to <a href="https://github.com/MattHoneycutt/SpecsFor/blob/master/SpecsFor/ShouldExtensions/ShouldLooksLikeExtensions.cs">check out the code</a>, of course. I’m going to talk about some high level parts here, but suggest you take a look at the code to see it all working together in action. The meat of it is simply in checking the Body property of the expression. For a simple initializer, it’ll be MemberInitExpression. </p>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="keyword" style="color: #569cd6">var</span> <span class="identifier">memberInitExpression</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="identifier">matchFunc</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">Body</span> <span class="keyword" style="color: #569cd6">as</span> <span class="User Types" style="color: #4ec9b0">MemberInitExpression</span>;<br /></pre>
<p>From there, you can use the helper function off the Expression class to turn the expression into a lambda, compile it, and execute it. Then you have your expected value:</p>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="keyword" style="color: #569cd6">var</span> <span class="identifier">expected</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="User Types" style="color: #4ec9b0">Expression</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">Lambda</span><span class="operator" style="color: #b4b4b4"><</span><span class="User Types(Delegates)" style="color: #4ec9b0">Func</span><span class="operator" style="color: #b4b4b4"><</span><span class="keyword" style="color: #569cd6">object</span><span class="operator" style="color: #b4b4b4">>></span>(<span class="identifier">memberInitExpression</span>)<span class="operator" style="color: #b4b4b4">.</span><span class="identifier">Compile</span>()();<br /></pre>
<p>Now, since we don’t want to compare the entire value, only the specified properties, we can loop through the Bindings property of the MemberInitExpression. If this is another expression, we call ourselves with recursion. Otherwise, we use reflection and just test the values. Here’s the code snippet of us checking to see if we need to use recursion or not:</p>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="keyword" style="color: #569cd6">var</span> <span class="identifier">bindingAsAnotherExpression</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="identifier">memberBinding</span> <span class="keyword" style="color: #569cd6">as</span> <span class="User Types" style="color: #4ec9b0">MemberAssignment</span>;</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"> </pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="keyword" style="color: #569cd6">if</span> (<span class="identifier">bindingAsAnotherExpression</span> <span class="operator" style="color: #b4b4b4">!=</span> <span class="keyword" style="color: #569cd6">null</span> <span class="operator" style="color: #b4b4b4">&&</span></pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="operator" style="color: #b4b4b4"></span>    <span class="identifier">bindingAsAnotherExpression</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">Expression</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">NodeType</span> <span class="operator" style="color: #b4b4b4">==</span> <span class="User Types(Enums)" style="color: #b8d7a3">ExpressionType</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">MemberInit</span>)</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">{</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">      <span class="identifier">ShouldMatch</span>(<span class="identifier">actualValue</span>, <span class="identifier">bindingAsAnotherExpression</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">Expression</span> <span class="keyword" style="color: #569cd6">as</span> <span class="User Types" style="color: #4ec9b0">MemberInitExpression</span>);</pre>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro">}<br /></pre>
<h1> </h1>
<p>We want to handle arrays as well! Turns out, this is simple too. Just like we tested the Body property to see if it was an MemberInitExpression, we can test if it’s a NewArrayExpression.</p>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="keyword" style="color: #569cd6">var</span> <span class="identifier">newArrayExpression</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="identifier">matchFunc</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">Body</span> <span class="keyword" style="color: #569cd6">as</span> <span class="User Types" style="color: #4ec9b0">NewArrayExpression</span>;<br /></pre>
<p>Then from there, we just loop off the Expressions array property on the NewArrayExpression type, calling ourselves with recursion.</p>
<pre style="font-size: 13px; font-family: consolas; background: #1e1e1e; color: gainsboro"><span class="keyword" style="color: #569cd6">var</span> <span class="identifier">array</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="identifier">actual</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">ToArray</span>();<br /><span class="keyword" style="color: #569cd6">for</span> (<span class="keyword" style="color: #569cd6">int</span> <span class="identifier">i</span> <span class="operator" style="color: #b4b4b4">=</span> <span class="number" style="color: #b5cea8">0</span>; <span class="identifier">i</span> <span class="operator" style="color: #b4b4b4"><</span> <span class="identifier">arrayExpression</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">Expressions</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">Count</span>; <span class="identifier">i</span><span class="operator" style="color: #b4b4b4">++</span>)<br />{<br />    <span class="identifier">ShouldMatch</span>(<span class="identifier">array</span>[<span class="identifier">i</span>], <span class="identifier">arrayExpression</span><span class="operator" style="color: #b4b4b4">.</span><span class="identifier">Expressions</span>[<span class="identifier">i</span>] <span class="keyword" style="color: #569cd6">as</span> <span class="User Types" style="color: #4ec9b0">MemberInitExpression</span>);<br />}</pre>
<p>Put those bits all together, and we have a pretty simple class that makes our tests a lot easier to read and maintain. I really do recommend <a href="https://github.com/MattHoneycutt/SpecsFor/blob/master/SpecsFor/ShouldExtensions/ShouldLooksLikeExtensions.cs">checking out the finished class</a> if you want to see how it all gels together!</p>
<p> </p>
<h1>TL;DR</h1>
<p>Don’t use ShouldLookLikePartial anymore. Use ShouldLookLike! You can now have your cake and eat it too! </p>
<p>If you find any bugs, please report them at the <a href="https://github.com/MattHoneycutt/SpecsFor/issues">GitHub SpecsFor repository</a>! Also please let us know if there’s some functionality that ShouldLookLikePartial used to perform that ShouldLookLike does not.</p> Anonymoushttp://www.blogger.com/profile/00751154354014174645noreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-78121330943755182652012-12-04T09:02:00.001-06:002012-12-04T09:02:12.610-06:00My experience with FubuMVC so far<p>I’ve been checking out FubuMVC with a little hobby project. Why? Honestly, just curiosity. I don’t have much problem getting stuff done in Asp.NET MVC, but I love StructureMap, so was just curious how the creator of that would envision a MVC framework. Here are my thoughts so far. This is not me trying to post a end-all / be-all post about FubuMVC, just detailing a little of my experiences so far.</p> <p> </p> <h1>The good</h1> <p>There’s lots to love about FubuMVC. Lets start with organization. I absolutely hate the “Controllers / Models / Views” folder layout that the Asp.NET MVC project template uses. That’d be like designing a library by making the folders “Classes / Interfaces / Enums”. So out of the gate FubuMVC is directing you to something better, I feel. I opted for Namespace-per-feature. Granted, I should be able to put controllers and models wherever in a Asp.NET MVC project (not sure on Views, but probably), but with the template doing that, it’s going to be hard to do that outside of greenfield development.</p> <p>I also really enjoy the behavior chains pattern. They work well and are easy to implement. I don’t know how much they differ from similar features in Asp.NET MVC like Handlers (and to an extent, ActionResults), but they’re still nice.</p> <p>It took me a while to fully grok it, and while I’m not 100% there, I really dig the way routes are handled. In Asp.NET MVC, you define a pattern, which then tries to match controller actions. In FubuMVC, that’s turned around – you define your actions, then your convention for how actions are discovered, and those are converted to routes. It feels much more intentional and direct, and after using it some, it makes Asp.NET MVC’s way feel bass ackwards.</p> <p>Everything, and I mean everything, is extensible. You can define your own conventions for pretty much everything. It has some great, sensible conventions baked in that will probably suit like 90% of people, and if nothing else, get you going out of the door. But when you’re ready for something different, you got the hooks to do it, typically by implementing a simple interface then telling StructureMap to pick it up.</p> <p>One of the <strong>best</strong> features thought, is their diagnostics. Your site will have a “/_fubu” path. Opening it up will show you all your routes and the behavior chains wrapped around them. A great way to see why your routes aren’t working, what chains are getting applied, and a good early warning system for issues. There’s a lot more there, but I haven’t had a chance to dig into it all yet. But I love what I see. So few tools put support to the forefront like this.</p> <p> </p> <h1>The bad</h1> <p>FubuMVC bills itself as “The MVC framework that gets out of your way”. Well, and this isn’t really a fair statement but I’ll say it anyways – often times it feels like it’s out of my way because there’s nothing there. It still has some areas that left me very frustrated and annoyed.</p> <p>The documentation is just sad. Their own docs are woefully incomplete with many sections left empty. And some of their examples do not seem to work as advertised. One that sticks out was their “asset pipeline”. It’s what you use to include CSS and Javascript files. There’s the very nice Bundles features of Asp.NET MVC, so I was looking for the FubuMVC alternative, and this was it. However, I cannot find a way to get it work. If I just want it to spit out the per-file link and script tags, it’s fine. But when I tried to use a combination, following what’s on their documentation, it would not work. I did not get an error (even with the option to show a YSOD turned on), and nothing gets emitted. It felt very black-box. I found a post on the FubuMVC google groups page with the same issue, with no response.</p> <p>The Razor story in FubuMVC is miserable. I feel it should just be pulled. From the docs, you’ll think you can have a rewarding experience with it, but you just can’t. I followed the instructions, then had to tweak things to work with the latest release of Razor. I could not get intellisense working, which makes developing Views extremely cumbersome and “guess-and-test”. On top of that, a lot of Razor is built on the Html helpers, which will not work in FubuMVC. I assume full Razor support is possible, but it’s probably not worth it, due to how Razor was unfortunately designed (lots of static helpers, dependencies on HttpContext, etc). I think the better path is to ditch Razor altogether, and have them fully embrace and support a view engine. Perhaps Spark is that view engine? I understand FubuMVC is trying to stay open and allow people to pick their own, but seeing Razor is tempting, and while it’s not directly FubuMVC’s fault, it leaves with an altogether underwhelming experience that made me want to go back to Asp.NET MVC. Do not use Razor if you’re going to use FubuMVC. The FubuMVC examples though show returning strings of HTML, and that’s not really going to work. So I feel lost – unless the answer from the team is indeed “use Spark”.</p> <p>I still have no idea how to render a partial view (or an action) with Razor, passing down a submodel. I probably shouldn’t be doing that anyways, as I thought of a better design for what I wanted using knockout templates, but it was still very frustrating. I can’t find anything in the documentation about how to do that. Probably because it all hinges on what view engine you use, and how much support it has.</p> <p> </p> <h1>Caveats</h1> <p>I don’t really like saying negative things, especially without giving the full context. So here’s some caveats I want to add in addition to the troubles I faced.</p> <p>For one, I didn’t ask for help. There’s the aforementioned FubuMVC google group, that the FubuMVC developers seem to be responsive on. I was able to usually find a post there about my issue, but there was no good resolution. Still, I could’ve reached out more to make sure I’m not making newbie mistakes with easy answers.</p> <p>Also, FubuMVC goes to version 1.0 in January (or that’s at least the plan). This is still a product in Alpha/Beta stage or some such. One of the things I know is coming with 1.0 is real documentation. Jeremy Miller has kinda a reputation for releasing a great product with poor docs (StructureMap), but with StructureMap I never ran into an issue I couldn’t solve with a little GoogleFu. Hopefully with 1.0 some of my issues get resolved.</p> <p>Then the last caveat, that I’ve already mentioned – this is just a post of my experiences so far. I’m not saying there’s no good and easy way to do bundling and minification of CSS files in FubuMVC, for example. Just that I couldn’t get it to work after banging away for a few hours (or completely rolling my own solution). That goes for most of my “bad” notes.</p> <p> </p> <h1>Final thoughts</h1> <p>FubuMVC has a lot of promise. What’s there is mostly great, it’s what’s not there that hurts it the most (especially when compared to Asp.NET MVC). If you’re looking to start a new project for your business – I hate to say it, but my opinion is to stick with Asp.NET MVC. You’ll get things done faster, and have more resources available to you. If you’re doing a hobby project and want to learn something new…I’d probably recommend to wait until FubuMVC 1.0 comes, and see what it holds at that time. It has a lot of promise, and I think it’s headed in a great direction. Just didn’t feel it was ready for “primetime” yet. Even then though, just stay away from Razor – from what I’ve read on their group, unless someone champions it on themselves, the Razor story in FubuMVC will always be lackluster. Which is a shame, because I really like that syntax.</p> Anonymoushttp://www.blogger.com/profile/00751154354014174645noreply@blogger.com6tag:blogger.com,1999:blog-2430856949934117881.post-53385826151145733352012-11-22T21:34:00.001-06:002012-11-22T21:34:01.375-06:00RavenDB and creating indexes – newbie gotcha! (and other Raven thoughts)<p>I’ve been playing with a hobby project on RavenDB and FubuMVC. I’m 100% newbing it up to both technologies, but I like a lot of what I see in both.</p> <p>Anywhos, almost all the “getting started” RavenDB tutorials recommend putting a line of code in your application startup (Global.asax for Asp.NET MVC) that will scan a given assembly for any indexes, and add them for you. Pretty awesome, right? Because you can’t query against an index if it isn’t there. Here’s the line:</p><pre class="csharpcode">IndexCreation.CreateIndexes(Assembly.GetCallingAssembly(), DocumentStoreInstance);</pre>
<p>I had this, yet my new index did not get picked up! I changed the Assembly.GetCallingAssembly() line to be typeof(MyIndexType).Assembly to make sure I wasn’t grabbing the wrong assembly. My query on the index still blows up with “index not found”. I open the RavenDB web UI, and the index isn’t there. I look on the file system, and I can even *see* the index in the folder!</p>
<p>To cut a long story short (4 hours worth, boy do I feel dumb), I was trying to be A Good Developer, and I was using tenants in RavenDB. Tenants are like creating a database in SQL Server. See, you can use RavenDB without creating a tenant. It just dumps everything in System. That’d be like creating your tables in the “master” database in SQL Server. The line above, of course, does not specify a tenant. The solution?</p><pre class="csharpcode">var catalog = <span class="kwrd">new</span> CompositionContainer(<span class="kwrd">new</span> AssemblyCatalog(<span class="kwrd">typeof</span>(MyIndexType).Assembly));
IndexCreation.CreateIndexes(catalog, DocumentStoreInstance.DatabaseCommands.ForDatabase(<span class="str">"YourTenantName"</span>), DocumentStoreInstance.Conventions);</pre><pre class="csharpcode"> </pre>
<p>I’d like to see an overload for IndexCreation that makes that a little simpler and easier to consume, but not the end of the world. Hopefully that helps someone else getting started to RavenDB! </p>
<p><strong>Other Raven thoughts</strong></p>
<p>Because I can’t stop talking…I’m not sure why RavenDB uses the words “tenants”. Even the web UI calls them Databases, and the method above says “ForDatabase”. Yet you’ll see some talk about multi-tenancy in relation to RavenDB. The <a href="http://ravendb.net/kb/31/my-10-tips-and-tricks-with-ravendb" target="_blank">10 tips and tricks page on RavenDB’s sit</a>e calls them tenants. I’m not sure if I’m using the wrong term, or if it’s a case of there not being a preferred term, and it all means the same thing.</p>
<p>I also don’t like what I call “the broken intro”. Remember when you were new to the world of software, and you wrote your first hello world website? And how that tutorial had you happily concatenate SQL right from a textbox and push that down to your database? I call that a broken intro – when the introduction to something is The Wrong Way to do it. I’ll probably make a bigger post on this some day, but the point is most of the intro stuff on RavenDB’s site has you dumping stuff into the “system” database. That’s even a protected database on the web UI, and it bitches at you for going there.</p>
<p>My last thought is how much I love working with RavenDB so far :3. A native .NET API, no fighting persistence related nightmares, and a great administrative interface. I know it’s just the honeymoon stage, but I really enjoy it.
<style type="text/css">.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style></p> Anonymoushttp://www.blogger.com/profile/00751154354014174645noreply@blogger.com1tag:blogger.com,1999:blog-2430856949934117881.post-29758432207270071042012-01-06T13:15:00.000-06:002012-01-06T13:46:06.398-06:00Saving the internet!<br />
<br />
Tired of all the hate spreading on the internet lately? I don't blame you. With recent tirades like "The framework I like working in is way more betterer than yours" and great responses like "nu-uh! Shut up!, it can get a bit tiresome.<br />
<br />
I think it'd help to remember though, that all these are, are the expressions of opinions. Unfortunately they're often presented as fact, generally because people just get tired of reiterating that it is indeed, just their opinion.<br />
<br />
However, I now have the solution! Simply <a href="javascript:(function(){function%20op(p){var%20h=p.innerHTML;h=h.replace(/\./gi,%22,%20in%20my%20opinion.%22);h=h.replace(/\!/gi,%22,%20in%20my%20opinion!%22);p.innerHTML=h;}var%20ps=document.getElementsByTagName('P');for(var%20i%20in%20ps){op(ps[i]);}})();">bookmark this link</a>, and anytime you're reading something and you start getting a little "hot under the collar", click your bookmark, and read it again.<br />
<br />
There! I've made the internet safe again!<br />
<br />
<i>(Edit: Sorry if you got this post multiple times. Original bookmarklet was trying to do too much, got too complex and buggy. This one has nuances, but it's fine for the joke, and much simpler ;-) )</i>Anonymoushttp://www.blogger.com/profile/00751154354014174645noreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-40119725653284313502011-12-23T19:23:00.001-06:002011-12-23T19:23:14.984-06:00The case for MSBuild<p>I was talking to a fellow developer on Facebook (I know, that’s not twitter, wtf!) and he was asking about build and deployment issues – specifically some frustrations around MSBuild. I suggested some things to help with his issues and utilize it better. That kinda got me thinking about how it seems many people don’t know how to use MSBuild in-depth (not that I’m an expert by any means). It seems to be dismissed very early and easily as a build and deployment solution. So, I’m taking the not trodden road, the dusty path, going where no man has gone before…and blogging in favor of MSBuild…in 2011!</p> <p><em>(Note: This post isn’t actually how to use MSBuild itself. It’s me talking about why it’s worth taking the time to actually consider/learn it.)</em></p> <h2>The Case Against</h2> <p><u><XML /></u></p> <p>Man, do people hate XML! Nothing more to really say about this – you either hate it or you don’t care. I don’t think anyone (well, human at least) loves XML. At least it’s not EDI, right? However – remember that writing your own MSBuild task can be as simple as inheriting from a base class and overriding Execute(). So if you want to do your whole build/deploy with a .NET language, you can, with a minimal amount of XML.</p> <p><u>It’s not sexy</u></p> <p>Okay, well, noone has said those words, I don’t think, but that’s what people’s faces say whenever you mention MSBuild. It’s not “the new hotness” by any means and it requires a learning curve. Any other new sexy build technologies have a learning curve too, but for whatever reason, developers (myself included) are much less likely to want to learn something when it’s an old product.</p> <p><u>Rob wrote a post saying you should consider it</u></p> <p>If I say it, it must already be wrong! I’m totally dooming myself to internet unpopularity! Zomgz! And anyone else who agrees with me even in the slightest will share my dark corner of internet shame. Next I’ll be posting about how awesome VB.NET is, how MSTest is soooo much more awesomer than nUnit, and how WebForms really got the web right! <CharlieTheUnicornsFriends>SHUUUUUUN!!!!</CharlieTheUnicornsFriends>*</p> <p><em>*Oh god, I’m using XML even in my blog posts now!</em></p> <p><u>It’s not updated for user friendliness…or I don’t think is…hell I don’t know!</u></p> <p>There doesn’t seem to be a real….community around MSBuild. If new updates are happening to it, I’m unaware of them (and I follow several MS blogs..maybe it’s the wrong ones?). Either way, I do not believe it gets updates that would make consumption of it easier, or have more things “baked in”, and some of the other new build tools are more likely to have that user-friendliness and open-source community guiding the directions of their product.</p> <p> </p> <h2>The Case For</h2> <p><em>*Man, I’m making lots of “notes” in this one! Anyways, none of the “case for” necessarily mean it in a “competing-product-x-cant-do-this” fashion. I’m simply saying that MSTest CAN do these things, and a lot of people seem to think it can’t, or that it’s a big hassle to do these things with MSBuild, which is not the case.</em></p> <p><u>You, and your grandma, already have it installed</u></p> <p>“Laziness” isn’t a good criteria for choosing your toolset, but simplicity is. As long as you’re building on a Windows machine, you already have all the tools you need*. You just run it from the command prompt (or better yet, a batch file).</p> <p><em>*note that the normal .NET installation does not have web-related targets by default however, which docks 5 internet points from MSBuild. What I’ve done is make a self-extracting exe, that you can call from a custom MSBuild target. You run it once on a given machine, and it’s set from there on out. You could probably do something similar for installing needed software for other builders too though.</em></p> <p><u>You’re already using it</u></p> <p>Like it or not, you’re using MSBuild! Until I started writing my own custom targets, I never really groked what was going on in a *.sln or .*proj file. This helped me learn more about how .NET solutions and projects are arranged, how things are coordinated “underneath the hood”. You can always read a book or a blog about these things, but I always find you can’t really understand something until you have to deal with it by hand. Knowing more about what you’re dealing with can a help a lot when you start having issues in your project/solution files, or want to add/edit post/pre build steps.</p> <p><u>There’s a nice existing library of community addons</u></p> <p>Chances are, if you’re thinking about doing some lower-level task (like, for example, reading XML out of a config, or starting/stopping windows services), there’s probably already a task out there. Granted, other frameworks have this too, and the MSBuild Community Tasks haven’t been updated in forever (remember, it’s old! Time to move on!), but the point is, there is a library out there that’s extremely useful and tackles a whole lot of common cases. The point being – there’s more than what’s just built-in that’s easy to get. A lot of people don’t seem to know this.</p> <p><u>Yes, you can do that with it</u></p> <p>Whatever “it” is, you can accomplish it with MSBuild. Again, not saying that other frameworks/methods don’t have this either – but MSBuild is extremely powerful. A lot of people seem to equate “XML = Useless”, and I just want people to understand that’s not the case. The fact that you can write your own C# library and have MSBuild run commands in it literally means “can do anything”.</p> <p><u>Highly reusable</u></p> <p>It’s extremely easy to factor-out common targets to reuse them across multiple projects or even multiple solutions. On a previous project we had 3 websites being deployed to 5 machines, all using the exact same target, with no repetition. You can usually factor out things into more targets and chain them or composite them together as needed in higher-level build files. Yet again – not a unique feature, just saying MSBuild supports it, and it’s easy.</p> <p> </p> <h2>What Really Matters</h2> <p>It’s good to remember to come back and focus on what’s important – delivering value. Build and deployment is a very serious part of any project, and unfortunately most of the time it gets cast aside, only to be rushed through at the last minute. Good agile software techniques are teaching us and the industry as a whole to consider these things up front and to make them painless. The fact that we’re even discussing it at all is a great thing! Noone really recommends “deploy from Visual Studio to prod” or “copy these files, then hand-edit that config, the don’t forget to insert these rows in the database…” as a serious technique anymore. What’s even better is that there ARE options out there!</p> <p>I just hope that after this people keep an open mind about MSBuild, and realize that it’s a powerful solution that can work great on .NET solutions. It’s as “correct” a solution as alternatives such as Albacore, Rake, PowerShell, etc. The only real differences are likely to be your <em>opinion</em> for what fits your style/team/situation better.</p> <p>So what it boils down to, again, is delivering that value.  Pick something that your team is interested in, that your company can easily support and maintain, and that efficiently works with your processes. </p> Anonymoushttp://www.blogger.com/profile/00751154354014174645noreply@blogger.com3tag:blogger.com,1999:blog-2430856949934117881.post-61312109069065814202011-12-13T16:21:00.001-06:002011-12-13T16:21:36.252-06:00Focus on the team – not the product<p>I'm going to state something you probably already know</p> <p>Agile is about the team - not about the products.</p> <p>It feels like a very obvious truth to me, but I didn't realize it until recently. It was one of those things that as soon as I said it, I realized that it was extremely true. I hadn't heard it before (or it didn't stick - I'm pretty dumb, after all).</p> <p>Why haven't I heard this before? Why does this even matter? This is probably due to, at least in part, always working on small teams. On the rare occasions where I've been on a larger team (6-7 developers), we had several products. Usually to the point where each developer worked on a product by themselves, or mostly by themselves.</p> <p>Now I'm going to talk about more things you probably already know!</p> <h1> </h1> <h1>How things typically seem to go:</h1> <p>Traditional (typically rooted in an attempt to do Waterfall) organization in regards to software development seems to be centered around the products. There's a request for some new software. It gets added to a Product Manager's "list of products I'm PM for". The PM makes a request to the development group. The development group allocates some resources to the effort. This is done by taking one or more developers away from something else they're doing - or worse, they're asked to "split time" between multiple products. Each way has their own major problems.</p> <p>If a developer is asked to split their time, they now have conflicting priorities. They can ask whoever represents the Product group which product feature is the most important across multiple products, and will get different answers. Everyone will always want whichever product they're closest too (or is the squeakiest wheel) done first. Getting a single clear direction, that doesn't change on a daily (or worse, hourly!) basis will be neigh-impossible.</p> <p>If a developer is made dedicated on this new product, while at least they won't have conflicting priorities, other issues arise. That developer will likely be working in a silo. No ability to do peer reviews (other than simple adherence to coding standards possibly). Higher stress due to not being able to take sick time. Developing in a black box. Harder to bounce ideas off of peers, since no one else will know the domain. Chances are if someone else has to join in on the product later, that person will be very lost, and will likely end up needing either a lot of time learn the existing codebase, or re-writing the product.</p> <p>In both cases, any existing products are damaged, as their ability to do planning will be interrupted. If they're attempting to do Scrum, for example, now their velocity will be incorrect, and will have to be recalculated. Again, if things are ran by product, and not by team, and especially if a developer is spread across products, getting any consistency will be extremely difficult, if not impossible.</p> <h1> </h1> <h1>How organizing around the team fixes things:</h1> <p>When you organize around the team, in a proper Agile environment, one of the first things you'll get is a single Product Owner. Without getting into the full definition of the PO role in Agile terms, the key part that is important in relation to this post is the fact that the PO will set the priority of work for the team. This gives a single person the responsibility of knowing what's important to each product the team supports and the relative priority among the products. This is critical.</p> <p>The next thing you'll get is predictability. With the developer/QA resources (boy do I hate using that word, but stick with me) being constant, the amount of work the team can get done will be consistent - regardless of the product.</p> <p>You'll also avoid silos this way. Since a team grooms stories together, everyone will be knowledgeable about the products. This gives people freedom to take time off work as needed, without being "the one guy" that knows how something works. The Company typically likes this aspect when phrased as "If we do this, then if [So-and-so] gets hit by a bus, the product isn't doomed!". If you're practicing some good policies like peer reviews, that will also help spread knowledge about the products throughout the team, as well as let everyone feel that they know all the products on that team.</p> <h1> </h1> <h1>Avoiding possible pitfalls:</h1> <p>What if it gets to where you have lots of products (typically, several smaller ones and a larger one or two)? Then you have another problem - but it's not solved by organizing around the product. Not that I'd even really want to call that a problem. If one product consumes 80% of the team's time, it may be viable to split the team at that point, so that a larger portion is dedicated to that product, and a smaller team is formed to handle the other products. Be prepared to keep the teams consistent after that point though, and don't start "borrowing" resources from other teams, or you'll end up right where you started. </p> <p>Splitting the team also means getting another PO - one for each team. It might, in theory, be possible to have a single PO over multiple teams, but more than likely it'll end up with that person not being able to focus on each team as they should.</p> <p>Many businesses want "on demand" time spent on their product. They want that product right then and there, and later on, interest in that product might slow down (especially once it's been launched, and initial revenue gained). That leads them to want to shuffle development around as needed. Agile is great at providing visibility in the effect these decisions have. By switching the focus from the product to the team, it allows businesses to see how it actually hurts other products, instead of creating the illusion that development is an unlimited resource. It's up to the PO to communicate back to the Powers That Be that the new product can be delivered, but that existing products will have their timelines affected. It's going to happen anyways - but when focusing on the product, there's the false sense that other products are unaffected.</p> <p>Often the most important thing when selling software (or selling anything, honestly), is managing expectations. By organizing around the team, you will get consistent, predictable results for your clients. Your developers will be able to focus on the work laid out for them, instead of trying to juggle priorities and emails. If you can deliver what you say, your clients will be happier. You'll have happier developers this way too, which lead to less turnover - which will again help with more predictability, feeding back into happy clients.</p> <p>There are other things I feel are beneficial as well, but this post is long enough! Suffice it to stay, focusing on the team helps solve many problems, and will prevent other issues from arising. Again, this is based on my experience, which is limited to tiny teams, or a larger team with more products than they can handle.</p> Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-2430856949934117881.post-40312238016609336472011-11-01T20:02:00.001-05:002011-11-01T20:02:18.124-05:00Decorating a generic interface with StructureMap<p>While at The Day Job, I noticed we had some services that all shared the same cross-cutting concerns. In particular, validating a request object. You may think of some other ones, like logging, auditing, standard error-handling, etc. Due to other architectural concerns of our project, it made sense to decorate a common interface we had as a way to achieve the validation. First, here’s our generic interface that we want to decorate:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">interface</span> IServiceOperation<<span class="kwrd">in</span> TRequest, <span class="kwrd">out</span> TResponse> <span class="kwrd">where</span> TResponse : ServiceResult, <span class="kwrd">new</span>()
{
TResponse PerformService(TRequest validatedRequest);
}</pre>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>Simply put, it just says given a request object, I’ll return a standard response object. To show it “in action”, here’s a sample implementation. Note that the interface has already assumed at this point that the request object has been validated.</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> SignUpService : IServiceOperation<SignUpRequest, SignUpResult>
{
<span class="kwrd">private</span> <span class="kwrd">readonly</span> IUserRepository _userRepo;
<span class="kwrd">public</span> SignUpService(IUserRepository userRepo)
{
_userRepo = userRepo;
}
<span class="kwrd">public</span> SignUpResult PerformService(SignUpRequest validatedRequest)
{
var user = Mapper.Map<User>(validatedRequest);
user.MarkAsLoggedIn();
user.ChangePassword(validatedRequest.UnhashedPassword);
<span class="kwrd">using</span>(var transaction = _userRepo.BeginTransaction())
{
_userRepo.Save(user);
transaction.Commit();
}
<span class="kwrd">return</span> <span class="kwrd">new</span> SignUpResult();
}
}</pre>
<p>Pretty standard stuff, nothing special. Just a domain service that takes in a request, performs some domain operations, then saves changes to a repository.<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style></p>
<p>Now for our decorator. If you’re unfamiliar with the decorator pattern, here’s the simple version – a decorator is a class that implements an interface, and also consumes an instance of that interface in it’s constructor. This allows you to “intercept” any calls against the passed-in instance to add extra behavior, while wrapping the consumed instance. Your consuming application doesn’t have to change it’s code at all – your IoC container will do the magic for you. You just code against the interface like normal, and everything is happy. You can even have multiple decorators (each one consuming another!).</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> ValidateServiceDecorator<TRequest, TResponse> : IServiceOperation<TRequest, TResponse> <span class="kwrd">where</span> TResponse : ServiceResult, <span class="kwrd">new</span>()
{
<span class="kwrd">private</span> <span class="kwrd">readonly</span> IServiceOperation<TRequest, TResponse> _serviceOperation;
<span class="kwrd">private</span> <span class="kwrd">readonly</span> IValidationService _validationService;
<span class="kwrd">public</span> ValidateServiceDecorator(IServiceOperation<TRequest, TResponse> serviceOperation,
IValidationService validationService)
{
_serviceOperation = serviceOperation;
_validationService = validationService;
}
<span class="kwrd">public</span> TResponse PerformService(TRequest request)
{
var response = <span class="kwrd">new</span> TResponse();
var validationResult = _validationService.Validate(request);
<span class="kwrd">if</span> (!validationResult.IsValid)
{
response.ValidationErrors = validationResult.ValidationErrors;
<span class="kwrd">return</span> response;
}
<span class="kwrd">return</span> _serviceOperation.PerformService(request);
}
}</pre>
<p>Easy peasy! It takes in IService<A,B>, and implements it as well. So, again – the magic needs to be handled by our IoC Container, in our case, StructureMap. StructureMap already has some great support for auto-registering open generic types with the “ConnectImplementationsToTypesClosing” function, and decorator support with the “EnrichWith” function. However, combining the two can be prolematic, as EnrichWith except your type, if generic, to be a closed generic type (meaning you know the type parameters explicitly). Obviously, we don’t know that – well, we could, but that’d mean every time we added a new request/response pairing for our IServiceOperation, we’d have to modify our container. This would lead to a lot of copy/pasted code in our container, be something everyone would forget to do, and another spot to be affected when renaming objects. Not exactly ideal.</p>
<p>It took quite a bit of digging, even posted the question to StackOverflow, but did not get a response. Eventually, I was able to find a solution – a custom IRegistrationConvention! If you’re not familiar with this (as I wasn’t), this is a hook StructureMap provides. By implementing this interface from Structuremap, you’ll get a hook in the form of a function that is called for every type StructureMap finds when starting up (depending on what assemblies you tell it to scan). From here, I was able to inspect each type, and see what interfaces it implemented. If the implemented interface was IServiceOperation, then through reflection I could get what two types (the response and request) were used to close the implementation, then tell StructureMap that for that closed type, to return my decorator using those same two types (with Activator.CreateInstance).</p>
<p>Here’s my final StructureMap code, showing it all hooked together. I hope this helps other people! </p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> StructureMapServiceScanner : Registry
{
<span class="kwrd">public</span> StructureMapServiceScanner()
{
Scan(scanner =>
{
<span class="rem">//Tells StructureMap to scan all types in the assmebly where the interface is defined</span>
scanner.AssemblyContainingType(<span class="kwrd">typeof</span> (IServiceOperation<,>));
<span class="rem">//Tells StructureMap that for all requests of IServiceOperation to automatically return</span>
<span class="rem">//the concrete type that closes the interface with the same as the requested parameters</span>
scanner.ConnectImplementationsToTypesClosing(<span class="kwrd">typeof</span> (IServiceOperation<,>));
<span class="rem">//And finally, we add our new registration convention</span>
scanner.Convention<ServiceRegistrationConvention>());
});
}
}</pre>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> ServiceRegistrationConvention : IRegistrationConvention
{
<span class="kwrd">public</span> <span class="kwrd">void</span> Process(Type type, Registry registry)
{
var interfacesImplemented = type.GetInterfaces();
<span class="kwrd">foreach</span> (var interfaceImplemented <span class="kwrd">in</span> interfacesImplemented)
{
<span class="kwrd">if</span> (interfaceImplemented.IsGenericType && interfaceImplemented.GetGenericTypeDefinition() == <span class="kwrd">typeof</span>(IServiceOperation<,>))
{
var genericParameters = interfaceImplemented.GetGenericArguments();
var closedValidatorType = <span class="kwrd">typeof</span>(ValidateServiceDecorator<,>).MakeGenericType(genericParameters);
registry.For(interfaceImplemented)
.EnrichWith((context, original) => Activator.CreateInstance(closedValidatorType, original,
context.GetInstance<IValidationService>()));
}
}
}
}</pre>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>And of course, if you know of another/better way to do this, please respond!</p> Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2430856949934117881.post-72562495558138207062011-07-15T20:48:00.001-05:002011-07-15T21:11:07.838-05:00Increasing Testability With The Adapter Pattern<p><em>(Edit: I accidentally originally fat-clicked the publish button in the middle of creating this post. Sorry for the spam in your reader!)</em></p> <p>So, you have some code that you can’t change for some reason. Maybe it’s an external library. Maybe it’s a crucial bit of code that too many things are coupled to, and changing it would be a big headache. Regardless of why, it does the work you need to do (for the most part!) but it’s not exposed in a way you like, or a way that fits 100% what you need to do. So how can you still use it? Also, how can you test that you’re using it correctly? Enter: The Adapter Pattern!</p> <h1> </h1> <h1>The basic idea, and then some</h1> <p>So, with the adapter pattern, the general goal is changing one interface to a desired interface. On top of that, this pattern will also help bring testability to your code. If you’re not familiar with TDD/BDD, or just generally unfamiliar with testing your .NET code, here’s some of the things I’ll be using in this post:</p> <ul> <li><a href="http://www.nunit.org/" target="_blank">nUnit</a> – Unit testing framework. You can also use MSTest (comes with Visual Studio). </li> <li><a href="http://code.google.com/p/moq/" target="_blank">Moq</a> – Mocking framework. Another popular one is <a href="http://ayende.com/wiki/Rhino+Mocks.ashx?AspxAutoDetectCookieSupport=1" target="_blank">RhinoMocks</a>. </li> <li><a href="http://nuget.codeplex.com/wikipage?title=Getting%20Started" target="_blank">NuGet</a> – While not shown here, I did use this tool to add NUnit and Moq to the project. If you were thinking of going and downloading nUnit, Moq, etc manually, don’t! Use NuGet. </li> <li>We’ll also <em>briefly</em> touch on the concept of Dependency Injection, although I won’t be using it here with an IoC container (like Ninject or StructureMap). </li> </ul> <h1></h1> <h1></h1> <p> </p> <h1></h1> <h1></h1> <h1>The Problem</h1> <p>For us, we had a base class (from an external library that we couldn’t change) that we had to inherit to make it “plug in” to another system. This base class had 2 main problems for us</p> <ol> <li>It requires a parameter-less constructor (so goodbye clean dependency injection) </li> <li>It has lots of methods on the base class that we want to use (although their parameters weren’t exactly what we wanted at times) </li> </ol> <p>So, to give an example – the class (in the external library) looks approximately like this:</p> <div class="csharpcode"> <pre><span class="lnum"> 1: </span><span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">class</span> UnchangeableBaseClass</pre>
<pre><span class="lnum"> 2: </span>{</pre>
<pre><span class="lnum"> 3: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> PerformOperation(<span class="kwrd">string</span> generalOperationName)</pre>
<pre><span class="lnum"> 4: </span> {</pre>
<pre><span class="lnum"> 5: </span> <span class="rem">//Magic stuff happens</span></pre>
<pre><span class="lnum"> 6: </span> }</pre>
<pre><span class="lnum"> 7: </span> </pre>
<pre><span class="lnum"> 8: </span> <span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">void</span> RunMe();</pre>
<pre><span class="lnum"> 9: </span>}</pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<h1></h1>
<p>We have a base class we can’t modify. We have to implement RunMe() to tie it into the system. And on this base class, is a function, “PerformOperation”, that we want to take advantage of, but we don’t like passing in a string.</p>
<h1> </h1>
<h1>Our Code</h1>
<p>So, we go to implement our class, so here’s what we end up with:</p>
<div class="csharpcode">
<pre><span class="lnum"> 1: </span><span class="kwrd">public</span> <span class="kwrd">class</span> YourClass : UnchangeableBaseClass</pre>
<pre><span class="lnum"> 2: </span>{</pre>
<pre><span class="lnum"> 3: </span> <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> RunMe()</pre>
<pre><span class="lnum"> 4: </span> {</pre>
<pre><span class="lnum"> 5: </span> PerformOperation(<span class="str">"KeepingItReal"</span>);</pre>
<pre><span class="lnum"> 6: </span> }</pre>
<pre><span class="lnum"> 7: </span>}</pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>So, what problems are here? Well, it’s untestable, for one. Second, we really don’t like passing in that string.  Let’s try to write a test (and you’ll see how far we don’t get!) (<em>Note: In good TDD fashion, you’d start with trying to write your test, which would help drive your design to testable code. But the goal of this post is to explain the pattern, which I think will be better served in this order. I’m probably wrong.)</em></p>
<div class="csharpcode">
<pre><span class="lnum"> 1: </span>[Test]</pre>
<pre><span class="lnum"> 2: </span><span class="kwrd">public</span> <span class="kwrd">void</span> WhenRunning_ItShouldPerformOperation()</pre>
<pre><span class="lnum"> 3: </span>{</pre>
<pre><span class="lnum"> 4: </span> var sut = <span class="kwrd">new</span> YourClass();</pre>
<pre><span class="lnum"> 5: </span> </pre>
<pre><span class="lnum"> 6: </span> sut.RunMe();</pre>
<pre><span class="lnum"> 7: </span> </pre>
<pre><span class="lnum"> 8: </span> <span class="rem">//Assert....uh...what?</span></pre>
<pre><span class="lnum"> 9: </span>}</pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>Wow. Didn’t get far there at all! It’s time for…THE ADAPTER PATTERN! </p>
<h1> </h1>
<h1>Patterns to the Rescue!</h1>
<p>Let’s start with what we WANT the code to look like. And by that, I mean let’s define the interface we wish we were consuming.<span class="lnum">  </span></p>
<div class="csharpcode">
<pre><span class="lnum"> 1: </span><span class="kwrd">public</span> <span class="kwrd">interface</span> IPerformOperation</pre>
<pre><span class="lnum"> 2: </span>{</pre>
<pre><span class="lnum"> 3: </span> <span class="kwrd">void</span> PerformOperation(Operations operation);</pre>
<pre><span class="lnum"> 4: </span>}</pre>
<pre><span class="lnum"> 5: </span> </pre>
<pre><span class="lnum"> 6: </span><span class="kwrd">public</span> <span class="kwrd">enum</span> Operations</pre>
<pre><span class="lnum"> 7: </span>{</pre>
<pre><span class="lnum"> 8: </span> KeepingItReal,</pre>
<pre><span class="lnum"> 9: </span> KeepingItMostlyReal,</pre>
<pre><span class="lnum"> 10: </span> MauryPovich</pre>
<pre><span class="lnum"> 11: </span>}</pre>
</div>
<p>Pretty simple! Now, lets write our actual adapter, with comments to help explain!</p>
<div class="csharpcode">
<pre><span class="lnum"> 1: </span>/ Our Adapter implements the <span class="kwrd">interface</span> we want to work against.</pre>
<pre><span class="lnum"> 2: </span><span class="rem">// Also, we name our class with "Adapter". When using patterns, this helps</span></pre>
<pre><span class="lnum"> 3: </span><span class="rem">// the team to work with a common terminology, and to explain complex ideas simply</span></pre>
<pre><span class="lnum"> 4: </span><span class="kwrd">public</span> <span class="kwrd">class</span> UnchangeableAdapter : IPerformOperation</pre>
<pre><span class="lnum"> 5: </span>{</pre>
<pre><span class="lnum"> 6: </span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> UnchangeableBaseClass _baseClass;</pre>
<pre><span class="lnum"> 7: </span> </pre>
<pre><span class="lnum"> 8: </span> <span class="rem">// Since we're translating one interface to another, we're going to have to actually</span></pre>
<pre><span class="lnum"> 9: </span> <span class="rem">// have a reference to the class that implements the original interface</span></pre>
<pre><span class="lnum"> 10: </span> <span class="kwrd">public</span> UnchangeableAdapter(UnchangeableBaseClass baseClass)</pre>
<pre><span class="lnum"> 11: </span> {</pre>
<pre><span class="lnum"> 12: </span> _baseClass = baseClass;</pre>
<pre><span class="lnum"> 13: </span> }</pre>
<pre><span class="lnum"> 14: </span> </pre>
<pre><span class="lnum"> 15: </span> <span class="rem">// This is our implementation of our new interface. It simply</span></pre>
<pre><span class="lnum"> 16: </span> <span class="rem">// acts as a pass-through to the original version, along with translating our parameters</span></pre>
<pre><span class="lnum"> 17: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> PerformOperation(Operations operation)</pre>
<pre><span class="lnum"> 18: </span> {</pre>
<pre><span class="lnum"> 19: </span> _baseClass.PerformOperation(operation.ToString());</pre>
<pre><span class="lnum"> 20: </span> }</pre>
<pre><span class="lnum"> 21: </span>}</pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>Alright, now we’re getting somewhere! Lets get back to that test – I bet we can get somewhere now, with the help of Moq!</p>
<div class="csharpcode">
<pre><span class="lnum"> 1: </span>[Test]</pre>
<pre><span class="lnum"> 2: </span><span class="kwrd">public</span> <span class="kwrd">void</span> WhenRunning_ItShouldPerformOperation()</pre>
<pre><span class="lnum"> 3: </span>{</pre>
<pre><span class="lnum"> 4: </span> <span class="rem">// Moq simply asks for what interface we wished our object used</span></pre>
<pre><span class="lnum"> 5: </span> var operationPerformerMock = <span class="kwrd">new</span> Mock<IPerformOperation>();</pre>
<pre><span class="lnum"> 6: </span> </pre>
<pre><span class="lnum"> 7: </span> <span class="rem">// Now, due to the parameter-less constructor constraint, we'll have to do something</span></pre>
<pre><span class="lnum"> 8: </span> <span class="rem">// interesting in our implementation, but we need this for testing. There's multiple</span></pre>
<pre><span class="lnum"> 9: </span> <span class="rem">// ways we could deal with this problem, but the one I use involves multiple constructors</span></pre>
<pre><span class="lnum"> 10: </span> var sut = <span class="kwrd">new</span> YourClass(operationPerformerMock.Object);</pre>
<pre><span class="lnum"> 11: </span> </pre>
<pre><span class="lnum"> 12: </span> <span class="rem">// Oh, and "sut" means "System Under Test" :)</span></pre>
<pre><span class="lnum"> 13: </span> sut.RunMe();</pre>
<pre><span class="lnum"> 14: </span> </pre>
<pre><span class="lnum"> 15: </span> <span class="rem">// This Moq command verifies that our class (YourClass) calls the PerformOperation method on the interface</span></pre>
<pre><span class="lnum"> 16: </span> <span class="rem">// properly. We don't care about the parameter at this point.</span></pre>
<pre><span class="lnum"> 17: </span> operationPerformerMock.Verify(o => o.PerformOperation(It.IsAny<Operations>()));</pre>
<pre><span class="lnum"> 18: </span>}</pre>
</div>
<p>Sweet! Now we have a failing test (and not compiling, actually – we don’t have that constructor!). So what now?</p>
<p><style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style></p>
<h1></h1>
<h1>Finishing our class</h1>
<p>We’re almost there! Home stretch!</p>
<div class="csharpcode">
<pre><span class="lnum"> 1: </span><span class="kwrd">public</span> <span class="kwrd">class</span> YourClass : UnchangeableBaseClass</pre>
<pre><span class="lnum"> 2: </span>{</pre>
<pre><span class="lnum"> 3: </span> <span class="kwrd">private</span> <span class="kwrd">readonly</span> IPerformOperation _operationPerformer;</pre>
<pre><span class="lnum"> 4: </span> </pre>
<pre><span class="lnum"> 5: </span> <span class="rem">// Our parameter-less constructor, as needed by the other system.</span></pre>
<pre><span class="lnum"> 6: </span> <span class="kwrd">public</span> YourClass()</pre>
<pre><span class="lnum"> 7: </span> {</pre>
<pre><span class="lnum"> 8: </span> <span class="rem">// Here, we get our concrete adapter. This example is trivial,</span></pre>
<pre><span class="lnum"> 9: </span> <span class="rem">// so nothing more is required, but if you're interested in better</span></pre>
<pre><span class="lnum"> 10: </span> <span class="rem">// software design, I'd recommend checking out the Factory pattern </span></pre>
<pre><span class="lnum"> 11: </span> <span class="rem">// and Inversion of Control libraries, like Ninject or StructureMap!</span></pre>
<pre><span class="lnum"> 12: </span> _operationPerformer = <span class="kwrd">new</span> UnchangeableAdapter(<span class="kwrd">this</span>);</pre>
<pre><span class="lnum"> 13: </span> }</pre>
<pre><span class="lnum"> 14: </span> </pre>
<pre><span class="lnum"> 15: </span> <span class="rem">// We expose this constructor to allow for testing!</span></pre>
<pre><span class="lnum"> 16: </span> <span class="kwrd">public</span> YourClass(IPerformOperation operationPerformer)</pre>
<pre><span class="lnum"> 17: </span> {</pre>
<pre><span class="lnum"> 18: </span> _operationPerformer = operationPerformer;</pre>
<pre><span class="lnum"> 19: </span> }</pre>
<pre><span class="lnum"> 20: </span> </pre>
<pre><span class="lnum"> 21: </span> <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> RunMe()</pre>
<pre><span class="lnum"> 22: </span> {</pre>
<pre><span class="lnum"> 23: </span> <span class="rem">// Let's simple call the function on our interface!</span></pre>
<pre><span class="lnum"> 24: </span> _operationPerformer.PerformOperation(Operations.KeepingItReal);</pre>
<pre><span class="lnum"> 25: </span> }</pre>
<pre><span class="lnum"> 26: </span>}</pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>Nice! Let’s run our test…and it passed! Thanks to the adapter pattern, we can now interact with an interface that matches our needs, and gives us the testability we desire in our software.</p>
<p> </p>
<h1>Interested in more?</h1>
<p>Want to check out this sample yourself? Head over to <a href="https://github.com/robertsimmons/DesignPatternSamples/tree/master/AdapterPattern" target="_blank">gitHub</a>!</p>
<p>If you want more information on design patterns, I cannot recommend the <a href="http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124">Head First Design Patterns book</a> enough. It’s the best down-to-earth book, to really help you learn not only the pattern, but help identify <em>when</em> to apply them. It’s like “Design Patterns for Dummies” – hell, if I can understand it, anyone can!</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-71964171394590447642010-10-06T21:05:00.001-05:002010-10-06T21:05:12.804-05:00When Scrum doesn’t seem to work<p>I consider myself an Agile prophet. By this, I just mean that I preach about the benefits of doing Agile software over old standards like Waterfall. There are various Agile implementations, and my favorite is Scrum. Granted, I haven’t tried any other Agile implementations in-depth other than Scrum, but I’ve had Scrum transform my life from misery to a blessing.</p> <p>I’ve been at my current job for a year, doing Scrum, and the team has kicked ass. The software has a high quality. It gets out on time. Best thing of all? Both of those are accomplished <strong>without</strong> any significant overtime! Ideally, you’d have no overtime, but what I’m referring to here is maybe 20 hours of overtime over the past <em>year</em>. I know many devs who work that much overtime every week, and few devs who don’t put in that much overtime in a month. So, a process that gets predictability down to that close within a typical 40 hour work week is just amazing.</p> <p>However, the past month have seen some changes to the team, and the work we’re doing. And we’re wrapping up our second sprint in a row where we’re going to have to pull stories (not counting those that are road-blocked by external forces). The gut initial reaction is “Oh man Scrum doesn’t work in this case, see!” but further introspection shows that we’ve lost sight of how to handle things. So I’m going to list out some things that can cause a high-performing Scrum team to go off track suddenly, as well as some other things I’ve noticed other places that have stopped Scrum from being successful.</p> <h1> </h1> <h1>You have to have top-to-bottom buy in</h1> <p>This is, by far, the reason I’ve seen most Scrum attempts fail. The company I’m at has top-to-bottom buy in. The developers, QA, SCM, managers, product owners, executive team – EVERYONE is on board. If you do <em>not</em> have <em>complete and total</em> buy in, your Scrum attempt is severely at risk. A big part of Agile is getting the client (whether that’s the actual client, or an internal product owner) involved into the software process. That visibility into the software process is crucial to bring understanding to all members involved in the software’s creation with the realities of what it takes to deliver software. If your managers want to back-into dates, instead of them being derived from release buckets consisting of prioritized features, you’re at risk of being driven off track, to cut corners on quality, and to work overtime. If your client wants to give you a big 500 page document of barely-thought-out requirements, then not talk to you for six months, you’re at risk of giving them garbage, or, more than likely, not really having a clue of the true needed requirements, yet you’ve agreed to a due date already.</p> <p>Simply put – everyone involved in the software has to be part, and to stick to it.</p> <h1> </h1> <h1>You have to keep asking questions until you can’t ask more questions (don’t make assumptions)</h1> <p>Our team changed from working on a well-known area, to something new. Having high confidence from the work we’ve been doing the previous year, combined with excitement of something new, unfortunately lead us to all take assumptions. The end result? We point sized based on how something similar would have ran in the previous area. Granted – you use past experience to point size (obviously). That’s part of it. But we could’ve done a more in-depth analysis of the new work. Not doing that extra analysis lead to constant discovery of new “uh oh”s throughout the story work.</p> <p>So ask questions. If you can’t get answers? Don’t point-size. If you need to do more of your own analysis first? Don’t point-size. There’s a happy balance here – you can’t spend a solid week investigating a story, when you could’ve implemented it in that time. Each story will have to be considered on a case-by-case basis, and if it’s truly unknown, create a Spike for it.</p> <p>The easiest way for me to accomplish this, is to pretend that I’m starting on the story <em>right then</em>. Where would I start? What would I do first? Then what would I do? Chances are, you’ll find yourself with questions pretty soon. And don’t trust assumptions! Ask your product owner. After all, he/she is right there in the grooming session with you.</p> <p>The goal here is to drive out as much unknown that is reasonable from a story before starting work on it. If your point size of a story is based more on unknown than on amount of work, then that story becomes a high-risk ticking time bomb, ready to explode on you mid-sprint. And when you pull in two or three like this? Then you’re really in trouble. You can’t give your product owner reliability/predictability, at which point your reputation goes down.</p> <h1> </h1> <h1>Break the story down. Then break it down again. Then? Yet again!</h1> <p>Our previous team and work had become a well oiled machine. We could take in a couple of 8s and a 13 in one sprint and knock it out. But those higher point sizes were driven from work to do – not unknown. Now we have new team members, doing new work – you have to get a new baseline to determine velocity. Large stories do not help you deliver a reliable velocity. If you pull an 8 point story, chances are you had 3-5 points worth of work done. You’ll finish it next sprint, sure – but now you have a large discrepancy between sprint 1 and sprint 2’s velocity. Yes, it’ll wash-out in the end, but it makes for a rougher start.</p> <p>So, break down stories. It’ll feel mind-numbing. It’ll feel tedious. But high confidence and the ability to work larger stories reliably comes as a reward for doing things more in-depth earlier. If you can find a clear vertical slice to break it down more, then you should do so. Make it simpler. Drive out unknown/risk from the story. The smaller you have to implement to succeed, the higher your chance of success is. You’ll get the 3 or 5 points of what was once a bigger story done, even if you have another 3-5 in it’s “sister” story that gets pulled. But you’ve delivered more to your product owner. You have less to think about next sprint. And, you’re closer to honing in to your team’s velocity.</p> <h1> </h1> <h1>tl;dr</h1> <p>Upon review, all this stuff is so basic. But you get used to things flowing well, and sometimes you loose sight of the bigger picture. So, in summary:</p> <ul> <li>Everyone must be involved and committed to the process</li> <li>Drive out requirements as thoroughly as is reasonable</li> <li>Break down stories into small pieces – 1-3 pointers are optimal, some 5s are okay. Stay away from 8s and 13s.</li> </ul> Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2430856949934117881.post-15823658280319593062010-08-10T08:01:00.001-05:002010-08-10T08:01:42.083-05:00TeamCity, dedicated build server, and MVC2<p>Just a quick “gotcha” I ran into. For whatever reason, the standalone .NET 4.0 installation does not contain MVC bits. You only get them by installing Visual Studio 2010 itself. Why Microsoft continues to do this is beyond me (they also do it with certain web copy/publish MSBuild targets). I’m about to explode with nerd-rage at this nonsense, so I’ll quickly move on to the solution.</p> <p>Since you aren’t likely to install Visual Studio on your webserver, the easy solution there is just to make the reference to System.Web.Mvc set to Copy Local. Easy enough work-around. On your build server however, that won’t do any good, because it’s not in source control. What you’ll have to do is either copy the DLL to your build server manually at the path referenced in your project, so your build server can find it, or copy it to your solution as an external reference, add it to source control, and reference it in your project from where you added it as an external reference in your solution. This is the option I took, that way we can have more build agents in the future without having to remember “oh yeah” for each machine.</p> <p>Seriously, what the hell, Microsoft? Quit making shit look like it’s part of the f’in framework when it isn’t.</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-80037606160938782992010-07-23T23:30:00.001-05:002010-07-23T23:30:23.045-05:00Exceptions? Errors? In my app_offline.htm? (Gotchas and tips!)<p>So, app_offline.htm isn’t a fullproof as we’d like. But just to catch up a few people who might be lost already…</p> <p><strong><u>What is it? How does it work?</u></strong></p> <p>The general idea is that you make a plain-jane html file, name it app_offline.htm, and drop it in the root directory of your ASP.NET website in IIS. IIS automagically knows that if it sees this file, that it should serve it for ALL requests. That way, when you’re doing maintenance, you can have a nice pretty message instead of an application in flux. Great idea right? Yes, it is! Too bad it doesn’t work 100% straightforward that way.</p> <p>My current <em>understanding </em>(as in, probably wrong) is that IIS only checks for this when serving up ASP.NET content. Which I guess means that IIS isn’t actually doing it at all, but some ASP.NET framework gobbledegook is at some point. This has some pretty serious differences, the two I’ve ran into being that it’s not going to do this for static content requests, and that you have to actually get ASP.NET loaded before this file can be served.</p> <p><strong><u>Why I’m running into it</u></strong></p> <p>I’ve been working on automated build and deployment scripts for some website applications at work. I have it plugged into our CI server, and we do a lot of QA and UA on the destination environments (note: UA at this stage is done by our internal Product Owner, not an outside client). Since those environments will obviously get messed with whenever we check-in code changes, showing them a nice “under maintenance” to let them know what’s up is a good idea. They know how these servers work, but at least this way they don’t think they uncovered some bug that caused the site to start throwing errors.</p> <p>We cranked out a quick app_offline.htm, and I worked it into the deploy script. The deployment script works in these steps:</p> <ol> <li>Copy over the app_offline.htm</li> <li>Delete everything else in the virtual directory (this is done so old pages/usercontrols/files/css/image/etc don’t stay around)</li> <li>Copy over the new build</li> <li>Delete app_offline.htm</li> </ol> <p>However, when trying to access the site during this, most of the time you’d just get exceptions. WOW THAT’S WORKING GREAT!</p> <p><strong><u>How to avoid issues</u></strong></p> <p>First off – since the app_offline.htm done by the ASP.NET framework, it still has to be able to complete initialization. What this means is that if you have a global.asax defined in your web application (and you probably do), it still has to be able to load properly. And if you’re deleting your /bin/ folder before global.asax, then your global.asax can’t finish loading. BAM! Exceptions. This also is important when copying items back over. So, I modified my scripts to delete global.asax FIRST, then everything else. When I’m copying the new build over, I copy /bin/ first, then everything else.</p> <p>But there’s more!</p> <p>You’re probably also using a default document. Default.aspx is the one that’s probably actually in your project. If your site’s home page doesn’t have a specific actual page (like 99% of websites), users could just be on <a href="http://mysite.com/">http://mysite.com/</a>, and get the “Virtual listing not denied”. Why? Because you’ve deleted Default.aspx, so the ASP.NET processing isn’t happening, so your user gets the “virtual listing not allowed” error. You could add app_offline.htm to the default document rule, but that’s kind of crappy. The real solution here is not to delete Default.aspx. Instead, just copy over it.</p> <p><strong><u>My final deployment process</u></strong></p> <p>So, now it looks like this:</p> <li>Copy over the app_offline.htm</li> <li>Delete global.asax</li> <li>Delete everything but Default.aspx and web.config (I know those files will ALWAYS exist – so I’m still cleaning out old garbage, but not getting nasty errors)</li> <li>Copy over new /bin/ contents</li> <li>Copy over the rest of the new build</li> <li>Delete app_offline.htm</li> <p>And now I’ve greatly reduced the change for a user to get nasty errors. Why only greatly reduced? Because if they were trying to get to static content, they’ll STILL get 404 (if the old file hasn’t been copied over yet), since the ASP.NET framework isn’t invoked. The solution for that? IIS7 and the integrated pipeline. You’ll want to add this to your web.config:</p> <pre class="csharpcode"><?xml version=<span class="str">"1.0"</span>?>
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests=<span class="str">"true"</span> />
</system.webServer>
</configuration></pre>
<p>Which is just yet another reason to only copy over your web.config, and not delete it. This setting tells IIS now that ANY requests in this virtual directory should fire the ASP.NET pipeline. However, our servers are IIS6, so we cannot take use of this feature. It’s low risk for us, so it’s not a large deal, but for those of you using IIS7 this is a nice thing to add, especially if you’re using MVC since none of your URLs directly link to an aspx page anyways.</p>
<p>Hope you find this information useful!</p> Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2430856949934117881.post-86497907136706431862010-07-11T18:05:00.001-05:002010-07-11T18:05:09.098-05:00Accessing custom data interfaces in ASP.NET WebForms<p>Yeah, this is a pain.</p> <p>So, you want to use “out of the box” controls like a listview, or gridview, etc. You have a custom interface for getting your data, let’s say something like:</p> <pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">interface</span> IGetData
{
IEnumerable<MyData> GetAll(<span class="kwrd">int</span> pageSize, <span class="kwrd">int</span> page, <span class="kwrd">string</span> sort);
}</pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> MyPage : Page
{
<span class="kwrd">public</span> IGetData MyData {get;set;}
}</pre>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style><style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>That’s a pretty basic interface. You have a large database, and you need to very specifically control how paging and sorting is done (no returning everything, and sorting in memory, especially). Unfortunately, if you want to display that information with the standard webform controls, you will run into MANY issues. All your sort/paging commands will be jacked up, and attempts at manually setting what page number you’re on will leave you smashing your head into a wall. A wall with spikes (hooray for read-only properties…).</p>
<p><em>(To be honest here, I tackled this nonsense a few months back, and don’t remember the specifics of the trouble I ran into, so feel free to try it anyways!)</em></p>
<p>The way ASP.NET wants you to do it, is to have your (let’s say ListView) point to an object datasource. After fighting these things, I can say that object datasources are complete garbage. But, here we are anyways. Here’s what you’ll need to do to get it work correctly.</p>
<p>You’ll create your ListView, and your ObjectDatasource. Have your ListView’s DataSourceID set to the name of your ObjectDatasource. Then you’ll set various properties on the datasource for what functions to call at certain events. The overall way how the ObjectDatasource is going to work? It’s going to create <strong><em>it’s own f’in instance</em></strong> of your control/page, and call those functions. Yes. You heard me correctly. That means any controls/data on your page are <strong>USELESS</strong>. Since your ObjectDatasource has it’s own instance, those values won’t exist. Awesome, right! So how do we set this up anyways? Like so…</p>
<p>On your ObjectDatasource, you’ll want to set the following properties: </p>
<ul>
<li>MaximumRowsParameterName, SortParameterName, StartRowIndexParameterName – These are optional. If set, when the ObjectDatasource uses reflection to search for it’s select function, it’ll look for parameters with those names.</li>
<li>SelectMethod – A name of a function in your codebehind, that has parameters equal to what you have set (in markup or codebehind) to your SelectParameters as well as the parameters listed above</li>
<li>SelectCountMethod – Function with the same parameters as SelectMethod, minus paging and sorting parameters.</li>
<li>TypeName – FQDN of your page or control</li>
<li>EnablePaging – Set to true if paging is enabled. Obvious at least.</li>
<li>OnObjectCreated – This is the bastard one. This is an event that you’ll want to wire into.</li>
</ul>
<p>So, we’ve set up our ListView and set up our ObjectDatasource with a bunch of functions that don’t do anything. The first thing that you’ll notice is a different function for Select and SelectCount. We don’t want to actually have to search our database twice. The good news is that Select is called first, so I made a tiny custom object to hold the records we’re going to show, as well as the total count. I modified my interface to return this object instead, as well.</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> DataControlResults<T>
{
<span class="kwrd">public</span> IEnumerable<T> Data { get; set; }
<span class="kwrd">public</span> <span class="kwrd">int</span> TotalRecords { get; set; }
}</pre>
<p>Now, we, can make a private field on our page (let’s define it as “private int _totalRecords”), and we call our Select method, we’ll store it.</p>
<pre class="csharpcode"><span class="kwrd">public</span> List<MyData> dsItems_Select(<span class="kwrd">int</span> pageSize, <span class="kwrd">int</span> startRow, <span class="kwrd">string</span> sortColumn)
{
var results = MyData.GetAll(pageSize, (<span class="kwrd">int</span>)(startRow/pageSize + 1), sortColumn);
var listData = <span class="kwrd">new</span> List<MyData>();
listData.AddRange(results.Data);
_totalRecords = results.TotalRecords;
<span class="kwrd">return</span> listData;
}</pre>
<p>Again, unfortunately, we have to do a little wonkiness with the paging. I prefer page and pageSize, but the data source uses starting row and page size. Oh well.</p>
<p>Now, our SelectCount just returns _totalRecords, so easy enough there that I can skip formatting code!</p>
<p>However, if you, like most people, are using a DI/IoC framework, your actual concrete implementation of your interface will be null! Most frameworks, when in the ASP.NET world, are instantiating those properties in your global.asax, or perhaps a custom Page base control, etc. Because the ObjectDatasource, though, is creating a copy of your page/control through Activator.CreateInstance, that’s all gone! SWEET! (That’s sarcasm, by the way.) So, that’s where the OnObjectCreated event is used.</p>
<pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">void</span> dsItems_ObjectCreated(<span class="kwrd">object</span> sender, ObjectDataSourceEventArgs e)
{
var newObj = e.ObjectInstance <span class="kwrd">as</span> MyPage
newObj.MyData = MyData;
}</pre>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>There ya go, now it’ll actually have a facade to use. Sigh.</p>
<p>At the end of the day, it works pretty simply, but I originally just wanted to throw up a ListView control, capture the paging/sorting events from the ListView (triggered from Commands from objects displayed in the ListView), and manually call my facade with proper paging/sorting/search parameters as needed. Then I’d just bind the results to the ListView.DataSource property, and be set. But that really just isn’t how they intend on you using these controls. They really want you to use some DataSource control, which unfortunately adds nothing but more noise to your markup and code-behind. If you want to have Updates and such as well, it’s the same pattern again.</p>
<p>Hopefully this approach can help someone else who wants control over their data access in their webform project! Thank god our next project is MVC!</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-50768556034397077232010-01-23T14:39:00.001-06:002010-01-23T14:40:31.667-06:00Story points only for things that provide business value<p>This was an idea that recently came up during training. One of the large values of using Scrum is the visibility it can provide to the rest of the business organization – clients, product owners, managers, etc. It helps plainly set out what the team can handle, and identify issues that are preventing features from getting done.</p> <p>As a team gets it’s velocity defined, it may be beneficial to not assign story points to stories in an iteration related to working on legacy systems, production issues, long-standing (or recurring) bugs/defects, or things that in general derive from various forms of “technical debt”. Many managers (or product owners, etc), especially the more teams they have to track, will usually not take the time to really investigate why a team may be having troubles, and making the issues more obvious (such as a low velocity) may be a way to help clearly signal them there are issues that need to be addressed. After given the “green light” to tackle some technical debt, future iterations would see an increased velocity.</p> <p>On the other hand, you’d still probably need to story point those “non-business value” stories, because you will still want to track when they’ll be resolved, and to be able to include them in releases. Perhaps you’d run multiple iterations in parallel – one for business value, one for everything else, and assign velocity independently. Of course, that has the overhead of managing two parallel iterations, which might be problematic depending on your Scrum tracking methods.</p> <p>I think it’s an interesting idea that has some merit, but still has some kinks. I like the principals behind it, just not sure how it’s best to proceed with it.</p> Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-2430856949934117881.post-41145424013065701032010-01-15T23:04:00.001-06:002010-01-15T23:04:31.771-06:00Does the .NET community need an attitude change?<p>Maybe it’s just me. Maybe my perceptions are skewed for some reason or another. It’d be nice. And no, this is not an “Evil Rob” post.</p> <p>It seems to me that the .NET community is becoming more and more of a popularity contest. A person’s ability to “play around” with new technology, and blog/twitter/whatever a lot about it seems to be more important than providing actual working solutions. I really hope that’s not the case. Developers should be able to get job based on their ability to provide <strong>business value</strong> to the client, in whatever form that may be – which is unlikely to be by making small demos or “widgets” of functionality.</p> <p>It seems that unless you’re working with the latest and greatest technology, that any work you’re doing is useless, and you’re a subpar developer. It seems that cliques and an elitist mentality are emerging, which is unavoidable, but there’s a chance it’s becoming the prominent (or at least prominent enough) mentality in our community. Instead of being a community focused on sharing knowledge, it’s more of a one-ups-manship contest.</p> <p>The reason all this is coming to a head, is because I’d like to blog about the work I’m doing. I found myself thinking “Man, no one cares about this.”, and “Eh it’s webforms, I don’t want to catch flack for it”. Then it occurred to me that there’s no way I’m the only developer out there still dealing with a legacy webforms app, that will be facing the same challenges I have. Maintenance is a large part of what we do, and something we should always plan for. So it’s always good to know about how to make those old apps easier to work with, or to fix that random bug that pops up in software no one has looked at in a year.</p> <p>By the same point, we definitely need people blogging and trying out new things with the new tech. I know that for myself, and surely many others, a lot of the enjoyment comes from facing challenges, and finding new, efficient, and interesting ways to overcome them. Without checking out the new stuff, we’d be stuck in a rut.</p> <p>So it all matters. New stuff matters. Old stuff matters. And it’s important that we keep a good balance with everything, so we can accept and all grow together as a community, and not become a circle-jerk of assholes.</p> <p>I should also take this time to say that this is NOT an attack on any one (or group) of people. I’m not saying that “popular” people in the community are not (or can not) be competent developers producing fully functional software. This has just been my perception of how things have trended over the past couple of years. I really, really, REALLY hope I’m wrong.</p> <p>With all this said, I plan on blogging about what I’m actually doing more. I’m also very lazy, so if it doesn’t happen, it’s not because I became shy again.</p> <p>So please leave me some comments! Am I way off of my rocker here? Am I insecure because my mommy didn’t hold me when I was a child and my vagina is full of sand? Or did I hit on a few nuggets of truth?</p> Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-2430856949934117881.post-23542682886042646262009-12-04T10:40:00.001-06:002009-12-04T10:40:56.223-06:00Software developers aren’t freakin’ construction crews<p>I swear, if I hear that damn “designing software is like building a house” analogy again, I’m going to shoot someone in the face (probably myself).</p> <p>Software is organic. It evolves. It changes. When you build a house, it’s set in stone – literally. All the floors depend on one another and build on one another. You can’t radically change one below it without disrupting those above it. If you’re designing your software to be like a house is built – you are doing it <strong><em>WRONG.</em></strong> Your software shouldn’t be so rigid and brittle that it’s a great pyramid of dependencies, and changing one thing brings the whole thing crumbling down. We have methodologies and technologies to keep us from doing that exact problem – and they’re not new! They’ve been around for a decade or more. Coping with and <strong>embracing</strong> change is exactly what good software is about. The only constant in software you can rely on is that things will need to be changed. If you’re designing your software so that it can’t meet that requirement, then it fails at it’s most fundamental level.</p> <p>If you still don’t agree with me, google some of these terms: Dependency Inversion (also known as Inversion of Control) (DI / IoC), Agile software, Single Responsibility Principal (SRP), Open-Closed Principle (OCP), Liskov Substitution Principle (LSP), or just buy (and read) this book – <a href="http://www.amazon.com/Software-Development-Principles-Patterns-Practices/dp/0135974445">Agile Software by Robert Martin</a>.</p> <p>That’s not to say that you can write software that will be able to gracefully handle every change ever. You can’t (not without an unlimited budget/time that is, which doesn’t exist in The Real World). But most business domains have areas that are more volatile than others, and you can reasonably predict which areas you need to be more careful and purposeful when adhering to proper software design principles. You want to be able to say that you can handle most changes and refactoring easily, but sometimes things will require change in an unexpected way. So you implement those changes, and adjust your architecture to adhere to similar changes of that nature in the future. That’s why we, as software developers, get paid what we get paid – to learn from our mistakes, to improve our practices, and help provide more business value in the future by providing the ability to handle owner’s requests more efficiently. When a change request / new feature comes down the pipe that we didn’t anticipate, we explain to them the cost (time/money/effort/resources) to handle that request, and we do it just like we do any other work. We don’t bitch and moan that doing our job is hard because we fucked up the initial design, or to whine about how software is exactly like masonry work.</p> <p>Maybe no one uses that analogy anymore, everyone agrees with me, and I’m overreacting. But I did just see it again the other day. Maybe that’s the freak occurrence though? I hope so.</p> Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-2430856949934117881.post-81067490221883944832009-11-16T17:48:00.001-06:002009-11-16T17:48:58.388-06:00Quick Resource Helper Class<p>The production app I’m currently working on involves reading a client-provided extract (on the magnitude of hundreds of thousands of lines), transforming that data, and importing it into our system for processing. This happens once a day. The current process involves importing this information into staging tables on the DB side, then running stored procedures to transform the data. </p> <p>As part of an effort to both improve efficiency as well as add in scalability, the DB team has decided this process should import into session-level temporary tables. This will allow multiple imports to go on at once if need be, as well as give some performance enhancements. The software side of this requires that the importing software opens a connection, and then creates the temporary tables on that connection. From there, the software reads the client-provided extract in about one thousand lines batches, and uses SqlBulkCopy to transfer it to SQL server.</p> <p>Most of the architecture in this problem was laid out already, and not having any previous experience dealing with data sets this large, I followed the rest of the team’s leads. The temporary table creation needed to be done on the software side, and the scripts themselves needed to be part of the project. Not wanting to rely on folder paths to read in the data, and really not wanting to have string variables that held the scripts, I opted to leave the scripts intact, but use them as embedded resources. I haven’t worked with embedded resources before, honestly, so I did find out a couple of things.</p> <p>The main call you’ll need is:</p><pre class="csharpcode">Assembly.GetAssembly(yourAssembly).GetManifestResourceStream(fullResourceName)</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<p>The tricky thing can be the file path. It uses periods to denote folder paths to load your project. Not difficult, but not the most obvious thing either. I wanted to “hide” that from my consuming apps, as they really don’t care about how the resource accessor likes to make it’s names. They just want their file. They do know about the project structure of the assembly that has their resource, however.</p>
<p>The next thing that I accidentally did wrong was the assembly – you need to provide the assembly that the resource lives in, for obvious reasons. Given that this helper class lives in a “Utilities” type of project, it’s no shock that as soon as I refactored my class out, my tests broke.</p>
<p>So, with those two thoughts in mind, here’s the API I wound up with, along with the full class:</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">class</span> ResourceHelper
{
<span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">string</span> GetResourceAsString(Type typeOfCallingObject, <span class="kwrd">string</span> namespaceName, <span class="kwrd">string</span> fileName)
{
<span class="kwrd">return</span> GetResourceAsString(typeOfCallingObject, <span class="kwrd">string</span>.Format(<span class="str">"{0}.{1}"</span>, namespaceName, fileName));
}
<span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">string</span> GetResourceAsString(Type typeOfCallingObject, <span class="kwrd">string</span> namespaceName, <span class="kwrd">string</span> folderName, <span class="kwrd">string</span> fileName)
{
<span class="kwrd">return</span> GetResourceAsString(typeOfCallingObject, <span class="kwrd">string</span>.Format(<span class="str">"{0}.{1}.{2}"</span>, namespaceName, folderName, fileName));
}
<span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">string</span> GetResourceAsString(Type typeOfCallingObject, <span class="kwrd">string</span> namespaceName, <span class="kwrd">string</span>[] folderPaths, <span class="kwrd">string</span> fileName)
{
var fullFolderPath = <span class="kwrd">new</span> StringBuilder();
<span class="kwrd">if</span>(folderPaths != <span class="kwrd">null</span> && folderPaths.Count() > 0)
{
<span class="kwrd">foreach</span> (var folderPath <span class="kwrd">in</span> folderPaths)
{
fullFolderPath.AppendFormat(<span class="str">"{0}."</span>, folderPath);
}
<span class="rem">// Remove the trailing period</span>
fullFolderPath.Remove(fullFolderPath.Length -1, 1);
}
<span class="kwrd">return</span> GetResourceAsString(typeOfCallingObject, <span class="kwrd">string</span>.Format(<span class="str">"{0}.{1}.{2}"</span>, namespaceName, fullFolderPath, fileName));
}
<span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">string</span> GetResourceAsString(Type typeOfCallingObject, <span class="kwrd">string</span> fullResourceName)
{
var fileStream = Assembly.GetAssembly(typeOfCallingObject).GetManifestResourceStream(fullResourceName);
<span class="kwrd">if</span> (fileStream == <span class="kwrd">null</span>)
{
<span class="kwrd">throw</span> <span class="kwrd">new</span> Exception(<span class="kwrd">string</span>.Format(<span class="str">"Resource '{0}' not found!"</span>, fullResourceName));
}
var sqlStreamReader = <span class="kwrd">new</span> StreamReader(fileStream);
<span class="kwrd">return</span> sqlStreamReader.ReadToEnd();
}
}</pre>
<p>
<style type="text/css">.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
</p>
<p>Note that most times, the first parameter is liable to just be “GetType()”. I could’ve maybe made it an extension method, or made the type a generic parameter, but it really felt like overkill for such a small class. Here’s some examples of calling it (from my unit tests):</p><pre class="csharpcode">ResourceHelper.GetResourceAsString(GetType(), <span class="str">"UtilitiesTests.RootResource.txt"</span>);
ResourceHelper.GetResourceAsString(GetType(), <span class="str">"UtilitiesTests"</span>, <span class="str">"RootResource.txt"</span>);
ResourceHelper.GetResourceAsString(GetType(), <span class="str">"UtilitiesTests"</span>, <span class="str">"ResourcesFolder"</span>, <span class="str">"FolderResource.txt"</span>);</pre><pre class="csharpcode">ResourceHelper.GetResourceAsString(GetType(), <span class="str">"UtilitiesTests"</span>, <span class="kwrd">new</span>[] { <span class="str">"ResourcesFolder"</span> }, <span class="str">"FolderResource.txt"</span>);
ResourceHelper.GetResourceAsString(GetType(), <span class="str">"UtilitiesTests"</span>, <span class="kwrd">new</span>[] { <span class="str">"ResourcesFolder"</span>, <span class="str">"NestedFolder"</span> }, <span class="str">"NestedResource.txt"</span>);</pre><pre class="csharpcode"> </pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<style type="text/css">.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<p>Yeah, this is all extremely basic, but thought it still might be useful for someone. I had fun doing it, none-the-less.</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-7716408786148497052009-10-30T19:14:00.001-05:002009-11-03T09:02:05.254-06:00New job, new challenges!<p>I know. It’s crazy. I had been dissatisfied with my old position for an extremely long time, and it eventually came to a boiling point, leading me to switch jobs in the middle of <strong>THE RECESSION!!! ZOMGS!!!!!</strong></p> <p>Things worked out amazingly, though. I had my new job before my severance even ran out. Nothing like getting paid to <strike>nurse my crack addiction</strike> play World of Warcraft.</p> <p>I’m the start of what is basically a new team. I’ve been here a little over 3 weeks now. The previous team consisted of a single developer, who has been here for about eight years. He’s moving to more of a management position, while me and another developer (a Web/UI focused developer) will be working for him. There’s also 2 DBAs that we work closely with, but aren’t <em>technically</em> on this team. We steal a lot of their time though.</p> <p>My role is “Senior .NET Software Engineer”. What do they mean by “Engineer” exactly, you ask? Well, that’s a good question that took me a bit to find out myself. I think I can explain it best by thinking of what an engineer by any definition really does – <em>makes things work!</em> My job is to make it work, however I feel that should be accomplished. My boss helps critique my proposed solutions, typically by giving me information about how many of the external systems interact with what I’m working on. That’s where a lot of the complexity is currently. The company deals with the health care supply chain. Not only is it my first foray into the health care arena, which is complex in and of itself, but the supply chain has many unique factors and forces at play at the same time. It’s a lot to take in. I’m finally getting a good base grounding (although not very in-depth yet) of how the entire system works.</p> <p>My current “day-to-day” focus involves refactoring an existing system made for a single client to make it extendable for the second client it needs to support. I’m finally getting a chance to put to use a lot of the great information I had read recently. The code is pretty straight forward, so while it’s not hard to understand what it’s doing, it’s very hard to break up and make extendable. I’ve been referencing <a href="http://www.amazon.com/Software-Development-Principles-Patterns-Practices/dp/0135974445">some</a> <a href="http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124">books</a> pretty frequently to help me make the right decisions, however, and I’m excited about how it’s turning out. My boss is liking my work as well (which is very important to the checkbook).</p> <p>The work here is also extremely data heavy. Collecting and processing the data is a huge concern. Working with tables that contain millions of records, and importing, exporting, and converting them. So I’m learning a lot of information about how to write efficient SQL and designing secure databases.</p> <p>On top of that, the company is fully committed to doing Scrum in a proper fashion. That’s great – but of course, each company will have it’s own “spin” on it. This is an extremely large company, and we’re actually a remote office, so it involves a lot of phone conferencing. So that’s been another challenge to learn how to work with properly.</p> <p>All in all, however, this is going pretty great. The work is challenging. It’s a new business domain, which is a great change of pace, if nothing else. I’m being allowed to propose architecture improvements, and implement them. My boss is committed to making sure we have good hardware and the latest development tools. He’s also always looking to the future – we want to wrap up the current project, then move on to the next. Then the next. Then the next.</p> <p>So, I hope to blog a little here and there about what I’m doing. I figure most people will find it mind-numbingly boring or introductory. Hopefully not though. A lot of it will be difficult to explain or may not make sense. We’ll see how it goes.</p> <p>Oh, and a freaking huge 11.5% raise. It was over the top end of the range I was asking for. And a bonus plan that actually pays about 10% of your salary a year (and yes, people actually get their bonus). Take that recession!</p> Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-2430856949934117881.post-8518878111458444402009-09-14T12:54:00.001-05:002009-09-14T12:54:30.724-05:00Keeping scroll position between redirects<p>Had need of this on a project, and while I thought it’d be a large hassle, <a href="http://elijahmanor.com/">Elijah Manor</a> was able to point me to a very simple to us javascript to do it – <a href="http://en.hasheminezhad.com/scrollsaver">Scrollsaver</a>.</p> <p>All you do is include it, and it does the rest. It uses a cookie and an ID of your element to keep track of your last position. Very nice!</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-58027292054258220422009-05-07T11:05:00.001-05:002009-05-07T13:37:10.171-05:00Silverlight – YOUR WORLD IS OVER<p>So, Sliveright THREE is in beta now, and it’s set to take over the entire web! If your site isn’t made in Silverlight, guess what? IT SUCKS. IT COMPLETLEY FAILS AS A WEBSITE. PERIOD.</p> <p>This site? SUCKS.</p> <p>Amazon.com? SUCKS.</p> <p>eBay? SUCKS.</p> <p>Google? SUCKS</p> <p>“You’re obviously right, Rob. But I can’t put my finger on why you’re so right! Please tell me!”</p> <p>Okay, I’ll tell you. But you keep your filthy fingers away from me. You sound poor, and I don’t like it when poor people touch me.</p> <h1> </h1> <h1>Gradients</h1> <p>You can make gradients with it. HOT. SHIT. You might have THOUGHT you could make gradients before, but guess what? YOU DIDN’T. NOW you can finally make them.</p> <p>I know, you really did think you were making gradients with Photoshop or Paint.NET or something, and using them on your site, but you didn’t. You just made colors. They were garish and horrible.</p> <p>And you certainly didn’t make a single grayscale transparent gradient, then use CSS to set that as the background image with a background color so you could have multiple gradients from image. Nope, you’ve never done that.</p> <p>See, all those would be way too much work and time investment. Why open up image software, and make a gradient in 3 or 4 clicks? Now you can open up Blend, and make a REAL GRADIENT WITH XAML in 3 or 4 clicks! </p> <p>So, now you can finally create gradients. You’re on your way to being a real developer. Right now there is only one real developer in the world, me, because I’m the only one who’s used gradients in Silverlight.</p> <p>But why are they good? Because the world is nothing but ONE BIG GRADIENT. Next time you’re in the bathroom, and you feel your insides explode and issue forth an eruption of epic proportions, take a look at what you see – it’s JUST like a gradient. It’s not one solid color. It’s a rainbow, softly blending from one color to the next. Just like Silverlight!</p> <h1> </h1> <h1>Animations </h1> <p>You can FINALLY animate stuff! I know, once again, you THOUGHT you animated stuff before. </p> <p>BUT.</p> <p>YOU.</p> <p>DIDN’T.</p> <p>“Pretty sure I use jQuery to easily animate some stuff.”</p> <p>Listen, I don’t know what jQuery is, so it doesn’t exist. Got it? It was never possible to animate UI before.</p> <p>“Well, pretty sure I used Flash to animate a site like a decade ago.”</p> <p>Will you quit making shit up? I’ve never used Flash either, so I’m pretty sure it doesn’t exist either. </p> <p>Finally, with Silverlight, using Blend, you can make animations! It uses this great thing that the Silverlight team invented, called a storyboard, which consists of timelines, that have keyframes! It’s pretty simple!</p> <p> </p> <h1>Hover effects</h1> <p>This is a bit of a combination of Gradients and Animations (capitalized because they’re so important)! Now, when a user hovers over important things, like menu items, you can give a subtle gradient to pop into place to let the user know they’re over something sensitive!</p> <p>“That’s been possible with CSS for yea—“</p> <p>SHUT UP!</p> <p>“I could do it with javascript even longer than t—“</p> <p>WHAT PART OF SHUT UP ARE YOU MISSING?! YOU COULD NEVER HAVE A HOVER EFFECT FOR A WEBSITE BEFORE SILVERLIGHT!!!! SHUT THE HELL UP!!!!!</p> <p> </p> <h1>It’s one huge ass object</h1> <h1></h1> <p>Well, I know FOR A FACT this one is new! Silverlight is now one single element on the page! This is super great, and really where Silverlight shines. </p> <p>This really makes it, finally, the perfect solution for public sites. I mean, who needs that “web” crap. Now, it’s one solid object. You no longer have to worry about your public site being pilfered by nasty search spiders. I don’t even know what those are, but they’re called spiders, so I assume they have eight legs and crawl all over you. I have enough night terrors about them as it is.</p> <p>Plus, people now can’t link to somewhere deep in your site. I hate it when people link to direct portions of my site, and skip all my advertisements or cool pictures of myself or something. Now, they have to see all that EVERY TIME. Hell yes.</p> <p>Also, you can’t copy & paste my text now, jerks! You’re just going to have to paraphrase it. I’ll get you started: </p> <p>“Then Rob was awesome”.</p> <p>Done.</p> <p>“Uh, I made sites entirely in Flash a decade ago, and it was a horrible idea, and that’s why only marketing sites do it now, You see—“</p> <p>I’M GOING TO SHOTGUN YOU IN THE FACE. I’M BUSY TALKING ABOUT HOW <a href="http://thedailywtf.com/articles/the_brillant_paula_bean.aspx">BRILLANT</a> SILVERLIGHT IS, AND HOW EVERYTHING IT DOES IS COMPLETLEY NEW AND BETTER THAN ANYTHING THAT EXISTED FOR THE WEB BEFORE, EVEN THOUGH I’M PURPOSEFULLY IGNORANT OF ANY AND ALL WEB TECHNOLOGY!!!</p> <p> </p> <h1>The Bad Stuff</h1> <p>Well, the main bad stuff is that all these non-Silverlight websites haven’t been converted yet. Hopefully soon browsers will support xaml natively. At least the <a href="http://www.microsoft.com/windows/Internet-explorer/default.aspx">One True Browser</a> should do it soon.</p> <p>But there’s really one thing wrong with it:</p> <p><strong>Case Sensitivity</strong>. Seriously. WTF. How freaking retarded is that. I mean, in this day and Age, why is ANYThinG case Sensitive? i can’T think WHY it would Matter at alL. AnD whiLE I’M on tHiS subJecT, I shOUlnD’t hAve to spEll thINGs correCTly eiTheR. it shouLd havE a DictIOnaRy of poSSiBle ValUEs, aND pIck teH nErEst wRd B-Cuz e dUn hAf tIm oR sKil 2 lErn al tHeeS wurDz i meN u nO hw eT s wHN u gTz so Mny wRd tt its impsB fr tO sTp fern rEd F dgeR DqoeR gler!!!!!</p> Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-2430856949934117881.post-86918111823645894022009-04-21T08:56:00.001-05:002009-04-21T08:56:06.627-05:00Google hates IE<p>And therefore, I hate Chrome a little less. </p> <p><a href="http://lh5.ggpht.com/_WMfxN1atJM0/Se3Qc3hABXI/AAAAAAAAAB4/qAEAyaSm9Yk/s1600-h/google-hates-ie%5B6%5D.png"><img title="google-hates-ie" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="484" alt="google-hates-ie" src="http://lh4.ggpht.com/_WMfxN1atJM0/Se3QdSUha9I/AAAAAAAAAB8/GL9dvFnkilM/google-hates-ie_thumb%5B4%5D.png?imgmax=800" width="492" border="0" /></a> </p> <p>Top is Firefox 3, bottom is Google. I was exploring some jQuery stuff and decided to see if the behavior was any different in IE (suspecting it wasn’t), and noticed a slight difference. I signed into my google account on both to see if that caused a difference</p> <p>While in my perfect world, everyone would use FFX, I’d still rather them use Chrome then IE.</p> <p>I then did a search on google to see if anyone else has noticed this (or so I could see how long it’s been around), and while I didn’t see anything relating to this, it’s nice to know that <a href="http://forums.thedailywtf.com/forums/p/4682/106527.aspx">google has been pushing for an alternative browser</a> for a while now. Too bad they switched their recommendations though.</p> <p>And no, I don’t know why I blacked out my email address. Everyone who visits this blog knows it anyways.</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-8115564650024578862009-04-17T15:32:00.001-05:002009-04-17T20:21:37.005-05:00A better way to organize your CSS/HTML<p>It’s tough being a genius. It really is. Here’s my new guidelines for CSS/HTML:</p> <ol> <li>All tags are divs </li> <li>Use standard html tags as class/id names whenever possible </li> </ol> <p>So, with our new awesomeness, we might get something like this:</p> <div id="codeSnippetWrapper" style="border-right: silver 1px solid; padding-right: 4px; border-top: silver 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: silver 1px solid; width: 146.6%; cursor: text; direction: ltr; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: silver 1px solid; font-family: 'Courier New', courier, monospace; height: 113px; background-color: #f4f4f4; text-align: left"> <div id="codeSnippet" style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; direction: ltr; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; text-align: left; border-bottom-style: none"> <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; direction: ltr; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; text-align: left; border-bottom-style: none"><span id="lnum1" style="color: #606060"> 1:</span> <span style="color: #0000ff"><</span><span style="color: #800000">div</span> <span style="color: #ff0000">class</span><span style="color: #0000ff">="body"</span><span style="color: #0000ff">></span></pre>
<!--CRLF-->
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; direction: ltr; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; text-align: left; border-bottom-style: none"><span id="lnum2" style="color: #606060"> 2:</span>  </pre>
<!--CRLF-->
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; direction: ltr; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; text-align: left; border-bottom-style: none"><span id="lnum3" style="color: #606060"> 3:</span> <span style="color: #0000ff"><</span><span style="color: #800000">div</span> <span style="color: #ff0000">class</span><span style="color: #0000ff">="h1"</span><span style="color: #0000ff">></span>My Title<span style="color: #0000ff"></</span><span style="color: #800000">div</span><span style="color: #0000ff">></span></pre>
<!--CRLF-->
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; direction: ltr; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; text-align: left; border-bottom-style: none"><span id="lnum4" style="color: #606060"> 4:</span> <span style="color: #0000ff"><</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">="p"</span><span style="color: #0000ff">></span>This is my awesome <span style="color: #0000ff"><</span><span style="color: #800000">div</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">="span"</span><span style="color: #0000ff">></span>stuff<span style="color: #0000ff"></</span><span style="color: #800000">div</span><span style="color: #0000ff">></</span><span style="color: #800000">div</span><span style="color: #0000ff">></span></pre>
<!--CRLF-->
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; direction: ltr; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; text-align: left; border-bottom-style: none"><span id="lnum5" style="color: #606060"> 5:</span>  </pre>
<!--CRLF-->
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; direction: ltr; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; text-align: left; border-bottom-style: none"><span id="lnum6" style="color: #606060"> 6:</span> <span style="color: #0000ff"></</span><span style="color: #800000">div</span><span style="color: #0000ff">></span></pre>
<!--CRLF--></div>
</div>
<p> </p>
<p>Pretty freaking slick, eh? I’m hoping it can be <a href="http://codebetter.com/blogs/karlseguin/archive/2009/04/16/kobe-oh-dead-lord-why.aspx">integrated</a> <a href="http://weblogs.asp.net/rashid/archive/2009/04/16/kobe-ms-new-web-2-0-resource-kit-in-asp-net-mvc-and-my-thoughts.aspx">into</a> <a href="http://msdn.microsoft.com/en-us/architecture/bb194897.aspx">Kobe</a> soon!</p> Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-2430856949934117881.post-72933084275589799432009-04-17T15:21:00.001-05:002009-04-17T15:21:01.260-05:00Installing Live Writer<p>So, I just got a new computer, and I had an amazing idea of outstanding excellence (forthcoming), but needed to install Live Writer first.</p> <p>First, it tries to get you to install FIVE HUNDRED other programs first. Piece of crap.</p> <p>But, then, in the installer, it has a picture of a girl smiling at her bewbz. I mean, I smile at bewbz too, but I don’t see why it’s in an installer. </p> <p>Proof:</p> <p><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="494" alt="image" src="http://lh4.ggpht.com/_WMfxN1atJM0/SejkrFZ_hRI/AAAAAAAAAB0/TqFyCixSids/image%5B4%5D.png?imgmax=800" width="604" border="0" /></p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-57906475502768820782009-03-12T09:29:00.001-05:002009-03-12T09:42:34.804-05:00Auditing Part 4 - Quit being a slob<p>Before I start, I'd like to think my colleagues <a href="http://sharplearningcurve.com/blog/">Alex Robson</a> and Craig Israel for helping with the design. It'd have ended up containing 200% more suck without their assistance. Also, the finished product is part of <a href="http://www.codeplex.com/nvigorate">Nvigorate</a>, so whenever Alex updates that project, it'll be there. What is currently up there however is very out of date. It's improved greatly.</p> <p>Welcome to Part 4, the last in my auditing series. Here's the previous ones, you drunken slob, Mr. I'm-Too-Lazy-To-Click-In-The-Archive:</p> <ul> <li><a href="http://robtechdiff.blogspot.com/2009/02/auditing-part-1-how-i-quit-being-tool.html" target="_blank">Part 1 - Introducing generics</a> </li> <li><a href="http://robtechdiff.blogspot.com/2009/03/auditing-part-2-from-one-to-many-in.html" target="_blank">Part 2 - Handling collections</a> </li> <li><a href="http://robtechdiff.blogspot.com/2009/03/auditing-part-3-because-you-can-get.html" target="_blank">Part 3 - Multiple auditor support through the .config file</a> </li> </ul> <p>Everything is almost wrapped up! Our list-o-crap has now turn into a sentence-o-crap, not even worthy of a list anymore! What is that sentence, you ask? Why, it's coming up! Pay attention! Here it comes! Right now! Firing our auditor is still noisy, as it takes place in our functions that are handling unrelated tasks. So let's clean it up!</p> <h1>I can't carry it for you Mr. Frodo, but I can carry you</h1> <p>Auditing is more of something that the function should support, but it'd be nice to not have to muddle up our business code with it, even if it is just one line.</p> <p>So what's a way we could do this? Why, attributes of course! If you're not familiar with adding attributes to a function/class, here's the quick version. If you know this, tough. I'm not going to identify when I'm not talking about it, so you have to wade through these words anyways. Deal.</p> <p>First, an attribute is represented (in C# that is - noone cares what it looks like in VB) by square brackets above your function/class. Like this:</p> <div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4"> <div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> [MyClassAttribute]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> <span style="color: #0000ff">public</span> MyClass</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> [MyFuncAttribute]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> MyFunc()</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> <span style="color: #008000">/* do stuff */</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> }</pre>
</div>
</div>
<p>See? Easy. Applying attributes is called "decorating" your class or function. So, we're going to go about creating some attributes that will fire up our AuditManager when our function is accessed. This is known as Aspect Oriented Programming, or AOP. But how do we do this? We're going to use an AOP framework. There are several out there, but Nvigorate already makes use of <a href="http://www.postsharp.org/" target="_blank">PostSharp</a>, so we're going to use that one. Why PostSharp? Most AOP frameworks have the attributes being evaluated at run-time. This can, unfortunately, lead to some serious run-time speed hits. PostSharp, however, is run pre-compilation, and actually injects your code in the appropriate places. This means no run-time overhead, but more setup on the developers side. To do this, it has to be physically installed on the machine doing the compilation. Also, any project that makes use of the attributes (or aspect, as I'll refer to it from here on), even if not directly using PostSharp libraries, will need a reference to the PostSharp DLLs from the GAC.</p>
<p>So, you've installed PostSharp, and added a reference to the DLLs in your consuming project. Let the fun begin!</p>
<h1>Insert witty subtitle here</h1>
<p>We'll start with the basic information our aspect needs - the action, the username, the object to be audited, and the date. Aka, the same 4 things we've been looking at this entire series. One of the restrictions though about making this an aspect, is that they <em>can't</em> be generic! Oh noes! Well, the good news is we can still fire our AuditManager, using Reflection, and get our generic call! Yay! There's another issue too, but we took care of it when we wrote AuditManager. Remember how I had us make TWO TrackAction calls? We ended up with TrackAction for instances, and TrackActionEnumerable for collections? Well, if we hadn't done that, our reflection calls would've actually failed, as it wouldn't have been able to distinguish between a generic type and a collection of a generic type. But we're so smart, we knew that ahead of time, so we're good. What we'll do is check if our information object implements IEnumerable or not, then we'll know which one to call.</p>
<p>Now, I don't feel like writing raw Reflection code. Yet again, I'll be using the Reflector portion of Nvigorate to handle that for me. One of things we'll have to pass to the call is a collection of arguments. Let's think about how we'll retrieve each of those:</p>
<ul>
<li>Action - well, this is just an enum type, so we can pass that right in the attribute itself. We'll add it to the constructor, then save it in a private field.</li>
<li>Date - we'll just use DateTime.Now, of course. If the auditors themselves wish to use a different timestamp, they can.</li>
<li>Information - I'm going to force a restriction here. I'm saying that consumers <em>have</em> to have this passed in on the function call. You're welcome to change this behavior if you desire. But I think separating your DAL from the rest of your code will end up with a cleaner design, and then this won't be an issue!</li>
<li>Username - hmmm....this one is tricky. And gee, it's like I did them out of order for a reason! Guess what, I did, suckers! That way I can make this it's own topic. Let's discuss it more.</li>
</ul>
<h1>What's in a name?</h1>
<p>Ah, getting the username. And the system username is useless. We need to know the user who's logged in and making the call. There's a LOT of options here. Maybe it's the current user principal. That could be in a windows app, or in a web app. Maybe it's passed along the function call. Maybe it's in your request header.</p>
<p>The point is, we have NO idea where it could be. And trying to define <em>every </em>possibility is asking for failure. This becomes pretty obvious pretty quick that it's an area we need to leave open for the consuming application to define.</p>
<p>We should make a base class for our aspect then. Since it'll be incomplete, lacking an actual way to get the user name, it should be abstract too. "AuditAspectBase" sounds good. We'll define an abstract function then, let's call it "GetUser", that developers will have to implement to use our system. Now, we don't have to care! Yay!</p>
<p>The last thing our class needs to do is make sure that our concrete aspect definitions can get to the information it needs. Lucky enough, PostSharp allows us to grab all kinds of good information about the function call. From it, we grab the instance the function was called on, the parameters the function has, and the values of those. There's more too, but those are the important ones. All of this is passed through a "MethodExecutionEventArgs" object, which is defined in the PostSharp assembly. In the interest of making the consuming developer know as little about PostSharp as possible, we're going to take out the important bits, and store them in our base aspect for easier consumption.</p>
<h1>Give me bits, dammit!</h1>
<p>Alright, alright, alright. I've been making with lots of the werdz and none of the codez. The good news is, there's nothing left to discuss! Here's our AuditAspectBase:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> [Serializable]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">class</span> AuditAspectBase : OnMethodBoundaryAspect</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> <span style="color: #0000ff">private</span> AuditAction _action;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">string</span> _functionArgumentName;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">object</span> _information;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">object</span> Instance { get; set; }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">object</span>[] FunctionArguments { get; set; }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> <span style="color: #0000ff">protected</span> ParameterInfo[] FunctionParameters { get; set; }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> <span style="color: #0000ff">protected</span> AuditAspectBase(AuditAction action, <span style="color: #0000ff">string</span> functionArgumentName)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span> _action = action;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> _functionArgumentName = functionArgumentName;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 16:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 17:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 18:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">sealed</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> OnEntry(MethodExecutionEventArgs eventArgs)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 19:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 20:</span> Instance = eventArgs.Instance;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 21:</span> FunctionArguments = eventArgs.GetReadOnlyArgumentArray();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 22:</span> FunctionParameters = eventArgs.Method.GetParameters();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 23:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 24:</span> _information = GetArgumentValueByName(_functionArgumentName);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 25:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 26:</span> CallAudit();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 27:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 28:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 29:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> GetArgumentValueByName(<span style="color: #0000ff">string</span> name)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 30:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 31:</span> <span style="color: #0000ff">foreach</span> (ParameterInfo info <span style="color: #0000ff">in</span> FunctionParameters)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 32:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 33:</span> <span style="color: #0000ff">if</span> (info.Name == name)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 34:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 35:</span> <span style="color: #0000ff">return</span> FunctionArguments[info.Position];</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 36:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 37:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 38:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 39:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 40:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 41:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 42:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 43:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> CallAudit()</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 44:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 45:</span> <span style="color: #0000ff">object</span>[] args = <span style="color: #0000ff">new</span> <span style="color: #0000ff">object</span>[]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 46:</span> { _action,</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 47:</span> GetUser(),</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 48:</span> _information,</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 49:</span> DateTime.Now</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 50:</span> };</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 51:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 52:</span> <span style="color: #0000ff">if</span>(_information <span style="color: #0000ff">is</span> IEnumerable)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 53:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 54:</span> Reflector.CallMethod(<span style="color: #0000ff">typeof</span>(AuditManager), <span style="color: #006080">"TrackActionEnumerable"</span>, args, _information.GetType().GetElementType());</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 55:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 56:</span> <span style="color: #0000ff">else</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 57:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 58:</span> Reflector.CallMethod(<span style="color: #0000ff">typeof</span>(AuditManager), <span style="color: #006080">"TrackAction"</span>, args, _information.GetType());</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 59:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 60:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 61:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 62:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 63:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">string</span> GetUser();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 64:</span> }</pre>
</div>
</div>
<p>But I'm such a nice guy, that even though you're an ungrateful jerk, I'm going to go through this with you anyways.</p>
<p>First you'll notice it's marked as Serializable. This is required by PostSharp, so do it. Next you'll notice we inherit from "OnMethodBoundaryAspect". This is a PostSharp class (Laos specifically) that will help make things simpler for us. It'll handle the weaving of the aspect for us. If you don't know what that means, don't worry about it. But this specific one, will allow us to provide "hooks" into our function calls. It's going to give us functions we can override, like "OnEntry", "OnExit", etc. Feel free to check the class out. But the one we're going to focus on is "OnEntry". This <em>does</em> mean there is some room here to get fancy - perhaps you're only interested in auditing when the function exits, or want to make sure your audit doesn't write if an exception occurs. Things like this, and more, are possible. But, our implementation is only going to make use of OnEntry. We're getting a smidge ahead of ourselves though.</p>
<p>What do we need in our constructor? Well, from our previous list, we only need two things given to us - the action, and the function parameter that will have our object we're auditing. Using the information PostSharp will give us, we really only need the parameter name. So, our constructor will require those two, and we'll save them in private fields.</p>
<p>Next is our OnEntry method. We'll override the base one, and I'm going to seal it because I don't want it screwed with. We're going to get the calling instance, the arguments, and the parameter names from the event args, and store them in public properties. Our consuming aspects might need this to get the user name. We'll also need to get the object that's being audited. Then, we can call our auditors. We're going to break both of those into their own functions.</p>
<p>First is GetArgumentValueByName. Pretty obvious what it does. It'll loop through our parameter info, and once it finds a match, it'll return the argument itself. If it can't find a match, it'll return null. Because our attributes can't be generic, it can only return an "object". This function is pretty useful though, so lets make it public. It'll come in handy again soon.</p>
<p>The last piece is actually firing up our audit manager, in a function called "CallAudit". We want to control when this happens, so we'll make it private. The first thing we need to do, is create our argument array. Both of the AuditManager's TrackAction calls take the same 4 parameters in the same order. So, we'll grab the action, call our abstract GetUser function that our subclass will have defined, grab the object we're auditing, and our time stamp.</p>
<p>Next we'll check if our object is a collection, by seeing if it's of type IEnumerable. If it is, we'll use Reflector (part of Nvigorate, for those of you not following along) to call TrackActionEnumerable. If not, we'll just call the regular TrackAction. Reflector.CallMethod() has several overloads, including ones to call generic functions. First we tell it the type of our class we want to call (AuditManager), then the function name, then we pass in our arguments. If it's our collection, we need to get the type of collection, then the type of the elements it holds. Else, we can just get the type.</p>
<p>Last thing there is our abstract "GetUser" function. All we need from it is a string, which would be the username.</p>
<h1>2 + 2 = 4</h1>
<p>Time to add it all up, and see what we get! We're done now with our base aspect, so how do we implement and consume it? Easy. Let's make a couple of simple ones that are liable to have lots of reuse potential. Well, one obvious one is using this in an asp.net app. All we need to do this is:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> [Serializable]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> AspNetAuditAspect : AuditAspectBase</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> <span style="color: #0000ff">public</span> AspNetAuditAspect(AuditAction action, <span style="color: #0000ff">string</span> functionArgumentName) : <span style="color: #0000ff">base</span>(action, functionArgumentName)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">string</span> GetUser()</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> <span style="color: #0000ff">return</span> HttpContext.Current.User.Identity.Name;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> }</pre>
</div>
</div>
<p>Doesn't get much simpler. To consume it then, all we do is:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> [AspNetAuditAspect(AuditAction.Update, <span style="color: #006080">"data"</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> SaveMyData(MyFirstType data)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> MyDataLayer.WriteData(data);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> [AspNetAuditAspect(AuditAction.Update, <span style="color: #006080">"data"</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> SaveMyDataCollection(List<MyFirstType> data)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> MyDataLayer.WriteDataCollection(data);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> }</pre>
</div>
</div>
<p>Our aspect, and audit manager, and auditors themselves All handle the rest! Wether it's a collection or an instance. That's pretty sweet.</p>
<p>Here's another good aspect you might want to make use of (and yes, both of these will be included in Nvigorate when it gets updated):</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> [Serializable]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> FunctionArgumentAuditAspect : AuditAspectBase</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">string</span> UserNameArgument;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> <span style="color: #0000ff">public</span> FunctionArgumentAuditAspect(AuditAction action, <span style="color: #0000ff">string</span> functionArgumentName, <span style="color: #0000ff">string</span> userNameArgument)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> : <span style="color: #0000ff">base</span>(action, functionArgumentName)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> UserNameArgument = userNameArgument;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">string</span> GetUser()</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span> <span style="color: #0000ff">return</span> GetArgumentValueByName(UserNameArgument).ToString();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 16:</span> }</pre>
</div>
</div>
<p>This will handle the case where the user name is in the function call itself. Perhaps it's a webservice function or some such. So, that'd obviously need to be passed in on the constructor for our aspect. Then, using our GetArgumentValueByName function we defined in our base aspect, retrieving that value is simple. All we need to do then, to consume it this time, is this:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> [FunctionArgumentAuditAspect(AuditAction.Update, <span style="color: #006080">"data"</span>, <span style="color: #006080">"username"</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> SaveMyDataService(<span style="color: #0000ff">string</span> username, MyFirstType data)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> MyDataLayer.WriteData(data);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> }</pre>
</div>
</div>
<p>Now, we've managed to get the code noise out of our function, and auditing just "happens" for us. Our code is cleaner, better organized, and more flexible. This will make it easier to implement, easier to maintain, and easier to enhance.</p>
<h1>This is the end, my only friend, the end</h1>
<p>My favorite part is when I was done writing all this. Hopefully you can now go forth and audit <em>like a man!</em> Let's see that smile!</p>
<p><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="356" alt="No more tears!" src="http://lh3.ggpht.com/_WMfxN1atJM0/SbkcX64O92I/AAAAAAAAABY/RdzxtwPz0c8/image%5B9%5D.png?imgmax=800" width="269" border="0" /> </p>
<p>That'll do horse. That'll do.</p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-83198430221005296652009-03-06T09:48:00.001-06:002009-03-06T09:48:56.257-06:00Auditing Part 3 - Because you can't get a build error with config files<p>Before I start, I'd like to think my colleagues <a href="http://sharplearningcurve.com/blog/">Alex Robson</a> and Craig Israel for helping with the design. It'd have ended up containing 200% more suck without their assistance. Also, the finished product is part of <a href="http://www.codeplex.com/nvigorate">Nvigorate</a>, so whenever Alex updates that project, it'll be there. What is currently up there however is very out of date. It's improved greatly.</p> <p>One last note - today's blog post was created with:</p> <p><u><font color="#800000" size="6"><strong><em><font color="#ff0000">U</font><font color="#ff80c0">n</font><font color="#8080c0">i</font><font color="#0080ff">R</font><font color="#00ffff">e</font><font color="#80ff80">l</font><font color="#ffff80">i</font><font color="#ff8000">g</font><font color="#008000">i</font><font color="#408080">o</font><font color="#800080">n</font><font color="#0000ff">!</font></em></strong></font></u> <br /><em><font face="Arial Narrow" size="4">All religions, all the time!</font></em></p> <p>Harnessing this amazing new technology allows me to create content that references all religions equally, so noone feels left out or offended! Onto the post!</p> <hr /> <p>If you are religious, I highly recommend you call your preacher/pastor/rabbi/spongebob/etc, because <strong><em>Hell may have just frozen over!!!</em></strong></p> <p>That's right! I actually made a third part in a series. It's crazy. Here's links to the first two parts, in case you suck and didn't know about my awesome blog before now:</p> <ul> <li><a href="http://robtechdiff.blogspot.com/2009/02/auditing-part-1-how-i-quit-being-tool.html" target="_blank">Part 1 - Introducing generics</a> </li> <li><a href="http://robtechdiff.blogspot.com/2009/03/auditing-part-2-from-one-to-many-in.html" target="_blank">Part 2 - Handling collections</a> </li> </ul> <p>That's also right, that's a bulleted list mother-fucker. And that's also <em>also </em>right, I dropped the f-bomb on my blog. Deal with it (unless you're my boss, and in that case, I mean, c'mon...it's not like you're honestly surprised are you? and second of all, this isn't even my blog! It's just a coincidence/result-of-a-hacker/internet-explorer-bug!)</p> <p>So what's our next step? Once again, let's break out the Bag O' Crap and see:</p> <ul> <li>What if we want multiple auditors for a single type? We'll have to add more and more TrackAction calls. </li> <li>Firing our auditor - it's in the middle of our functions. That adds a bit of code noise, and can make it harder to track down. </li> </ul> <p>Ah yes. That top one. This is gonna be a long post. I was in a good mood until I realized I had to go through this with you. I hate you so much. It's not my fault you're not me and don't remember doing all this already.</p> <h1>Goooooooaaaaaallllll</h1> <p>So, currently, you'd have to explicitly call a concrete implementation for each of your auditors. So that's dumping more code in your existing code, and if you need to fire multiple auditors, that's multiple calls. It's going to get messy, and you're going to have to remember when to call which auditors, and make sure you didn't forget any, and when you add a new auditor go and plaster it everywhere, blah blah blah.</p> <p>What we have here is a single set of logic. We know the relationship of auditors to the objects we're editing. We need to store all this mess in a single place. Let's call this place our "AuditManager" ("OMG THATS THE CLASS NAME IT'S GONNA BE I CAN JUST FEEL IT"). Now, we could have this so-called "AuditManager" ("WOAH IT'S USED TWICE IT'S SO GONNA BE THE CLASS NAME") contain all the logic explicitly. Now when we add auditors, we're restricted to changing our code in 1 place. But how about we just make it so we don't have to edit any code at all?</p> <p>"WOAH ROB THAT SOUNDS LIKE THE DEVILS MAGIC I DON'T TRUST THE DEVILS MAGIC THIS IS CODE ITS SERIOUS BUSINESS YOU'RE A BAD PERSON I'M GOING TO PRAY TO MY PREACHER/PASTOR/RABBI/SPONGEBOB/ETC FOR HIM TO SAVE YOU FROM THIS DEVILS MAGIC"</p> <p>.....</p> <p>Seriously, quit it with the caps, jack ass. If you weren't so busy being a jack ass as to not read the title, you'd know where this is going. Go ahead, read it. I'll wait.</p> <p><font size="1">"oh."</font></p> <p>Yeah. That's right, speak in a small font. You should be embarrassed. We're gonna put all that stuff in config files, and let our AuditManager (yes it's the class name shut up for god/jesus/buddha/spongebob/etc's sake) determine which auditors to fire up.</p> <h1>It's like code, but instead of semi-colons you use less-than and greater-than symbols</h1> <p>If you seriously believe this heading, you should stop right now. Maybe go to a <a href="http://www.apple.com/" target="_blank">"your money buys you pre-built opinions to mimic!"</a> platform. </p> <p>Now noone likes over-abundant XML, so we're gonna try to make this as simple as possible, and only focus on must-have features. Due to the complexity of the upcoming pieces, we're gonna end with the full feature-set. This is *not* the order it was written in - it expanded and changed throughout development. Unlike in <a href="http://robtechdiff.blogspot.com/2009/02/auditing-part-1-how-i-quit-being-tool.html" target="_blank">Part 1</a>, I think it'd be more confusing to show the natural development of this piece. We'd constantly keep jumping around. And in part 1  it was a design decision, and this is more of a feature set. So, I think it's less crucial, and if you disagree, go write your own damn blog talking about how stupid I am.</p> <p>And just in case you're unfamiliar with config files, we're talking about embedding this in our respective app.config or web.config files (depending on what type of solution you are building).</p> <p>First, we'll need a root containing tag. We'll call it "AuditorConfiguration" (wow, it's like the name tells you what it means! How novel!). Inside it, what do we need? Well, our auditor definitions. Well call this block "Auditors". And then we'll list each "Auditor" inside its separately. Now what do we need to know about each auditor? Well, we will need to know the type of the auditor itself (so we can fire it up), as well as for what type it should handle.</p> <p>Let's discuss that for a second. Done. LAWL, GET IT I LITERALLY WAITED A SECOND. </p> <p>Sorry. I pulled a you.</p> <p>Anywhos, It's going to do more than just "handle a single type". What if you want ALL your business objects to be audited, regardless of anything evarz, but maybe here and there you want add something extra? And maybe you have a case or two where you don't want ANY other auditors to handle it? So, this is more than just a single type. If you put a base class in here, that all your business objects inherit from, they'll all get audited. We'll make sure our AuditManager checks for inheritance. For the other case, we'll need to be able to explicitly state in our config file that it's an exclusive auditor...why let's make the attribute "exclusive"! This "naming crap what it means" is neat!</p> <p>Now, let's say you have all your auditors in a single assembly, but your project is tiered. Maybe sometimes you need to audit things on the front end of the system, but other times on the back end. Depending on <em>where</em> in your technology stack you are you will save your audits differently. You don't want to have to write multiple auditors that do the same thing. So, we're going to leave this completely undefined, but we're going to support the ability to embed a "config" section for your auditor. You'll have different config files depending on where your auditor lives, and each one can specify how that data gets saved. How you interpret that in your auditor and want to use that is up to you. I recommend going with something that doesn't suck. </p> <p>However, we'll need to make a quick change to support this. We should add something to our base class, or we won't have a way to know how to pass the custom config in! All we need to add to our AuditorBase<T> is:</p> <div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; height: 36px; background-color: #f4f4f4"> <div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> <pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">void</span> LoadConfiguration(XElement xml);</pre>
</div>
</div>
<p>Making it abstract will force our consumers to provide a definition. This is done to hopefully force users to think about how they want to save their audits, and come up with something flexible. You could make it virtual if you don't want to enforce that. If you're not familiar with defining your own config schema and options, you will be by the time we're done today, so you can do so easily. Or you can just parse the XML that will get passed. I'd like to get more in-depth, but any solution is really going to be more domain-specific, and what this system does (or at least it's goal) is provide a flexible way of auditing regardless of your domain.</p>
<p>So, it sounds like our configuration section is coming along nicely. Let's take a peek at what it looks like so far:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; height: 274px; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff"><</span><span style="color: #800000">AuditorConfiguration</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> <span style="color: #0000ff"><</span><span style="color: #800000">Auditors</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> <span style="color: #0000ff"><</span><span style="color: #800000">Auditor</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="MySolution.Auditors.MyFirstTypeAuditor, MySolution.Auditors"</span> </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> <span style="color: #ff0000">handlesType</span><span style="color: #0000ff">="MySolution.BusinessObjects.MyFirstType, MySolution.BusinessObjects"</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> <span style="color: #ff0000">exclusive</span><span style="color: #0000ff">="true"</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> <span style="color: #0000ff"><</span><span style="color: #800000">Config</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> [custom config shizzle here if needed]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> <span style="color: #0000ff"></</span><span style="color: #800000">Config</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> <span style="color: #0000ff"></</span><span style="color: #800000">Auditor</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> <span style="color: #0000ff"><</span><span style="color: #800000">Auditor</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="MySolution.Auditors.MyGenricAuditor`1, MySolution.Auditors"</span> </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> <span style="color: #ff0000">handlesType</span><span style="color: #0000ff">="MySolution.BusinessObjects.MyBaseType, MySolution.BusinessObjects"</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> <span style="color: #0000ff"><</span><span style="color: #800000">Config</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> [custom config shizzle here if needed]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span> <span style="color: #0000ff"></</span><span style="color: #800000">Config</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> <span style="color: #0000ff"></</span><span style="color: #800000">Auditor</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 16:</span> <span style="color: #0000ff"></</span><span style="color: #800000">Auditors</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 17:</span> <span style="color: #0000ff"></</span><span style="color: #800000">AuditorConfiguration</span><span style="color: #0000ff">></span></pre>
</div>
</div>
<p>Time for another round of "explain the made up crap" - This is saying you have a solution. Everything in this solution will start with the "MySolution" namespace. There are two projects in this solution that this is concerned with - "MySolution.BusinessObjects" and "MySolution.Auditors". Those are your assembly names as well. All your business objects inherit from "MyBaseType". So, for naming our types, we give the full namespace name for our class, then a comma, then the assembly name where they live. This is called a fully qualified domain name, usually abbreviated as FQDN. But you already knew that. But the window cleaner behind you in your Skyscraper of Power has been reading this article with you, and he was confused. I'm always helping out the little people. </p>
<p>"MyFirstTypeAuditor" hasn't changed since we last saw it in <a href="http://robtechdiff.blogspot.com/2009/03/auditing-part-2-from-one-to-many-in.html" target="_blank">Part 2</a>, except for defining LoadConfiguration. But what's this "MyGenericAuditor`1" you ask? More specifically, what the hell is that "`1"? That's how you define generic types in a config file. Here's our class definition for "MyGenericAuditor":</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; height: 240px; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> MyGeneralAuditor<T> : AuditorBase<T> <span style="color: #0000ff">where</span> T : MyBaseType</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> TrackAction(AuditAction action, <span style="color: #0000ff">string</span> user, T information, DateTime? when)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> MyDataLayer.WriteData(<span style="color: #0000ff">new</span> AuditLog()</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> Action = action,</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> User = user,</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> Information = SerializeObject(information),</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> Date = when ?? DateTime.Now</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> });</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span> public override void LoadConfiguration(XElement xml) {}</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> }</pre>
</div>
</div>
<p>Notice that this auditor is generic itself! Crazy sauce! We've specified, though, that it only works on types that come from our base type, cleverly called "MyBaseType". Also notice that our magical "SerializeObject()" function has made a return. So, since the definition for this class is generic, and you can't put "<" or ">" in an attribute definition for XML, we do that with ~1. Note that if our class definition had multiple generic types (say "MyGenericSomething<T, P, S>"), it would be defined in a config file like "MyGenericSomething~1~2~3". But, our AuditManager that we'll write soon won't be supporting that, so it's irrelevant to us at the moment. Just trying to be nice to those who don't know. Geez, lay off.</p>
<p>There's another feature I think we should support in our config too though. Maybe we have some business objects we DON'T want to audit? A very possible realistic use of this is putting it at the entry points to your data layer. But your AuditLog class will go through there too! Hello, infinite loop, our old friend. Or maybe you have notifications as well that you log to a database, but don't care about auditing. So, we need to tell our AuditManager to ignore some stuff. Let's give it two ways to do that - by types, or by namespace. That'd expand our config block to look like:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff"><</span><span style="color: #800000">AuditorConfiguration</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> <span style="color: #0000ff"><</span><span style="color: #800000">Auditors</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> <span style="color: #0000ff"><</span><span style="color: #800000">Auditor</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="MySolution.Auditors.MyFirstTypeAuditor, MySolution.Auditors"</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> <span style="color: #ff0000">handlesType</span><span style="color: #0000ff">="MySolution.BusinessObjects.MyFirstType, MySolution.BusinessObjects"</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> <span style="color: #ff0000">exclusive</span><span style="color: #0000ff">="true"</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> <span style="color: #0000ff"><</span><span style="color: #800000">Config</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> [custom config shizzle here if needed]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> <span style="color: #0000ff"></</span><span style="color: #800000">Config</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> <span style="color: #0000ff"></</span><span style="color: #800000">Auditor</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> <span style="color: #0000ff"><</span><span style="color: #800000">Auditor</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="MySolution.Auditors.MyGenricAuditor`1, MySolution.Auditors"</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> <span style="color: #ff0000">handlesType</span><span style="color: #0000ff">="MySolution.BusinessObjects.MyBaseType, MySolution.BusinessObjects"</span><span style="color: #0000ff">></span> </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> <span style="color: #0000ff"><</span><span style="color: #800000">Config</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> [custom config shizzle here if needed]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span> <span style="color: #0000ff"></</span><span style="color: #800000">Config</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> <span style="color: #0000ff"></</span><span style="color: #800000">Auditor</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 16:</span> <span style="color: #0000ff"></</span><span style="color: #800000">Auditors</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 17:</span> <span style="color: #0000ff"><</span><span style="color: #800000">IgnoreNamespaces</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 18:</span> <span style="color: #0000ff"><</span><span style="color: #800000">IgnoreNamespace</span> <span style="color: #ff0000">namespace</span><span style="color: #0000ff">="MySolution.Notifications"</span> <span style="color: #0000ff">/></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 19:</span> <span style="color: #0000ff"></</span><span style="color: #800000">IgnoreNamespaces</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 20:</span> <span style="color: #0000ff"><</span><span style="color: #800000">IgnoreTypes</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 21:</span> <span style="color: #0000ff"><</span><span style="color: #800000">IgnoreType</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="MySolution.BusinessObjects.AuditLog, MySolution.BusinessObjects"</span> <span style="color: #0000ff">/></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 22:</span> <span style="color: #0000ff"></</span><span style="color: #800000">IgnoreTypes</span><span style="color: #0000ff">></span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 23:</span> <span style="color: #0000ff"></</span><span style="color: #800000">AuditorConfiguration</span><span style="color: #0000ff">></span></pre>
</div>
</div>
<p></p>
<p>Alrighty then. That looks pretty good. I think we're done here.</p>
<p>"But what about--" nope. Not happening. We're done. I'm tired of your ruining my life.</p>
<p>":("</p>
<p>Go colon-right-parenthesis yourself somewhere else.</p>
<h1>Microsoft WANTS you to put crap in a config file</h1>
<p>Swear to god/jesus/buddha/spongebob/etc they do. Why? Because they give you some classes that keep you from having to parse all the XML yourself. It'll turn your XML into objects, which is spiffy. Easy to use too. At each node of the configuration block, we define a new class that defines what attributes and children it can have. I'm going to go through this pretty quickly. It's not difficult, and <a href="http://msdn.microsoft.com/en-us/library/system.configuration.aspx" target="_blank">MSDN</a> can explain stuff for you in more detail if you need it. Everything that you need is contained in the "System.Configuration" namespace. Add a reference to the dll in your project if you don't already have one.</p>
<p>We'll start at the top level, and keep defining our classes as we go down. If you're playing along at home, doing it in this order is kinda bass-ackwards, since we'll have not-yet-defined class names. But it's easier to explain this way, so deal. </p>
<p>The first block is the AuditorConfiguration. It's defined as such:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> AuditConfigurationSection : ConfigurationSection</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> [ConfigurationProperty(<span style="color: #006080">"Auditors"</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> <span style="color: #0000ff">public</span> AuditorCollection Auditors</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> get { <span style="color: #0000ff">return</span> ((AuditorCollection)(<span style="color: #0000ff">base</span>[<span style="color: #006080">"Auditors"</span>])); }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> [ConfigurationProperty(<span style="color: #006080">"IgnoreTypes"</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> <span style="color: #0000ff">public</span> IgnoreTypesCollection IgnoreTypes</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> get { <span style="color: #0000ff">return</span> ((IgnoreTypesCollection)(<span style="color: #0000ff">base</span>[<span style="color: #006080">"IgnoreTypes"</span>])); }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> [ConfigurationProperty(<span style="color: #006080">"IgnoreNamespaces"</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 16:</span> <span style="color: #0000ff">public</span> IgnoreNamespacesCollection IgnoreNamespaces</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 17:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 18:</span> get { <span style="color: #0000ff">return</span> ((IgnoreNamespacesCollection)(<span style="color: #0000ff">base</span>[<span style="color: #006080">"IgnoreNamespaces"</span>])); }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 19:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 20:</span> }</pre>
</div>
</div>
<p></p>
<p>So, your root section needs to inherit from "ConfigurationSection". Then, each of your properties in this class that are represented in the config file, need to have the attirbute "ConfigurationProperty", which takes 1 parameter - what it's named in the config itself. Each of our sections from our top level contain multiples, so that's why they're each named "Collection". We don't want to set them in our client code, just read what's there, so we're only going to define a getter (and no setters). To retrieve them, we call "base" with an string index, that is the same as the parameter you passed to the "ConfigurationProperty". Then you'll want to cast that to your property type (in our case, our various collection classes).</p>
<p>Let's move to our "AuditorCollection" class then. It looks like this:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> [ConfigurationCollection(<span style="color: #0000ff">typeof</span>(Auditor), AddItemName = <span style="color: #006080">"Auditor"</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> AuditorCollection : ConfigurationElementCollection</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> ConfigurationElement CreateNewElement()</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Auditor();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">object</span> GetElementKey(ConfigurationElement element)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> <span style="color: #0000ff">return</span> ((Auditor)(element)).TypeName;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> }</pre>
</div>
</div>
<p>Since this is a collection, you inherit from "ConfigurationElementCollection". You decorate this class with a "ConfigurationCollection" attribute, which takes one parameter - the type of of the actual configuration element it contains (which we'll name Auditor to match our XML). We're also going to specify what tag name it should look for to add new items, which is "Auditor" again. We do that with "AddItemName" property.</p>
<p>"ConfigurationElementCollection" also requires us to override two functions. The first is "CreateNewElement", and all we do there is return our "Auditor" configuration element class that we haven't defined yet. The other is "GetElementKey". We know our elements are all of type "Auditor" in this collection, so we'll cast it, and grab a property that we'll treat as the key and return it. In our case, it'll be the name of the type of auditor it represents.</p>
<p>Lastly, lets define our "Auditor" element. Here are teh coedz:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Auditor : ConfigurationElement</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> <span style="color: #0000ff">private</span> XElement _configurationXml = <span style="color: #0000ff">new</span> XElement(<span style="color: #006080">"blank"</span>);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> [ConfigurationProperty(<span style="color: #006080">"type"</span>, DefaultValue = <span style="color: #006080">""</span>, IsKey = <span style="color: #0000ff">true</span>, IsRequired = <span style="color: #0000ff">true</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> TypeName</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> get</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> <span style="color: #0000ff">return</span> (<span style="color: #0000ff">string</span>)(<span style="color: #0000ff">base</span>[<span style="color: #006080">"type"</span>]);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> set</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span> <span style="color: #0000ff">base</span>[<span style="color: #006080">"type"</span>] = <span style="color: #0000ff">value</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 16:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 17:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 18:</span> [ConfigurationProperty(<span style="color: #006080">"handlesType"</span>, IsRequired = <span style="color: #0000ff">true</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 19:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> HandlesType</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 20:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 21:</span> get</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 22:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 23:</span> <span style="color: #0000ff">return</span> (<span style="color: #0000ff">string</span>)(<span style="color: #0000ff">base</span>[<span style="color: #006080">"handlesType"</span>]);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 24:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 25:</span> set</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 26:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 27:</span> <span style="color: #0000ff">base</span>[<span style="color: #006080">"handlesType"</span>] = <span style="color: #0000ff">value</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 28:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 29:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 30:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 31:</span> [ConfigurationProperty(<span style="color: #006080">"exclusive"</span>, IsRequired = <span style="color: #0000ff">false</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 32:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">bool</span> Exclusive</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 33:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 34:</span> get</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 35:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 36:</span> <span style="color: #0000ff">return</span> (<span style="color: #0000ff">bool</span>)(<span style="color: #0000ff">base</span>[<span style="color: #006080">"exclusive"</span>]);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 37:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 38:</span> set</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 39:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 40:</span> <span style="color: #0000ff">base</span>[<span style="color: #006080">"exclusive"</span>] = <span style="color: #0000ff">value</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 41:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 42:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 43:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 44:</span> <span style="color: #0000ff">public</span> Type AuditorType</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 45:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 46:</span> get</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 47:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 48:</span> <span style="color: #0000ff">return</span> Reflector.GetType(TypeName);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 49:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 50:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 51:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 52:</span> <span style="color: #0000ff">public</span> XElement ConfigurationXml</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 53:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 54:</span> get</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 55:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 56:</span> <span style="color: #0000ff">return</span> _configurationXml;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 57:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 58:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 59:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 60:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">bool</span> OnDeserializeUnrecognizedElement(<span style="color: #0000ff">string</span> elementName, System.Xml.XmlReader reader)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 61:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 62:</span> _configurationXml = (XElement)XElement.ReadFrom(reader);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 63:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 64:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 65:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 66:</span> }</pre>
</div>
</div>
<p>Our single element inherits from "ConfigurationElement". We have a private field for that user-defined config block. We tag our properties that are attributes in our XML properly, marking key and required as needed. Each one exposes a get and a set, which just go against the base collection. We also made a Type property that uses Reflector. Reflector is a part of Nvigorate, and is one of it's most useful features. Reflector simplifies all your reflection calls, as you can see.</p>
<p>The last thing we do is override "OnDeserializeUnrecognizedElement". This will be raised whenever that user-defined config block is hit. So, we take that, and store it in our field.</p>
<p>We repeat this for IgnoreTypes and IgnoreNamespaces. I'll show them here for you, but they both follow the same setup as AuditorCollection and Auditor, except simpler, so I'm not going to explain them.</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> [ConfigurationCollection(<span style="color: #0000ff">typeof</span>(IgnoreType), AddItemName = <span style="color: #006080">"IgnoreType"</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> IgnoreTypesCollection : ConfigurationElementCollection</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> ConfigurationElement CreateNewElement()</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> IgnoreType();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">object</span> GetElementKey(ConfigurationElement element)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> <span style="color: #0000ff">return</span> ((IgnoreType)(element)).Type;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> IgnoreType : ConfigurationElement</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 16:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 17:</span> [ConfigurationProperty(<span style="color: #006080">"type"</span>, DefaultValue = <span style="color: #006080">""</span>, IsKey = <span style="color: #0000ff">true</span>, IsRequired = <span style="color: #0000ff">true</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 18:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Type</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 19:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 20:</span> get</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 21:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 22:</span> <span style="color: #0000ff">return</span> (<span style="color: #0000ff">string</span>)(<span style="color: #0000ff">base</span>[<span style="color: #006080">"type"</span>]);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 23:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 24:</span> set</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 25:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 26:</span> <span style="color: #0000ff">base</span>[<span style="color: #006080">"type"</span>] = <span style="color: #0000ff">value</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 27:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 28:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 29:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 30:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 31:</span> [ConfigurationCollection(<span style="color: #0000ff">typeof</span>(IgnoreNamespace), AddItemName = <span style="color: #006080">"IgnoreNamespace"</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 32:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> IgnoreNamespacesCollection : ConfigurationElementCollection</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 33:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 34:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> ConfigurationElement CreateNewElement()</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 35:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 36:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> IgnoreNamespace();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 37:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 38:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 39:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">object</span> GetElementKey(ConfigurationElement element)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 40:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 41:</span> <span style="color: #0000ff">return</span> ((IgnoreNamespace)(element)).Namespace;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 42:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 43:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 44:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 45:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> IgnoreNamespace : ConfigurationElement</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 46:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 47:</span> [ConfigurationProperty(<span style="color: #006080">"namespace"</span>, DefaultValue = <span style="color: #006080">""</span>, IsKey = <span style="color: #0000ff">true</span>, IsRequired = <span style="color: #0000ff">true</span>)]</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 48:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Namespace</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 49:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 50:</span> get</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 51:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 52:</span> <span style="color: #0000ff">return</span> (<span style="color: #0000ff">string</span>)(<span style="color: #0000ff">base</span>[<span style="color: #006080">"namespace"</span>]);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 53:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 54:</span> set</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 55:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 56:</span> <span style="color: #0000ff">base</span>[<span style="color: #006080">"namespace"</span>] = <span style="color: #0000ff">value</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 57:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 58:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 59:</span> }</pre>
</div>
</div>
<p>"Waaaah, you're going too fast! I need more detail!" Stuff it, you big baby. This blog isn't <em>for</em> babies. It's for real men who punch live animals to death every night, or they don't get to eat.</p>
<p>Last thing we'll have to do, is let the configuration manager know to link up our configuration classes with the config elements. In the configuration/configSections of your config file, add this:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; height: 38px; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff"><</span><span style="color: #800000">section</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="AuditorConfiguration"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="MySolution.AuditingConfiguration.AuditConfigurationSection, MySolution.AuditingConfiguration"</span> <span style="color: #0000ff">/></span></pre>
</div>
</div>
<p> Once again, I'm just making up a namespace, but what you have to do is just put the FQDN in for the "type" attribute of where your "root" class lives.</p>
<h1>Less code = less chance for you to screw it all up</h1>
<p>Damn this is a long post. I should've broken it up into multiples, but you'd be left with an incomplete solution. Not that I think you should use anything until the series is finished, but you could if you wanted to. Phew.</p>
<p>So, last piece! Praise be to jesus/buddha/god/ganesh/spongebob/etc! .We have all our auditors defined and configured and all that crap. We've mentioned that we're gonna use an "AuditManager" class to read the config and do the magic. The goal is so that we only have to call TrackAction ONCE in our consuming code, instead of calling all the auditors individually. There's no reason to change our signature on that function either. We'll need two TrackAction's, just like in our auditors - one for instances, and one for collections. </p>
<p>However - in the next post, you'll see we're actually going to be calling the AuditManager using reflection. I'm jumping the gun a tad, because I'm saving us the headache of having to go back and rework this piece. How this is going to affect our design is minimal, but you'll bitch at me if I don't explain it. Since we'll be calling AuditManager.TrackAction with reflection, and TrackAction will be a generic call with two overloads where the only changed parameter IS the generic one, it's going to fail for us. It won't be able to identify between "T information" and "IEnumerable<T> information". So what we're going to do is instead have TrackAction and TrackActionEnumerable.</p>
<p>Before our AuditManager can do anything though, it's going to need that config data! That's easy. Remember, MS wants you to use configs. And we don't want to have to load that config data over and over and over, so we're going to make it static. We'll have a private static field that will save our information for us. In our public property, when we try to access that private field, if it's null, we'll load it from the config. Else, we'll just return the private field. All you need is this:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> AuditConfigurationSection _configSection = <span style="color: #0000ff">null</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">static</span> AuditConfigurationSection ConfigSection</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> get</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> <span style="color: #0000ff">if</span> (_configSection == <span style="color: #0000ff">null</span>)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> _configSection = (AuditConfigurationSection)ConfigurationManager.GetSection(<span style="color: #006080">"AuditorConfiguration"</span>);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> <span style="color: #0000ff">return</span> _configSection;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span> }</pre>
</div>
</div>
<p> </p>
<p>"ConfigurationManager" is also contained in the "System.Configuration" namespace I mentioned earlier. We're going to grab our configuration, then cast it to our classes we defined earlier.</p>
<p>Now to start going through it. The good news for you, is that this is also easy. The good news for me, is that means you're less likely to whine at me. You access the config section just like you'd expect! The "ConfigurationManager" at this point has organized your object hierarchy so that you can just loop through your properties. You'll see that in just a second, but first let's think of the overall approach we're going to need to do here. Our two track action functions will first need to make sure our "ConfigSection" property isn't null. If it is, then that means the consuming application didn't define anything in the config (or possibly named the section incorrectly). If it's not null, we'll need to make sure then that the type isn't in the ignore list. If it passes both of those however, then we'll want to loop through all the auditor definitions and find which ones match, create an instance of them, and call TrackAction on each one.</p>
<p>So let's start with our easier part of this functionality - checking to see if it's an ignored type. "IsIgnoredType" sounds like a good function name for me. Our TrackAction call is generic, so let's make our IsIgnoredType generic as well. I'll show you the function, then we'll discuss it.</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">bool</span> IsIgnoredType<T>()</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> Type objectType = <span style="color: #0000ff">typeof</span>(T);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> <span style="color: #0000ff">foreach</span> (IgnoreNamespace ignoreNamespace <span style="color: #0000ff">in</span> ConfigSection.IgnoreNamespaces)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> <span style="color: #0000ff">if</span>(objectType.Namespace == ignoreNamespace.Namespace)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> <span style="color: #0000ff">foreach</span> (IgnoreType ignoreType <span style="color: #0000ff">in</span> ConfigSection.IgnoreTypes)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> Type ignoredObjectType = Reflector.LoadType(ignoreType.Type);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 16:</span> </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 17:</span> <span style="color: #0000ff">if</span>(ignoredObjectType.Equals(objectType))</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 18:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 19:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 20:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 21:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 22:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 23:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 24:</span> }</pre>
</div>
</div>
<p> First thing to note is that it's static. There's no reason for us to have to instantiate our AuditManager. All of our functions will be static.</p>
<p>The first thing we do in our function is create a Type object of our generic parameter. We'll then start at our ignored namespaces. For each of our ignored namespaces defined in our config, we'll see if it matches the Type's namespace property. If it does, we exit the function with a return value of true.</p>
<p>If our type passes that check, then we'll move on to our ignored types. We'll loop through them. For each defined one, we'll once again use Reflector (that handy dandy part of Nvigorate I mentioned earlier) to load our type, then call the "Equals" function on the Type object to see if it matches our current type. The reason we load the type and call the equals function, instead of doing something simpler like say, just checking the type names, is because we want to make sure they are indeed the EXACT same type. We don't want to run into issues where classes get named the same and end up ignoring the wrong ones. Once again - if we find a match, we exit returning true.</p>
<p>Then if our type passes these checks, we return false.</p>
<p>The last thing we need to do is retrieve all our matching auditors. We're going to call that "GetAuditors". It will also be a generic function. And when it's done, it should return a list of our auditors. Now, we won't know the concrete auditor types, but that's why they have a base class in common. So, we'll return a "List<AuditorBase<T>>", that way our TrackAction calls can still fire TrackAction on each one.</p>
<p>Once again, I'm going to show you the code then explain it.</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> List<AuditorBase<T>> GetAuditors<T>()</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> Type objectType = <span style="color: #0000ff">typeof</span>(T);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> List<AuditorBase<T>> auditors = <span style="color: #0000ff">new</span> List<AuditorBase<T>>();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> <span style="color: #0000ff">foreach</span> (Auditor a <span style="color: #0000ff">in</span> ConfigSection.Auditors)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span> Type configuredObjectType = Reflector.LoadType(a.HandlesType);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> <span style="color: #0000ff">bool</span> typeMatch = configuredObjectType.Equals(objectType);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> <span style="color: #0000ff">if</span> (typeMatch || objectType.IsSubclassOf(configuredObjectType))</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> Type auditorType = Reflector.LoadType(a.TypeName);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> <span style="color: #0000ff">if</span> (auditorType != <span style="color: #0000ff">null</span>)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 16:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 17:</span> AuditorBase<T> auditor = <span style="color: #0000ff">null</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 18:</span> <span style="color: #0000ff">if</span> (auditorType.IsGenericTypeDefinition)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 19:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 20:</span> auditor = (AuditorBase<T>)Reflector.MakeGenericInstance(auditorType, objectType);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 21:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 22:</span> <span style="color: #0000ff">else</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 23:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 24:</span> auditor = (AuditorBase<T>)Activator.CreateInstance(auditorType);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 25:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 26:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 27:</span> auditor.LoadConfiguration(a.ConfigurationXml);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 28:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 29:</span> <span style="color: #0000ff">if</span>(a.Exclusive)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 30:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 31:</span> auditors.Clear();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 32:</span> auditors.Add(auditor);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 33:</span> <span style="color: #0000ff">return</span> auditors;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 34:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 35:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 36:</span> auditors.Add(auditor);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 37:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 38:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 39:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 40:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 41:</span> <span style="color: #0000ff">return</span> auditors;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 42:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 43:</span> }</pre>
</div>
</div>
<p> First things first, we create a Type object of our generic parameter. Next, we create an empty list of our return value. This way, at the end of our function, we can just return this parameter, and our consuming code doesn't have to worry about doing null checks.</p>
<p>Next we'll loop through all the defined auditors. For each one, we'll use Reflector to load the type, then check if the types match. If they do, OR if our type we're auditing is a subclass of this auditor's handled type, then we need to create an instance and add it to our list. If not, we continue on to the next defined auditor.</p>
<p>So, let's say we've found a match. Then we'll use Reflector (yet again) to load the auditor's type itself. We'll do a null check first - if you find this failing, make sure you've added a reference to the project where you've defined your auditors. Then we'll need to see if it's a generic auditor (remember, defined in the config file with the "`1" syntax). If it is, then we'll use Reflector to make an instance of that for us, passing the auditor's type as well as the generic parameter type (which will be the type created by our generic parameter that the function is running under). If not, then we'll just use the regular "Activator.CreateInstance" call.</p>
<p>Whichever way we load our auditor, we'll of course want to cast it to our AuditorBase<T>. Next, we'll want to pass our auditor the configuration XML that we found. Lastly, we'll want to check if this auditor is exclusive or not. If it is, then we should clear our list, only add this one, and exit. If not, then just add it to the list, and continue to the next one.</p>
<p>Last thing to do, is to create our actual TrackAction calls! we defined earlier what they need to do, so let's take a look at the final product, using our spiffy new functions:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> TrackAction<T>(AuditAction action, <span style="color: #0000ff">string</span> user, T information, DateTime? when)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> <span style="color: #0000ff">if</span> (ConfigSection != <span style="color: #0000ff">null</span> && !IsIgnoredType<T>())</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> GetAuditors<T>().ForEach(a => a.TrackAction(action, user, information, when));</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 7:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 8:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 9:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> TrackActionEnumerable<T>(AuditAction action, <span style="color: #0000ff">string</span> user, IEnumerable<T> information, DateTime? when)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 10:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 11:</span> <span style="color: #0000ff">if</span> (ConfigSection != <span style="color: #0000ff">null</span> && !IsIgnoredType<T>())</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 12:</span> {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 13:</span> GetAuditors<T>().ForEach(a => a.TrackAction(action, user, information, when));</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 14:</span> }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 15:</span> }</pre>
</div>
</div>
<p> You'll notice we're using LINQ there to iterate through, and call our individual TrackAction calls. You could do this with a regular "foreach" call as well, but this obviously looks cleaner. That's it!</p>
<h1>Loose weight and impress the opposite sex!</h1>
<p>So, let's check our consuming code now!</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 1:</span> AuditManager.TrackAction(Action.Update, currentUser, myData, DateTime.Now);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 2:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 3:</span> (or)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 4:</span>  </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060"> 5:</span> AuditManager.TrackActionEnumerable(Action.Update, currentUser, myData, DateTime.Now);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060"> 6:</span>  </pre>
</div>
</div>
<p> No matter how many auditors we add now, we only have to make one simple call. We no longer have to touch this code.</p>
<p>However, the fact that there is still code there is uggo-fied. That's our <em>last</em> major hurdle to clean up. But how could we remove actually calling our code? That's kind of important. Maybe if we could decorate the functions we needed to audit...hmm....</p>
<p><strong>TO BE CONCLUDED!</strong></p> Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-2430856949934117881.post-15329024694514456422009-03-05T19:48:00.004-06:002009-03-05T19:50:34.506-06:00New templateAs you can tell, I've been working on switching templates. In the time I've spent searching templates, then having to tweak them tons to get them how I want, I should've just written it myself from scratch.
Anyways, this isn't done yet. I need to switch the header image to something I don't hate, and there's still some display issues with IE (surprise I know). I hope to have it ironed out soon.
I like it better. Good news is, I don't care if you do or not! But it's gotta better than reading long blog posts in a stupid narrow-ass column.Unknownnoreply@blogger.com0