Brothers In Code

...a serious misallocation of .net resources

Getting Active Directory Information From ASP.net The Easy Way

A couple years ago I wrote a short article on an old blog about connecting to Active Directory from an ASP.net project.  I thought the article was fairly complete until I tried to help somebody else do the same thing.  I had forgotten two major parts:

  • Manually sifting thru the different AD containers to find the right LDAP string. 
  • Ensuring the correct security context.

The security context can be an easy thing.  A console or winforms .net app runs in the context of the currently logged on user.  For simplicity the ASP.Net development server in Visual Studio does the same thing.  So as long as your user account as access to the AD (which is the norm unless your AD admin has locked down querying), then you should be fine while you are developing.

Running under IIS is a different story.  Depending on the version, the user context of the iis process could be all sorts of things - ASPNET, Network Service, Local Service, the new IIS app pool accounts, etc.  During testing the easiest thing to do is enable impersonation:


<configuration>
  <system.web>
    <identity impersonate="true" userName="contoso\Jane" password="********" />
  </system.web>
</configuration>

Optionally, you can remove the userName and password attributes and make sure that NTLM/Integrated security is still checked in the IIS configuration.  This will make IIS operate similar to the ASP.Net Development Server and use the current user as the execution context.

So with the security context out of the way, the next task is to actually query AD for a user object.  In my old example, I would specify the container to connect to whe creating a DirectoryEntry object.  For example:


System.DirectoryServices.DirectoryEntry directoryEntry
        = new System.DirectoryServices.DirectoryEntry(LDAP://CN=Users,DC=contoso,DC=com);

This worked fine for me but was a bit to limiting as an example to go by.  Many domains have an additional "corp" domain context.  "Users" might be named something different like "DomainUsers".  There are all sorts of variables with AD.  To combat this I added an extra query to "RootDSE" which is sort of the current context.  With that I'm able to get the address of an actuall domain controller and from there, can make the query on a higher level.  In the example below, I'm trying to get the AD User object for the currently authenticated user, but there's lots of diagnostic output that would let you find other things or narrow down the container that you're querying (for performance reasons).

 


<%@ Page Language="C#" %>
<%@ Import Namespace="System.DirectoryServices" %>
<%@ Import Namespace="System.Collections.Generic" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
      OptLocalUser.Text = User.Identity.Name;
     
      Dictionary<String, String> directoryPropertyDictionary;
       
     
      //get the currently connected AD server info:
      DirectoryEntry de = new DirectoryEntry("LDAP://RootDSE");
     
      directoryPropertyDictionary = new Dictionary<string, string>(de.Properties.Count);
      foreach (string key in de.Properties.PropertyNames)
      {
        String allValues = "";
        foreach (object value in de.Properties[key])
          allValues += value;
        directoryPropertyDictionary.Add(key, allValues);
      }
      GridView1.DataSource = directoryPropertyDictionary;
      GridView1.DataBind();
     
      //connect to the current server
      de = new DirectoryEntry("LDAP://" + de.Properties["dnsHostName"][0].ToString());

      DirectorySearcher ds = new DirectorySearcher(de);
      String[] nameParts = User.Identity.Name.Split('\\');
      ds.Filter = "(&(objectClass=user)(sAMAccountName=" + nameParts[1] + "))";
      SearchResult result = ds.FindOne();


      OptUserPath.Text = result.Path;
      directoryPropertyDictionary.Clear();
      foreach (string key in result.Properties.PropertyNames)
      {
        String allValues = "";
        foreach (object value in de.Properties[key])
          allValues += value;
        directoryPropertyDictionary.Add(key, allValues);
      }
      GridView2.DataSource = directoryPropertyDictionary;
      GridView2.DataBind();

      OptLocalUser.Text = User.Identity.Name;
    }
  </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
      Local User:<asp:Label ID="OptLocalUser" runat="server" /><br/>
     
      RootDSE:
      <asp:GridView ID="GridView1" runat="server">
      </asp:GridView>
     
      AD User Path:<asp:Label ID="OptUserPath" runat="server" /><br/>
      <asp:GridView ID="GridView2" runat="server">
      </asp:GridView>
    </div>
    </form>
