Monday, May 11, 2009

Poor man’s MVC

Hi, I’m considering using a what I call a poor man’s MVC for a project at work.  Actually the more I think about it, the more I think I’m going to use Fubu, so I figured I’d blog this out before I forgot about it.

The idea is that if you are in a medieval torture chamber and are being forced to use WebForms to write an app you could do the following.

Let’s say you have a page with the following event’s on it. 

Load()

ApplyThumbscrew()

ListenToScreams()

the Load you surely recognize as one of the god awful page life cycle events. ApplyThumScrew() and ListenToScreams() are obviously ways that a user can enjoy ones self.  They click a button and said event happens.

For each page you will have a corresponding controller ( or presenter if you will.  I’d rather not. ).  The Controller will have corresponding methods to the Page.  It will also have a specific input and output.  The sig will look something like this.

public ApplyThumbscrewOutputModel ApplyThumbscrew(ApplyThumbscrewInputModel input) { }

the input and output models are just DTOs. The input model has everything form the page that you need to do you stuff.  the output model has everything that the page needs from the server to do it’s stuff.

so the ApplyThumbScrew() event would look like this

but wait first let me tell you that you should be using Dependency Injection for the controller ( and later the torture object ) and a proper IOC Container.  But that is beyond the scope of this blog and would require that I write more code in this horrible editor.

protected void ApplyThumbscrew(blah blah blah)

{

var input new ApplyThumbScrew{

SizeOfThumb = txtSizeOfThumb.Text,          

HowBadIsPerson = txtHowBad.Text,                          

HowSickAreYou = txtHowSick.Text,           

                                           };

var controller = new TortureController();

var output = controller.ApplyThumbScrew(input);

// then do something with return. my imagination is waning

txtPersonsThumb.text = output.PainExpression;

txtUsersEnjoyment.text = output.Enjoyment;

}

Then the corresponding Controller action would look like so

public ApplyThumbscrewOutputModel ApplyThumbscrew(ApplyThumbscrewInputModel input)

{

var torture = new InterigationTechnique();

var fun = torture.DoTheScrew(input.SizeOfThumb,input.HowBadIsPerson,input.HowSickAreYou);

return new ApplyThumbscrewOutputModel{

PainExpression=fun.Pain;

Enjoyment = fun.Enjoyment;

                                                        };

}

 

So you get the idea.  coding like this sucks and the formatting is all fubar so no more code.

But the idea is that now you have the “codebehind” doing nothing but view related stuff.  I harvests information gives it to a more responsible agent then receives some goo to spread back on the view.  In so doing you have completely severed the nasty httpcontext and Request object and all that untestable shite from the business logic.  Rendering the business code, yep you guessed it, TESTABLE!  yay.  furthermore, if you ever are released from the dungeon, you will have code that you can then hook into any view mechanism you want.  Fubu, Asp.Net, some other shite.

I don’t understand what is going on with the formatting.  this is bullocks.  Anyway, sorry that this is kind of superficial but really you should be using a proper MVC framework anyway, not this webforms crap.

“I am not a crook!” Impersonation

I was recently tasked with creating little web page that monitors the backup files on our servers.  Obviously I’m going to need to use particular credentials since the server hard drives are locked down.

So I set about creating a little impersonation object.  I read a number of blogs and they all seemed to be showing similar systems and then I came across a tutorial from Microsoft.  Now normally I back page as quick as possible when I end up on one of there documentation pages because they are invariably Byzantine, but this time I figured I’d give it a shot.  Well they were saying oh you don’t have to do it this ways ( the way most blogs were showing it ) if you do this and that. So I said aha!  A short cut.  Well after many errors and exceptions it occurred to me to search the code repository on my machine and see if there was anything already there.  Brilliance! Low and behold!  log4net needs to access your file system in order to write it’s logs.  And guess what?  They are doing it the same way everyone else ( except microsoft ) is doing it.  So I kinda stripped out some of the stuff they had that was specific to their use and came up with the following.

