got net?

Kevin Hazzard's Brain Spigot

About the author

Welcome to Kevin Hazzard's blog.
E-mail me Send mail

Recent posts

Recent comments

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

July 2008 Richmond Meet and Code Notes

The Richmond Meet and Code Dinner in Richmond tonight was awesome. We had 30+ people turn out. Our key presenter had to cancel at the very last moment but Justin Etheredge stepped up to the plate and pitted his self-proclaimed meager Ruby skills against the barrage of questions from the crowd. Justin did a great job, nascent Ruby skills or not. Harper Trow also presented on the history and current state of Ruby and man, I've so been looking forward to that! Harper was just great. I sure hope he steps out and presents more often. Harper's whole life experience oozes with "I love .NET and I love everything else, too." We need more of that kind of healthy alternative-yet-embracing thinking in the .NET community I believe.

The Meet and Code Dinner format is excellent, in my opinion. I think what Justin is doing is commendable. The goal of his group is to build up the community, not potential sponsors. He's going to be setting up a website and taking donations via PayPal. I am definitely going to support him financially in his effort.

In between two of Justin's sessions, I presented my ProxyGen tool again. This is the same tool that I presented at the last Richmond .NET Code Camp and at the last NOVA .NET Code Camp. Except this time, I focused not on the task of dynamic proxy generation against WSDL contracts but on the use of the ScriptRuntime and ScriptScope classes in Microsoft.Scripting to host a Python or Ruby scripting engine within a C# application. I think I got the brains of the attendees pumping with ideas which is all I was after. I described an application that could be statically typed and early bound, written in C# with a dynamic lower edge that could be scripted from a remote source. People in the crowd started coming up with all sorts of great ideas to implement business logic in dynamic code and inject it. Awesome thinking!

I've attached the latest build of the ProxyGen code below. Here are a couple of screenshots that show how it works. This first screen shot shows running IPY.EXE to execute a Python script to call a SOAP-based web service with no precompiled proxy. The only magic here is in some dynamic code generation that my ProxyForWsdl class does by downloading the WSDL contract and building classes for services, operations and data contracts. As you can see, I am calling an integer factoring service dynamically. No new Python knowledge yet. But read on.

The next screen shot is of the test harness in the sample code showing how a Python script similar to the one shown in IPY.EXE above can be injected into a C# application.

The C# code to embed the Python engine is simpler than you would think. I wrote a little wrapper class to make it easier to digest:

using System.Collections.Generic;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;

namespace TestHarness
{
    public class DynEngine
    {
        private readonly ScriptEngine _engine;
        private readonly ScriptScope _scope;

        public DynEngine( string engine )
        {
            // get an engine from the script runtime of
            // the desired type
            _engine = ScriptRuntime.Create().GetEngine(engine);

            // creating a scope gives us a dynamic space
            // to run code in
            _scope = _engine.CreateScope();
        }

        public T ExecuteStatements<T>( string codeText,
            string resultVarName,
            IEnumerable<KeyValuePair<string, object>> scriptVars)
        {
            // inject some variables into the scope
            foreach (var kvp in scriptVars)
                _scope.SetVariable(kvp.Key, kvp.Value);

            // "compile" the code and execute it
            var source = _engine.CreateScriptSourceFromString(
                codeText, SourceCodeKind.Statements);
            source.Execute(_scope);

            // pull a typed variable from the scope as the result
            return _scope.GetVariable<T>(resultVarName);
        }

    }
}

Invoking the Python code is as easy as loading up variables into a dictionary, instantiating my wrapper class with the type "py" for Python and calling ExecuteStatements with the Python source code text:

var vars = new Dictionary<string, object>
           {
              { "url", tbUrl.Text },
              { "ep", ep }
           };

var engine = new DynEngine( "py" );
result = (List<int>)engine.ExecuteStatements<object>(
   tbPythonCode.Text, tbEvaluationExpression.Text, vars );

The HTTP path to the web service WSDL contract is passed as a parameter by injecting it as a script variable named url in the Python script. And the ServiceEndpoint is also injected as a variable named ep so that it's Name property can be selected in the Python script. This is a good example of marshalling a .NET object into the script scope where it can be fully discovered and used by a dynamic language. In the DynEngine class shown above, you can see the SetVariable and GetVariable methods on the ScriptScope being used to inject and extract variables as a type of Inter-Process Communication (IPC) mechanism. This isn't the only way to communicate between a host and a dynamic script but it's simple for illustration purposes.