</body>
</html>

AsyncPostBackTrigger On A Control External To An Update Panel Doesn't Display An Update Progress Control

Consider the following code:


    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>   
    <div>
      <asp:Label ID="Label2" runat="server" Text="Label"></asp:Label>
      <asp:Button ID="Button2" runat="server" Text="Button" />
      <asp:Button ID="Button3" runat="server" Text="Button" />
      <asp:UpdatePanel ID="UpdatePanel1" runat="server">
   <Triggers>
     <asp:AsyncPostBackTrigger ControlID="Button2" />
   </Triggers>
      <ContentTemplate>
        <asp:Button ID="Button1" runat="server" Text="Button" />
        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
      </ContentTemplate>
      </asp:UpdatePanel>
     <asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1">
      <ProgressTemplate>
       Please Wait
      </ProgressTemplate>
     </asp:UpdateProgress>
    </div>


//code behind:
  protected void Page_Load(object sender, EventArgs e)
  {
    Label1.Text = DateTime.Now.ToString();
    Label2.Text = DateTime.Now.ToString();

    if (Page.IsPostBack)
    {
      System.Threading.Thread.Sleep(2000);
    }
  }

In the above example, Button1 will do a partial page update for UpdatePanel1.  Button3 will cause a full postback.  Button two will also do a partial page update for UpdatePanel1 since it is listed as a trigger.  However, Button2 will not cause UpdateProgress1 to be displayed.

There is some help for this on the buttom of an article on codeproject.com, but I needed something for multiple controls.  My solution ended up being two functions:


  private void RegisterExternalTriggerFixForUpdateProgress()
  {
    String updateProgressWTriggerFix = @"
      var triggerMappings = new Array();

      function TriggerMapping(controlId, updatePanelId)
        {
          this.TriggerControlId = controlId;
          this.UpdatePanelId = updatePanelId;
        }
        function RegisterTriggerMapping(controlId, updatePanelId)
        {
          triggerMappings.push(new TriggerMapping(controlId, updatePanelId));
        }
        function GetTriggerMapping(control)
        {
          for(var i=0; i<triggerMappings.length; i++)
          {
            if(triggerMappings[i].TriggerControlId == control.id)
            {
              return triggerMappings[i];
            }
          }
          return null;
        }

        var prm = Sys.WebForms.PageRequestManager.getInstance();
        function CancelAsyncPostBack() {
            if (prm.get_isInAsyncPostBack()) {
              prm.abortPostBack();
            }
        }


        prm.add_initializeRequest(InitializeRequest);
        prm.add_endRequest(EndRequest);
        var postBackElement;
        function InitializeRequest(sender, args) {
            if (prm.get_isInAsyncPostBack()) {
                args.set_cancel(true);
            }
            postBackElement = args.get_postBackElement();
       
            var triggerMapping = GetTriggerMapping(postBackElement);
            if (triggerMapping != null) {
                $get(triggerMapping.UpdatePanelId).style.display = 'block';
            }
        }
        function EndRequest(sender, args) {
            var triggerMapping = GetTriggerMapping(postBackElement);
            if (triggerMapping != null) {
                $get(triggerMapping.UpdatePanelId).style.display = 'none';
            }
        }";

    this.Page.ClientScript.RegisterStartupScript(typeof(Page), "UpdateProgressWTriggerFix", updateProgressWTriggerFix, true);
  }
  protected void RegisterExternalAsyncTrigger(Control triggerControl)
  {
    this.Page.ClientScript.RegisterStartupScript(
      this.GetType(),
      triggerControl.ClientID,
      String.Format(@"RegisterTriggerMapping('{0}','{1}');",
        triggerControl.ClientID,
        UpdateProgress1.ClientID),
      true);
  }