public class Impersonator
    {
        private readonly string _userName;
        private readonly string _domainName;
        private readonly string _password;
        private IntPtr _tokenHandle;
        private WindowsIdentity _identity;
        [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 extern static bool CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

        public Impersonator(string userName, string password, string domainName)
        {
            _userName = userName;
            _domainName = domainName;
            _password = password;
            LogonUser();
        }

        private void LogonUser()
        {
            const int LOGON32_PROVIDER_DEFAULT = 0;
            //This parameter causes LogonUser to create a primary token.
            const int LOGON32_LOGON_INTERACTIVE = 2;

            // Call LogonUser to obtain a handle to an access token.
            _tokenHandle = IntPtr.Zero;
            if (!LogonUser(_userName, _domainName, _password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _tokenHandle))
            {
                //log4net error handler.  I'm using log4net so I figured I'd take advantage
                //NativeError error = NativeError.GetLastError();
                throw new Exception("Failed to LogonUser [" + _userName + "] in Domain [" + _domainName + "]."); // Error: " + error.ToString());
            }

            const int SecurityImpersonation = 2;
            IntPtr dupeTokenHandle = IntPtr.Zero;
            if (!DuplicateToken(_tokenHandle, SecurityImpersonation, ref dupeTokenHandle))
            {
                //log4net error handler.  I'm using log4net so I figured I'd take advantage
                //NativeError error = NativeError.GetLastError();
                if (_tokenHandle != IntPtr.Zero)
                {
                    CloseHandle(_tokenHandle);
                }
                throw new Exception("Failed to DuplicateToken after LogonUser."); // Error: " + error.ToString());
            }

            _identity = new WindowsIdentity(dupeTokenHandle);

            // Free the tokens.
            if (dupeTokenHandle != IntPtr.Zero)
            {
                CloseHandle(dupeTokenHandle);
            }
            if (_tokenHandle != IntPtr.Zero)
            {
                CloseHandle(_tokenHandle);
            }
        }

        public IDisposable Impersonate()
        {
            return _identity != null ? new DisposableImpersonationContext(_identity.Impersonate()) : null;
        }

        private sealed class DisposableImpersonationContext : IDisposable
        {
            private readonly WindowsImpersonationContext m_impersonationContext;
            public DisposableImpersonationContext(WindowsImpersonationContext impersonationContext)
            {
                m_impersonationContext = impersonationContext;
            }
            public void Dispose()
            {
                m_impersonationContext.Undo();
            }
        }
    }

 

One would then use it like so

 

  var impersonator = new Impersonator(LoginName, Password, Domain);
            using(impersonator.Impersonate())
            {
                if (!Directory.Exists(DirectoryPath)) return;
                var dir = new DirectoryInfo(DirectoryPath);
             }

Sorry about the code formatting I have to learn how to do this.

After calling the impersonator.Impersonate() method( provided your credentials are proper ) you will be operating under those credentials.  In example I’m accessing a directory on a server that I specified in code else where.

So this is the quick and dirty plus some of my bitching.  Here is a nice post by Rick Strahl who goes into more detail.

Saturday, May 9, 2009

My Current Project

So I’ve been tasked with re writing the booking engine ( basically the check out process for reserving a room at a bed and breakfast ) at work.  The current system was written five years ago and with what seems like a conscious effort towards obscurity, bloat, and inextricability.  The current system was some time after it’s creation cloned and the clone was used to access product listed on a listed on a winforms product.  It’s a little complicated.  

The two use different databases: SqlServer and Oracle, and have diverged considerably over time. There is, as one might imagine, an awful lot of logic in the code behind, the middle tier is composed of almost all static methods and the data layer is a combination of a number of messy home rolled ado wrappers using in line sql.

I’m to combine the two processes into one as well as add considerable new functionality and checkout logic.  I will create a seam where the property ( a bed and breakfast ) has been chosen and the book it button is clicked, and replace everything through where the reservation conformation screen shows.  Sadly I will most likely have to interface with some legacy objects such as the credit card processing object and who knows what else.  And of course I will be using the legacy database schema.

This promises to be a rather exciting project for me.  At the very least I will be able to create a proper business process, in a middle tier, using nice clean SOLID principles.  I will also be able to interface with webforms in my chosen manner ( see next post, if I ever write it ) and hopefully I will be ale to use NHibernate for data access, at least for some of it.  I will be slipping structuremap into the project.  If they don’t like it I can always back it out and use a poor mans dependency injection, but the hope is that they will think DI and StructureMap in particular are very cool.  I believe and or hope that this will sow the seeds of future patterns ( i.e. using NHibernate, SOLID, StructureMap etc ) for future projects.  Hopefully it wont also cost me my job.  You know how people love change.