That's pretty much it. Hosting a dynamic Python in C# is not hard at all. In fact, if I referenced the IronRuby assemblies on the TestHarness project, I could switch the "py" constructor parameter to the DynEngine shown above to "rb" and inject Ruby script just as easily. That's literally all we would have to do to move from Python to Ruby in this case. As we used to say in America in the 1980s, that's tasty!

The ProxyGen code's attached below. Be sure to download the IronPython distribution from CodePlex and reference four (4) assemblies in the TestHarness project. I am using IronPython 2.0 Beta 3, by the way. These are the four (4) IronPython assemblies you'll need to reference:

  • IronPython.dll
  • IronPython.Modules.dll
  • Microsoft.Scripting.dll
  • Microsoft.Scripting.Core.dll

All of them can be found in the root of the IronPython BIN distribution ZIP. Here's the ProxyGen code I demoed at the meeting.

ProxyGen20080731.zip (21.40 kb)


Posted by kevin on Thursday, July 31, 2008 10:18 PM
Permalink | Comments (3) | Post RSSRSS comment feed

Moving to CapTech Ventures

My boss, Wei Wang, the CTO here at SnagAJob.com announced my resignation to the rest of the Engineering team a few hours ago. It went very well. Although Wei wishes I weren't making this change, he has been supportive of my decision and my reasons for making it. My peers on the Engineering team expressed some regret but they've also agreed to support me through the change. I reciprocated by giving SnagAJob.com a full four weeks of time for transitioning off of the projects I am heading up. It will take at least that long. I predict nights and weekends of effort to get finished in time.

I am anxious to get started as a Lead Consultant, Architect for CapTech Ventures on 25 August 2008. I have friends at CapTech already including Darrell Norton, Mark Hudson, Matt Borgard, Mark DiGiovanni, Mike Diiorio and Sam Nixon. I'm really looking forward to working with all the great professionals there. It's a great company with a reputation for results.

As the Software Architect here at SnagAJob.com, it has been my job to shepherd everyone through a long and difficult re-architecture process which started in May 2007 and ended in March 2008. It took over 47,000 person hours across every department in the company and was successful in almost every way. We started with a group of folks on the Engineering and Product teams who didn't know much about large scale software design. They were good programmers but honestly hadn't made the leap in their own minds to become developers yet. Over the past year and a half, I've worked day in and out to help them make the transition from programmers to developers. Many of them are now making the leap from developers to real software engineers. It's very exciting to see that kind of growth.

Serving SnagAJob.com has been extremely rewarding. Now I can stand silently in our scrums, just smiling and listening to our developers talk with authority about the risks of not having enough unit testing coverage. They talk about their behavioral and integration testing milestones and their mock object strategies as if they had been doing this for many years. They speak with confidence concerning security and n-tier architecture best practices. Service contracts, operation contracts, data contracts and fault contracts are an integral part of their vocabulary now. Their transformation has been nothing short of amazing. I am pleased, to say the least.

But there comes a time for every Software Architect when he must ask, "What's left for me to do?" It's often said that if you hire a salesperson who's not interested in making money, they will fail miserably. That's because their goals are all wrong. A salesperson's goals must be based on selling stuff and making money. And I think it stands to reason that software architects who can't imagine the day when they won't be needed any longer will never be truly successful either. This is because the goals of software architecture (and software engineering to a certain extent) are not the same as the goals for software development. Development is a set of tasks that lead to other tasks whereas design is a constrained short-term effort. Consider these analogies to make my point clear: How many building architects move into the buildings they design and live there forever? How many civil engineers throw out a tent under the bridges they design to keep an eye on them? You see, in the architectural world, good design is self-deprecating with respect to the current effort because it must be a finishable work. Businesses that depend on architecture of any sort would cease to function if this weren't true.

It's not that I can't continue to contribute here at SnagAJob.com. After all, every good architect has served as a software developer at some point in his career. And there's plenty of software development to do at SnagAJob.com. But much of the growth and planning now is vertical in nature, multiplying the business formula that's working well. My architecture is designed to scale for that. I don't need to stay here to watch it do what I built it to do. I believe that my architecture will also scale horizontally to new products and services as well. We've already observed that phenomenon since we released the new system in March. But, again, the team I will be leaving behind knows how to make horizontal growth happen using the techniques that I taught them.