Then to fix a particular AsyncPostBackTrigger control, you just need the following call in your Page_Load:


    //fix for async update from a control outside of the update panel
    RegisterExternalTriggerFixForUpdateProgress();
    RegisterExternalAsyncTrigger(Button2);

Keep a Winforms Application in the Foreground

I needed a way to force an application to stay on top.  I thought it would be as simple as "this.Activate" in the form's deactivate event.  It looked like it was trying to work - when clicking out of the app, it's start bar button would blink, but it wouldn't bring the app back on top.  I then proceeded to try just about everything under the sun:

  • Form.Activate
  • Form.BringToFront
  • Form.Focus
  • Form.Show
  • [DllImport("User32.dll")]
    public static extern Int32 SetForegroundWindow(int hWnd);

Everything seemed to do the same thing.  Finally I thought that maybe I was trying to refocus the form too soon.  I decided to create a timer and delay the Activate call:

//declare the timer
private System.Timers.Timer restoreFocusTimer = new System.Timers.Timer();

//setup the timer in the constructor
restoreFocusTimer.AutoReset = false;
restoreFocusTimer.SynchronizingObject = this;
restoreFocusTimer.Interval = 1000;
restoreFocusTimer.Elapsed += new System.Timers.ElapsedEventHandler(restoreFocusTimer_Elapsed);

//define the handler
void restoreFocusTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
  this.Activate();
}


//enable the timer in the deactivate event (I also added a preprocessor directive so i could disable it when debugging.
private void MainForm_Deactivate(object sender, EventArgs e)
{
  if (!this.formClosing)
  {
    #if !NOALWAYSONTOP
    restoreFocusTimer.Enabled = true;
    #endif
   }
}

 

Is Your Next Programmer a Moron?

We have been interviewing for a .net developer position for quite a while - way too long in fact.  What I thought would be a quick interview process has turned into a very rude awaking.

When I was looking for a job I was contacted by a contractor with a position that interested me.  I was warned however, that the interview process included a 4 hour programming test.  Many bodies had been thrown at this test and very few succeeded.  I try not to be arrogant but I do like to think that I'm good at my job.  Plus I have no certifications and no big name companies on my resume so I usually welcome the chance to prove myself.  The test wasn't rocket science but it wasn't simple either.  It was a simple recursion/stack problem, some database queries, a basic dynamic web page problem, and creating a functional calendar.  It was a lot of time to give a prospective employer but when I got the job I thought the test was well worth it after so many other companies didn't even give me a phone call or an email.

OK, a year later I'm looking to clone myself.  As much as I thought the test was warranted, I also thought that 4 hours is a really long time.  I created a trimmed down version that was nothing more than sql queries and a simple databinding exercise.  After a few candidates we decided it was too data-centric.  My boss forwarded me the fizz-buzz question.  I just couldn't believe what it's author was saying; senior level programmers can't write this trivial block of code?  As more of an experiment than anything, we added in our own variation of fizz-buzz.

And this is where the horror starts.  The very next candidate came in, sat down for 20 minutes, and asked to leave citing "personal reasons" without writing a single line of code.  I couldn't believe it.  I examined all the possibilities: Maybe she didn't understand the mod operator?  I suppose you could do years of CRUD style programming and never need it?  Maybe she couldn't read English?  Maybe she was a VB.net programmer (the test is in C#)?  But then there was always the last option - this 10 page resume couldn't actually write code.

We had another come in and at least attempt it but also failed miserably.  Another came in and passed fizz-buzz, but couldn't write a database query to save his life.  Another came in and did do well on both fizz-buzz and the queries.  He didn't even know ASP.net, but because he at least seemed like he had his head screwed on straight we were willing to train him.  But problems with his contracting house kept him from coming aboard.