At CapTech my new job will be to engage in a different sort of multiplicative effort. I hope to multiply the success I've had here at SnagAJob.com across many more companies. Jumping back into consulting makes a lot of sense for me at this stage of my career for all the reasons I've outlined above. To reverse (and hack) an old adage, "Software development is a journey but good software architecture is a destination." At CapTech, I hope to bring many companies to that destination so that their ensuing journies may be successful. I will miss my friends at SnagAJob.com sorely. This is an awesome company run by some of the best business minds with whom I've ever had the privilege to work. It's time for me to move on but if you are in high-tech or human resources worlds and you want to grow, check out SnagAJob.com. To my friends at CapTech, I'll see you soon.


Posted by kevin on Wednesday, July 30, 2008 6:00 PM
Permalink | Comments (5) | Post RSSRSS comment feed

Meet the New Mike

Photo of the my new studio mic and my old mic side-by-side

My new podcasting studio microphone came today. It's the Samson C01U Studio Condenser Microphone recommeded by my mentor Andy Leonard. So far, I really like the new mic. I bought it from an eBay company called Unique Squared because they seemed to carry audio equipment in my price range of high quality and they had a very good rating. Payment was simple via PayPal and the package showed up in just a few days in excellent condition.

I bought what's called the Podcasting Kit which puts together some parts that make a lot of sense for podcasting. These include the C01U mic, of course, a heavy base, a retro-looking spider mount for absorbing vibration noise and a pop filter for taking the edge off of words beginning with that hard "P" sound.

In the picture attached to this blog entry, you can see the old $5 mic in the foreground and the new $112 mic behind it. I thought my friend Joey Beninghove would get a kick out of seeing the two microphones together since he ribbed me in a tweet about this purchase a few days ago.

This mic is all-digital and USB-connected so I was worried about drivers and potential incompatibility. Thankfully, there were no drivers to install for Windows XP. I just plugged the mic into the USB port and Windows XP recognized it right away. I had to adjust the mic volume but I was up in running in just a few minutes. How the setup goes in Windows Vista (or Mojave) or Mac OS X remains to be seen.

The Cakewalk LE (ostensibly meaning Limited Edition, or cripple-ware) software that came with the package was a different story. It installed OK but it was clearly a 1990s style installer that had been cobbled together by someone who didn't really know what he was doing. After being interrupted by about 20 pop up dialogs asking inane questions about features I didn't understand, I got through the installation. However, after the installation, I discovered that the the Cakewalk LE user interface is pretty much incomprehensible for someone like me who has never used audio mixing and voice-over software before. I suppose I'll get the hang of it over time. If you know of some better (hopefully freeware) software that I should be using or if you can aim me at a Cakewalk LE Tutorial, that would be great.

I used the Cakewalk LE software to record a voice version of this blog post as an experiment. You can use the player below or download the MP3 file here. Let me know what you think. Drop me a note anytime, OK?

[mp3:MeetTheNewMike.mp3]


Categories: Fun
Posted by kevin on Monday, July 28, 2008 6:10 PM
Permalink | Comments (5) | Post RSSRSS comment feed

Twitter Has So Many Chances to Screw Up and So Little Time

Could Twitter.com get any worse? OMG. If it's not up, it's spambot-seeking bots are killing my followers. I keep TweetDeck up in the background all day at work. I follow some folks on Twitter, some people follow me. They are my tribe, as they're called, and I love them because they resonate with me. The beauty of the Twitter.com idea is that I can choose those with whom I resonate spiritually, economically, politically, socially, gastronomically, whatever-ically. Get it? I choose. Nobody chooses my tribe for me.

Now, if in choosing, I have some malfeasance in mind, say harvesting profile data and building spam campaigns against a large group of Twitters, I should probably be stopped. A low ratio of followers to followees (those whom I am following) might be one way to identify people with no legitimate motive in the space. Another might be to look at the number of times someone has been blocked by other Twitters, essentially taking the community's vote of confidence into account when deciding who the real spammers are. Still another might be to look at the ratio of followees to tweet volume. In other words, an evil harvester is likely to be watching many, followed by few and contributing very little conversation. There are many algorithms I could cook up that would accurately find the creeps and stop them while leaving the innocents alone.

So, today, I log in to Twitter.com via TweetDeck and see that half of my followers and half of my followees are gone. Months of work building relationships through my friends and their friends just gone. This happened to millions of Twitters, not just me. Massive social energy vanished in the blink of an eye. Really normal, healthy people like Rachel Appel and Kevin Griffin who followed me because we resonated with one another, are now told by Twitter.com, "No, you are not following Kevin Hazzard any longer because who knows why? We just felt like making this change. Have a nice day." Rachel Appel, Kevin Griffin and I don't have any qualities which would make us stand out as potentially malicious. But Rachel lost 36 of her followers. And, Kevin Griffin, who just got started with Twitter.com lost 75% of his followers. I lost 38 of mine, almost half. Poor Ted Neward, whom I follow(ed) because I have great respect for him, went from 243 followers to zero. That's right, Twitter.com thinks it's better for all 243 of us who respect Ted not to hear what he has to say.

And I was already diligent about blocking spambot and fembot followers common to social networks like Twitter.com. To have 79 legitimate followers on July 23rd, 2008, I had already blocked more than 20 spambot followers over the previous few months. This morning, Twitter's own spambot-seeking bots reduced my followers from 79 to 41, cutting out Rachel and Kevin and many others. And Jeff Bezos is investing his hard-earned money in this piece of junk? I suppose he's not as smart as I thought he was. Sorry. I shouldn't say that about Jeff because I don't know him. He must be brilliant. But someone needs to take those Twitter bozos by the scruff of the neck and give them a good shaking. Maybe that's what Jeff Bezos will do. I hope so.

By the way, I was able to recover my followers because TweetDeck, my Twitter client of choice, caches my tribe over time. After Twitter cut my followers, I got a very accurate rendering of my former tribe by clicking the GROUP button in TweetDeck. Twitter had lost them but TweetDeck remembered them. Victory! I added my followers back manually because in Twitter.com's official response to the problem, they claim that some of the losses will never be fully recovered. While my followees have been restored, my followers will have to rediscover me on their own. That will take months.

If you want to see how many followers you or your friends lost today, check out TwitterCounter and type in your screen name in the search field.


Tags: ,
Categories: Rant
Posted by kevin on Thursday, July 24, 2008 7:00 PM
Permalink | Comments (3) | Post RSSRSS comment feed

News Page for the Richmond Code Camp

I've added a permanent news page for the Richmond .NET Code Camp to my site. It has news and information you'll want if you're a .NET developer in the mid-Atlantic region.

http://www.gotnet.biz/Blog/page/Richmond-NET-Code-Camp-News.aspx

Check it out!


Posted by kevin on Tuesday, July 22, 2008 3:25 PM
Permalink | Comments (3) | Post RSSRSS comment feed

Dictionary Classes Benchmarked

A few days ago, I stumbled on an article by Amit Raz about the SortedList<K,T> on Dev102.com. In the article, which compares and contrasts the SortedList collection class in the .NET BCL to the SortedDictionary class, Amit concludes with, "So what is the SortedList good for? Beats me. I deem it useless." His conclusion seemed to be predicated on the fact that the Add() method would throw an exception if the programmer attempted to insert a duplicately keyed entry into a SortedList. However, this is documented behavior. And both the SortedList and the SortedDictionary exhibit that same behavior. An indexer exists on each of those collections that will allow the insertion of a duplicately keyed item. For both classes, duplicates replace the original values when using the indexer.

I had a difficult time following Amit's logic but he's a bright fellow so I wanted to find out if the SortedList really was useless as he had proclaimed. On this page, Microsoft provides a table that describes the benefits and relative drawbacks of these two seemingly similar classes. Long story short, the key advantages of the SortedList<K,T> are that it uses less memory than the SortedDictionary<K,T> and that some of its members that return keys and values are indexed. OK, so the SortedList uses less memory. But what's that latter claim about?

Well, the SortedList<K,T> has a few members that the SortedDictionary<K,T> does not. Among them are:

  • int IndexOfKey( K key )
  • int IndexOfValue( T value )