I couldn't get over that fizz-buzz relies very heavily on a single operator.  I think it was denial more than anything.  I couldn't help but thinking something is wrong with the test instead of the candidates.   Consequently, I added another simple question.  It only required a boolean be returned if a second phrase could be made from the letters of the first phrase.  I figured if they couldn't do fizz-buzz I'd give them a second attempt.

Originally we had advertised only a 3 month contract and we theorized that the short contract was one of the reasons behind the substandard pool we were pulling from.  We upgraded the position to a 6 month contract to hire and called back a promising applicant that originally turned the short contract down.  I started with him just like I did with everybody else; I explained each question, showed him where the answers were (yes we display what the exact answer should look like), went over any hang-ups that I thought he might have, and reiterated that he can ask any question.  I didn't even get thru explaining my new anagram question when he stopped me and said something like "if this is the what you're looking for I don't think I want to work here."  I reiterated that it's OK if there were parts that he couldn't do.  He didn't care.  I brought him back to my boss and he asked what he didn't like about the test, he referred to it as a bunch of puzzle questions that he needed google for and that we should look at his resume to the systems he's "architected."  I walked him out and he described his (superior) interview process of asking questions about polymorphism and factory patterns.  I just wanted to slap him and say "Don't you understand?  It's people like you why we do this!  Yes you can use some big words and put fancy projects on your resume.  You can call yourself a senior developer and an architect.  But you can't write code!!"

On my way back to my desk I realized my blood was boiling.  I understood why good developers either can't find a job or can't get the pay they deserve.  I understood why so many projects fail.  I understood why I spend so much time cleaning up crap.  I understood why we have been trying to fill a position for 2 months.  It's because it would appear that the ratio of fake to genuine developer resumes out there is about 5:1 or worse!  And the really bad news is that these simple tests don't even guarantee that you have a good programmer.  They only tell you if you have a programmer at all. 

The moral of the story?  If you want to build a house, hire a guy that can hammer a nail.  If you want to build a car, hire a guy that can loosen a bolt.  If you want to build a piece of software, than hire a developer that can write programming 101 code.  Test your programmers! 

Unwanted Assembly/EXE Sharing in Windows Mobile

I just got done merging two Windows Mobile applications into one and a user complained that the combined version was missing a feature of one of the original apps.  As I set out to prove him wrong I bumped into something very wierd.  I set a breakpoint in the event in the old app that I was expecting to check and nothing happened.  The form in the app did absolutely nothing.  However, I was pushing all http traffic from the mobile device thru fiddler and I could see that the form was hitting the webservice that the new combined app was supposed to be using.  The device also gave the beep code I had programmed in after a successful operation.  I put a breakpoint in a couple of other methods like Form.Load and Form.Close and even a couple of Button.Click events and those I was able to debug.  I wasn't loading any assemblies in the GAC but even if I was I couldn't explain this partial debugging ability.  The new app was on the device but it was in a separate folder so at first I disregarding the possibility that I was getting some sort of cross contamination.  But then I thought what if the other app is actually running?  Sure enough, after checking task manager, I could see the new app was running in the background and killing it let me debug the old app.  How did this happen?  The classes do have the same namespace and name but I've never heard of an app sharing another app's code in memory.

Catching 'Thrown' Exceptions in Visual Studio

Every once in a while I'll have an app crash without any warning at all.  One minute it's there, one minute it's not.  No exception message, no break in visual studio while debugging, nothing.  Each time this happens I just allow visual studio to catch 'thrown' exceptions rather than just 'user-unhandled' exceptions.  This means that visual studio will break right at the time it occurs, rather than letting it bubble up to see if it will be handled later in the code.  Go to File>Debug>Exceptions and check the 'Thrown' boxes...

Event-Based Keyboard Wedge Scanner