Kicking around in this class in Reflector, one sees that the internal storage for the SortedList<K,T> is a pair of arrays: one for the keys which is kept in sorted order and one for the values which is kept in insertion order. When using the IndexOfKey method noted above, Array.BinarySearch() is used to perform an efficient search for the desired key. However, the IndexOfValue method uses a brute force (O(n)) scan to find the requested value. Another special case advantage of the SortedList is that insertions are O(1) for data inserted in sorted order whereas for the SortedDictionary, the average insertion cost is around O(log n). In fact, for data already in sorted order, the SortedDictionary pays a bit of a penalty on insertion because of the required balancing of the tree structure used to store the information. More on that later. So, if you have small lists and the keys are already sorted before insertion, the SortedList might be a good choice. If your keys are not sorted, insertion into a SortedList could be as bad as O(n). So it may be that you have to know something about your data to use the SortedList in a way that makes it worthwhile. Not understanding your data, could make the SortedList worthless, as Amit claims.

I wrote a small test harness that exercises the SortedList<K,T> and SortedDictionary<K,T>. I've included a link to the source code below. The application runs a battery of tests using a small list of 1,000 items on each type of dictionary and the same battery using a large list of 40,000 items. The main window looks like this:

These results show an average test run on my Windows Server 2008 machine using the .NET Framework 3.5. For the small list of 1,000 items, the SortedList seems to be a bit more efficient than the SortedDictionary with respect to time, despite the fact that the keys are not in sorted order for that test. However, when it comes to the larger list of 40,000 items, the SortedDictionary is the clear winner for both insertions and removals. But what about memory? Remember that Microsoft's MSDN topic said that the SortedList can be more memory efficient? I put 10 seconds of time in between the 4 test groups shown on the screen shot above and ran the .NET memory profiler to see what was happening. It's not all that conclusive, in my opinion. Here's a graphic showing the Gen 0, 1 and 2 heap sizes over the lifetime of the test. Perhaps you can help me analyze what you see:

There is a very large spike during the third test in the Gen 1 heap size when the large data set of 40,000 values in placed into the SortedList. Most of that newly allocated memory seems to move to the Gen 2 heap when the last test kicks off, returning the Gen 1 heap almost back to it's former value. The internal implementation of the SortedDictionary is based on a private, internal class in System.Collections.Generic called TreeSet<T>. In an upcoming blog post, I will be examining the TreeSet<T> class in detail. It uses a special kind of binary tree implementation known as a red-black tree. Why Microsoft didn't expose this incredibly cool class, I don't understand. So I suppose I should do that, right? Until next time...

Source Code for the DictionaryTestHarness Application (6KB)


Categories: C# | Debugging | Software Dev
Posted by kevin on Sunday, July 13, 2008 8:30 PM
Permalink | Comments (6) | Post RSSRSS comment feed

Accessing Web Services from Silverlight 2

I presented tonight (10 July 2008) to the Richmond .NET User Group. We had a pretty good turnout, I'm guessing 40 to 45 developers. I gave this same presentation at my office today as a dry run and as a training opportunity within the company. It's so good to see the developer community eager to learn. I've attached my slides and the three demonstrations projects I used in this post. I'll be giving this same presentation to the Charlottesville .NET User Group next Thursday (17 July 2008). The abstract we put on both user group websites follows:

Silverlight is a client-side technology. So it’s not really a part of your SOA strategy, right? You may want to think twice about that. SOAP and WSDL support are coming to the web desktop via Silverlight. And Silverlight has good client support for REST+ JSON/POX and RSS/ATOM-based web services, too. During this discussion, we’ll dive into data serialization, security and cross-domain access policy capabilities inside Silverlight 2 Beta 2. We also talk about the nuances and pitfalls of provisioning your web services for an Internet audience. This presentation will be heavy on coding, demonstration and interactive discussion.

Powerpoint Presentation (289KB)

Twitter solution showing how to invoke a cross-domain RESTful service by way of an in-domain SOAP service bypassing the cross-domain access policy problem. (842KB)

REST solution showing how to create RESTful services in WCF and how to consume RESTful services in Silverlight (307KB)

Silverlight syndication solution showing how to consume cross-domain RSS and Atom feeds using the SyndicationFeed class. (11KB)


Posted by kevin on Thursday, July 10, 2008 10:39 PM
Permalink | Comments (3) | Post RSSRSS comment feed

Windows Impersonator Class

I wrote a handy little class called Impersonator a while ago to assist me in doing Windows impersonation. There are dozens of examples of this type of thing on the net. However, none of them were as "handy" as I prefer. By handy, I mean idiot-proof, of course. I like the IDisposable pattern a lot (I use the word pattern here loosely). IDisposable is usually meant to help idiots like me avoid mistakes. And in the case of changing the user identity on the running thread, forgetting to revert to the initial identity could be catastrophic. When combined with C#'s using statement, I get an extra measure of safety from forgetfulness or from rogue exceptions that might be thrown inside the impersonating code.

For the uninitiated, C#'s using statement makes IDisposable really hum by encapsulating the statement's code in a try/finally block where the IDisposable.Dispose method is called automatically and reliably. With my Impersonator class, you can now write code like this:

using (new Impersonator("domain", "username", "password"))
{
   // do whatever you want in here as domain\username
   // the security context will automatically revert on exit
   // when IDisposable.Dispose is called on the Impersonator
}

Pretty simple, huh? The code compiled by the C# compiler would actually look something like this:

Impersonator X = null;
try
{
   X = new Impersonator("domain", "username", "password");
   // do whatever you want in here as domain\username
   // the security context will automatically revert on exit
   // because of the Dispose call in the finally block
}
finally
{
   if (X != null)
      X.Dispose();
}

Now, if IDisposable were a real design pattern, there might be better compiler support. Wouldn't it be great that for classes implementing IDisposable, they could NOT be instantiated outside of a using statement context? That might be a bit restrictive in some cases but think about how fool-proof that would be. If you were required to instantiate IDisposable types within a using statement, you could guarantee that a type, which could be doing radical things like changing the identity on the running thread, would always clean up after itself. Alas, the C# team at Microsoft has been ignoring my plea for help.