I just came off a project programming Motorola barcode canners based on Windows Mobile.  The Motorola/Symbol API was top notch and provided access to everything I needed.  This included an event driven API for the scanner.  This meant I had a nice "Scan" event to use from within my code rather than rely on simple keyboard emulation.  This great when a single barcode had multiple fields of data.  I could parse everything behind the scenes without using a "capture" field on my forms.

The next project also needed a barcode scanner but would be a Winforms app rather than a mobile app.  To my surprise the APIs for these usb and serial scanners were not nearly as good.  Only a select few scanners supported Motorola's usb SNAPI interface, and there was no native .net support there (just a bunch of DllImports).  Others had an RS232 based interface but it wasn't much better than reading raw data from the serial port.  A few of the scanners supported the OPOS standard which means I could have used POS for .net but that seemed overkill for my needs.

Finally I realized there was a much simpler solution.  Most of these scanners supported a keyboard emulation mode.  More importantly they supported the ability to be programmed to include prefixes and suffixes in the scan.  While most would use this feature to send an 'Enter' after a successful scan, I realized I could use this to send special characters to indicate the start and end of a scan and separate it from normal keyboard input.  From there making my own API was simple.

There were two main points to this.  The first was to monitor keypresses:

HostForm.KeyPreview = true;
this.enabled = true;
if (this.enabled)
{
  HostForm.KeyPress += new KeyPressEventHandler(KeyPressHandler);
}
else
{
  HostForm.KeyPress -= KeyPressHandler;
}

The line of interest here should be the Form.KeyPreview=true.  This allows you to pickup keyboard strokes at the form level rather than from the control with focus.

From there it's just a matter of looking for the started and ending characters (i chose ctrl-s and ctrl-t, ascii char 19 and 20 resp):

public void KeyPressHandler(object sender, KeyPressEventArgs e)
{
  //if a scan has started...
  if (!IsScanning && e.KeyChar == ScanStartCharacter)
  {
    IsScanning = true;
    timeoutTimer.Start();
    e.Handled = true;
    OnScanStarted();
  }
  //if a scan is in progress and is not being terminated...
  else if (IsScanning && e.KeyChar != ScanEndCharacter)
  {
    timeoutTimer.Stop();
    //...then add the char to the buffer
    scanBuffer.Append(e.KeyChar);

    timeoutTimer.Start();
    e.Handled = true;
  }
  //if a scan has ended
  else if (e.KeyChar == ScanEndCharacter)
  {
    timeoutTimer.Stop();

    CompleteScan(false);

    e.Handled = true;
  }
  else  //not scanning, pass the character on as keyboard input.
  {
    e.Handled = false;
  }
}

I threw a timer in there just to make sure the scan eventually completes, even if the user forgets to program the suffix into the scanner.

That's pretty much it.  The full code is attached.

Easy UI Thread Management with System.Timers.Timer

There's a great article on msdn that covers the 3 different types of timers.  I've basically boiled it down to this:

  • Use the Forms.Timer for simple updates to the UI.  For example i like to bold certain errors when they happen and then return them to a normal font.  This helps the user identify when they caused the same error twice.
  • Use the Threading.Timer to execute one-off processes off of the UI thread
  • Use the Timers.Timer to execute recurring processes.  This timer's AutoReset and Enabled properties make it much cleaner to use than Threading.Timer's Change method.

I tended to lean to Threading.Timer in most cases.  When I needed to do something on the UI thread i just used Invoke.  What I missed from the article is Timers.Timer's SynchronizingObject property.  Simply set this to your form or something else on your UI thread, and no "InvokeRequired" code is needed to access the UI.  Because of this, this timer has no become my timer of choice.  The only drawback to it compared to the Threading version, is that the Threading version's callback takes an object parameter allowing you to pass some state into the callback.  That's only a minor issue considering you can either create a field to temporarily store this additional data or you can create different "Elapsed" events.