Here's the code for the Impersonator class for your enjoyment. Let me know if you like it. I have many other gems like this one lying around.

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace gotnet.Security
{
    /// <summary>
    /// Impersonate a local or domain user. This class uses the IDisposable
    /// pattern to automatically revert to the caller's original security
    /// context safely. When instantiated from within C# code, this class
    /// should always be constructed in a using statement to ensure that the
    /// disposal routine runs. If you are not using VB.NET, you should call
    /// the <see cref="Dispose"/> method in a Finally block.
    /// </summary>
    /// <example>
    /// <code>
    /// // enter the following block of code as user Fortunato
    ///
    /// using (new Impersonator("MyDomain", "Amontillado", "pAs5w0Rd"))
    /// {
    ///     // the running thread identity is now that of user Amontillado
    ///     // execute whatever you like here as the user Amontillado
    ///     // buy some bricks, some mortar, some good wine, etc.
    /// }
    ///
    /// // at this point, the thread identity has reverted to user Fortunato
    /// </code>
    /// </example>
    public class Impersonator : IDisposable
    {
        #region // DllImports
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool LogonUser(String lpszUsername,
            String lpszDomain, String lpszPassword, int dwLogonType,
            int dwLogonProvider, ref IntPtr phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(IntPtr handle);
        #endregion // DllImports

        private readonly IntPtr tokenHandle = new IntPtr(0);
        private readonly WindowsImpersonationContext impersonatedUser; 

        /// <summary>
        /// Impersonate a user. When instantiated from within C# code, this
        /// class should always be constructed in a using statement to ensure
        /// that the disposal routine runs. If you are not using VB.NET, you
        /// should call the <see cref="Dispose"/> method in a Finally block.
        /// </summary>
        /// <param name="domainName">
        /// The domain to authenticate against. May be a machine name.
        /// </param>
        /// <param name="userName">
        /// The user name to authenticate with.
        /// </param>
        /// <param name="password">
        /// The password to authenticate with.
        /// </param>
        /// <exception cref="Win32Exception">
        /// The LogonUser operation failed.
        /// </exception>
        /// <exception cref="UnauthorizedAccessException">
        /// Windows returned the Windows NT status code STATUS_ACCESS_DENIED.
        /// </exception>
        /// <exception cref="OutOfMemoryException">
        /// There is insufficient memory available.
        /// </exception>
        /// <exception cref="System.Security.SecurityException">
        /// The caller does not have the correct permissions.
        /// </exception>
        public Impersonator(string domainName, string userName,
            string password)
        {
            const int LOGON32_PROVIDER_DEFAULT = 0;
            const int LOGON32_LOGON_INTERACTIVE = 2;
            tokenHandle = IntPtr.Zero; 

            if (!LogonUser(userName, domainName, password,
                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                ref tokenHandle))
            {
                int ret = Marshal.GetLastWin32Error();
                throw new Win32Exception(ret);
            }

            WindowsIdentity newId = new WindowsIdentity(tokenHandle);
            impersonatedUser = newId.Impersonate();
        } 

        /// <summary>
        /// Cleanup by reverting the user identity and closing any previously
        /// obtained handles. This method will be called automatically if you
        /// construct the Impersonator object from within a C# using statement.
        /// If you are using VB.NET, be sure to call Dispose from within a
        /// Finally block to make sure it happens. Failure to do so may leave
        /// the running thread in an unusable state.
        /// </summary>
        /// <exception cref="System.Security.SecurityException">
        /// An attempt is made to use this method for any purpose other than
        /// to revert identity to self.
        /// </exception>
        public void Dispose()
        {
            if (impersonatedUser != null)
            {
                impersonatedUser.Undo();
                impersonatedUser.Dispose();
            }
            if (tokenHandle != IntPtr.Zero)
                CloseHandle(tokenHandle);
        }
    }
}


Categories: C# | Security
Posted by kevin on Tuesday, July 08, 2008 11:34 PM
Permalink | Comments (9) | Post RSSRSS comment feed

Efficient Paging in SQL Server via LINQ

UPDATE: I've included a videocast with this blog post. Let me know what you think. 

A few days ago, my buddy Justin Etheredge wrote a blog post about Efficient Paging in SQL Server. I was thinking about how transparent Language Integrated Query (LINQ) makes paging and I thought I'd blog about it. Two of the more interesting extension methods offered by LINQ are Skip() and Take(). You can use these extension methods to skip rows at the beginning of the query result and take only those you want to return. Sounds like paging to me. I wonder if Skip() and Take() used in combination with LINQ to SQL behave as efficiently as Justin's example? Let's take a look. Consider the following LINQ query:

var db = new AdventureWorksDataContext();
var query = from p in db.SalesOrderHeaders
  where p.SalesTerritory.Name.Equals( "Northeast" )
  select new {
    p.Contact.FirstName,
    p.Contact.LastName,
    TotalSales = p.SalesOrderDetails.Sum(
      o => o.OrderQty * o.UnitPrice )
};

This small example uses the AdventureWorks SalesOrderHeaders as the input sequence and shapes the output sequence to include the associated Contact's name parts and the total value of each order. The total value is computed as the OrderQty times the UnitPrice for each associated item in the SalesOrderDetails table. There is a filter placed on the query to restrict the results to orders placed in the 'Northeast' territory. This simple query shows how easy it is to filter, perform arithmetic and use the relationships in a LINQ to SQL data context to traverse table relationships. What does this query look like when it's compiled for execution on SQL Server?

SELECT
  [t2].[FirstName],
  [t2].[LastName],
  (
    SELECT SUM([t4].[value])
    FROM
    (
        SELECT
          (CONVERT(Decimal(29,4),[t3].[OrderQty])) * [t3].[UnitPrice] AS [value],
          [t3].[SalesOrderID]
        FROM [Sales].[SalesOrderDetail] AS [t3]
    ) AS [t4]
    WHERE [t4].[SalesOrderID] = [t0].[SalesOrderID]
  ) AS [TotalSales]
FROM [Sales].[SalesOrderHeader] AS [t0]
LEFT OUTER JOIN [Sales].[SalesTerritory] AS [t1]
  ON [t1].[TerritoryID] = [t0].[TerritoryID]
INNER JOIN [Person].[Contact] AS [t2]
  ON [t2].[ContactID] = [t0].[ContactID]
WHERE [t1].[Name] = @p0

You can see the territory filter applied as a WHERE clause. Note that even when a string literal is used in the C# code, LINQ to SQL still passes filtering variables as parameters. In this case, the territory name 'Northeast' is passed as a variable named @p0. This is always a good practice because it helps to thwart the injection of potentially malicious T-SQL into your query. We can see another interesting feature of LINQ to SQL in the T-SQL that is created called projection. Because the C# code shown above shapes the output sequence to only a few required columns, the LINQ to SQL engine is smart enough to T-SQL shape the query to return only what's needed. Projection often improves query performance and always improves transportation speed on the wire.

Finally, notice that the third column projected into the output sequence, i.e. the sum of each order's value, is instatiated as a two-part, nested sub-SELECT operation in the T-SQL statement. The inner SELECT does the math on the order quantity and price. The containing SELECT aggregates the line item totals and them filters them to the rows selected by the outer query. Nicely done, LINQ! Now, we see that this is a long list, returning thousands of rows. If this query is meant for human consumption, we should break it into smaller chunks to make it easier to handle. How do we do that in LINQ? Add this to the C# code shown before.

var _pageNum = 3;
var _pageSize = 20;
query = query.Skip((_pageNum - 1) * _pageSize).Take(_pageSize);

This modification uses the Skip() and Take() extension methods to skip 40 rows and take the next 20 rows. In other words, at 20 results per page, this query now returns the 3rd page. Though the magic of deferred execution, we can add the Skip() and Take() extentions at any time before we begin iterating over the result set. This comes in handy when you want to enable paging for human consumption but to disable it for B2B or ETL scenarios. Is the paged T-SQL query shown here efficient though? You tell me. Here the T-SQL that is produced:

SELECT
  [t6].[FirstName],
  [t6].[LastName],
  [t6].[value] AS [TotalSales]
FROM
(
  SELECT
    ROW_NUMBER() OVER
    (
      ORDER BY
        [t5].[FirstName],
        [t5].[LastName],
        [t5].[value]
    ) AS [ROW_NUMBER],
    [t5].[FirstName],
    [t5].[LastName],
    [t5].[value]
  FROM
  (
    SELECT
      [t2].[FirstName],
      [t2].[LastName],
      (
        SELECT
          SUM([t4].[value])
        FROM
        (
          SELECT
            (CONVERT(Decimal(29,4),[t3].[OrderQty])) * [t3].[UnitPrice] AS [value],
            [t3].[SalesOrderID]
          FROM [Sales].[SalesOrderDetail] AS [t3]
        ) AS [t4]
        WHERE [t4].[SalesOrderID] = [t0].[SalesOrderID]
      ) AS [value], [t1].[Name]
      FROM [Sales].[SalesOrderHeader] AS [t0]
      LEFT OUTER JOIN [Sales].[SalesTerritory] AS [t1]
        ON [t1].[TerritoryID] = [t0].[TerritoryID]
      INNER JOIN [Person].[Contact] AS [t2]
        ON [t2].[ContactID] = [t0].[ContactID]
    ) AS [t5]
    WHERE [t5].[Name] = @p0
  ) AS [t6]
WHERE [t6].[ROW_NUMBER] BETWEEN @p1 + 1 AND @p1 + @p2
ORDER BY [t6].[ROW_NUMBER]

If you read the query from the inside out, you'll see that on the inside it's essentially the same query that we saw before we added the paging feature. It has all the original SELECTs named t1 through t4 and is wrapped as a new result called t5. The SQL Server ROW_NUMBER() function is used to inject a row number into t5 ordered by all 3 projected columns. That looks a lot like the query Justin showed us in his blog post. Very efficient! The new result containing the row numbers is named t6.

Finally, the t6 result is filtered by a starting row number and ending row number using two new variables @p1 and @p2. For page 3 paged in 20 row chunks as shown above, these variables would have the values 40 and 59, respectively. LINQ to SQL injects these starting and ending row number parameters whenever you use Skip() and Take() together. Well, it almost always does that. If you happen to specify Skip(0), it reverts to the behavior that Take() uses without Skip() which is to use SQL Server's TOP() function instead. LINQ to SQL sure knows how to sweet talk SQL Server, don't you think?


Categories: C# | LINQ | ORM | Software Dev | SQL
Posted by kevin on Sunday, July 06, 2008 12:00 PM
Permalink | Comments (12) | Post RSSRSS comment feed

You Know Your Kids Are Geeks When #1

You know your kids are geeks when...

Dishwasher buttons showing bits 0, 3 and 5 set.

You tell them to use the high-temperature configuration on the dishwasher and they collectively refer to that as setting number 41.


Tags: , ,
Categories: Fun
Posted by kevin on Saturday, July 05, 2008 6:27 PM
Permalink | Comments (0) | Post RSSRSS comment feed