Some other basic threading tips:

  • Don't forget to hold a reference somewhere to your timer.  If there are no references, the timer might be garbage collected before it gets a chance to fire
  • Timers.Timer AutoReset is true by default.  I almost always set this to false and then reset Enabled=true in the Elapsed event.  This avoids any reenterance issues.

Databound Winforms TextBox Reverts Back to Original Value

I had a TextBox that I had bound to a property on a class that implements INotifyProperyChanged.  No matter what I did, I just couldn't get the TextBox to update the bound property.  Each time the text box just reverted back to it's original value.  A simplified version of my class looked like this:

  public class KeyboardWedgeScanner : INotifyPropertyChanged
  {
    public TimeSpan ScanTimeout
    {
      get
      {
        return TimeSpan.FromMilliseconds(timeoutTimer.Interval);
      }
      set
      {
        timeoutTimer.Interval = value.TotalMilliseconds;
        OnPropertyChanged("ScanTimeout");
      }
    }


    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(String propertyName)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }

    #endregion
  }

In my form I bound the textbox with this in my constructor:

InScannerTimeout.DataBindings.Add("Text", scanner, "ScanTimeout");

This is exactly how a bound TextBoxes in another project and it worked fine there.  I messed around with the DataSourceUpdateMode parameter on an overload of Add but that didn't help either.  It wasn't until I set the formattingEnabled property to true did it start working:

InScannerTimeout.DataBindings.Add("Text", scanner, "ScanTimeout", true);

The only thing I can think of is that something about the TimeSpan class requires this to return the TextBox.Text's string value back into an instance of TimeSpan.

 

 


 

 

 

SQL Plus vs. PL/SQL and binding variables between the two.

I had a lightbulb moment yesterday.  My new employer is mostly an oracle shop so I end up spending a lot of time translating what I know about sql server into oracle terms.  But one thing I've struggled with is SQL Plus vs. PL/SQL.  That is until yesterday.   Maybe I never took the time before but a sequence of searches forced me in the right direction.

I'm using very few stored proceedures lately (reasons for which will come in a different post).  Consequently I was looking for ways to execute a batch of statements .net code with the Oracle Data Provider and found my answer here on OTN.  But then i looked at how he was getting variable data out of the command.  He was basically doing what I've always wanted to do with Oracle's SQL Developer.  When using the Sql Server query tools (query analyzer, SSMS), I'd often write myself maintenance procedures that I just kept in a file.  It's no problem to create variables and run sql statements in the exact same way you would from inside of a stored procedure.  Sometimes I could copy nearly the same code into a SqlCommand and it would run just fine.  Oracle isn't like that.  Variables (pl/sql variables at least) must be declared within the 'declare' section of a begin/end block.  These blocks can be 'anonymous' (not in a stored procedure) but once you enter the block things change.  You can't simply do a 'select column from table' for example or you get an 'INTO clause expected' error.  Oracle assumes that you're now in a programming block and not connected to some user interface so it wants you to store the data in some variable.  But how was this .net code getting this v_maxnum variable out?  On some sort of protocol level there must be a way for a human to do the exact same thing.

Finally thanks to Wikipedia, I got it.  SQL Plus is very similar to the combination of cmd.exe and SqlCmd/isql?  The big difference is that line between sqlcmd and t-sql is blurred a little more blurred than it is with SQL Plus and pl/sql.  But once I dug in to sqlcmd a little I realized that other than begin/end blocks it's really not that different.  I guess I really never used sqlcmd for anything but a single statement from the command line.

The big realization came now when I understood the variable types in SQL Plus.  It has both substitution variables (&var and &&var) and regular variables (var myvar varchar2).  But unlike sqlcmd's variables being t-sql variables, SQL Plus's variables are different than PL/SQL variables.  However, PL/SQL can 'bind' SQL Plus variables.  Take the following example.

var myDate varchar2;
begin
  select sysdate into :myDate from dual;
end;
/
print myDate

Now I finally understood what the data provider was doing and consequently I understood SQL Plus a lot better too.