Saturday, October 30, 2010

Connection was Unexpectedly Closed

I encountered an issue were a web service was calling a mainframe web service and every other time I would get the following error.

Error: "The underlying connection was closed: A connection that was expected to be kept alive was closed by the server."

As it turned out the mainframe was not setup to keep connections alive. Due to limitations with the mainframe, changing this functionality was not an option. So a simple partial class handled this automatically.

namespace <webservicenamespace> 
{
  public partial class <webserviceproxy> 
  {
    protected override System.Net.WebRequest GetWebRequest(Uri uri) {
      System.Net.HttpWebRequest webRequest = base.GetWebRequest(uri);

      webRequest.KeepAlive = false;

      return webRequest;
    }
  }
}

Saturday, October 2, 2010

Handling Enumerations from a Web Service with Generic Functions

Looking back at some code I ran across a handy piece of code that I wrote to save a good deal of typing, increase maintainability and readability.

Dealing with enumerations from a web service can be confusing at first. The enumeration field names are the same on both sides (client and server) of the web service, however the values are likely not going to be the same. This is especially true if the enumeration is defined with specific values that don't start with 1. The client side will give the enumeration values starting with 1. This means that when saving the value back to a web service object with a property of the enumeration type, you must make sure that the correct enumeration value is returned.

We run into situations where the enumeration value needs to be resolved from enumeration field name and the enumeration field name needs to be resolved from a value. The to just handle this inline can be rather hard to read and requires duplicate typing. Generic functions to the rescue.

Public Shared Function ParseEnum(Of T)(ByVal value As String) As T
    Return CType(System.Enum.Parse(GetType(T), value, True), T)
End Function


Public Function ResolveEnumToValue(Of T)(ByVal value As Object) As String
    Dim genericType As Type = GetType(T)
    Return [Enum].GetName(genericType, value)
End Function

Thursday, June 17, 2010

Using SQL Transactions in Powershell

It occurred to me that I have not seen a write up on System.Transactions.TransactionScope usage in powershell. I have tried this on Powershell v2, not sure if this works in Powershell 1. So here it goes...

The example below just shows the usage, I leave it as an exercise to the reader to add in the database query code.

"Start. " + [DateTime]::Now().ToString();

try {
 $transScope = New-Object System.Transactions.TransactionScope;

 ## Insert Queries

 "Complete";
 $transScope.Complete();
}
catch [Exception] {
    #$_ | fl * -Force
 Write-Host $_.Exception.ToString();
}
finally {
 if ($transScope) {
  $transScope.Dispose();
 }
}

"Done. " + [DateTime]::Now().ToString();

A more complex example just waiting for SQL statements. It shows some nested transactions.
"Start. " + [DateTime]::Now().ToString();

try {
 $transScope = New-Object System.Transactions.TransactionScope;
 
 ## Insert Queries
 
 try {
  ## Performs queries that are not included in a transaction.
  $transScope2 = New-Object System.Transactions.TransactionScope([System.Transactions.TransactionScopeOption]::Suppress);
  
  ## Insert Queries
  
  $transScope2.Complete();
 }
 finally {
  if ($transScope2) {
   $transScope2.Dispose();
  }
 }
 
 ## Insert Queries

 try {
  ## Perform actions that should be included in a side transaction outside of the enclosing transaction
  $transScope3 = New-Object System.Transactions.TransactionScope([System.Transactions.TransactionScopeOption]::RequiresNew);
  
  ## Insert Queries
  
  $transScope3.Complete();
 }
 finally {
  if ($transScope3) {
   $transScope3.Dispose();
  }
 }
 
 ## Insert Queries
 
 "Complete";
 $transScope.Complete();
}
catch [Exception] {
    #$_ | fl * -Force
 Write-Host $_.Exception.ToString();
}
finally {
 if ($transScope) {
  $transScope.Dispose();
 }
}

"Done. " + [DateTime]::Now().ToString();

Wednesday, June 16, 2010

VB.NET Debug Visualizer for Guids for Visual Studio 2010

Every once in a while I must program in VB.NET. My largest frustration is how Visual Studio handles Guids while debugging VB.NET code.

Seeing "System.Guid" as the value for a variable that contains a Guid is really not helpful. Debugging in C# correctly displays the actual value in the same situation.

Visual Studio provides an avenue to rectify this issue. You can create a new class library project and replace the contents of the default class file with the below code snippet.

<Assembly: DebuggerDisplay("{ToString()}", Target:=GetType(Guid))>

Public Class EmptyGuidVisualizerClass
    ' Empty
End Class

After compiling, copy the DLL to "%USERPROFILE%\My Documents\Visual Studio 2010\Visualizers" and restart Visual Studio. The Guids should resolve to their actual values.

After installing this in Visual Studio 2010, I found that it also works in Visual Studio 2008. The DLL should, likewise, be placed in the Visualizers directory in the Visual Studio 2008 folder in My Documents.

I created a batch file that can be used to install the DLL for 2010 and 2008. The batch file and the DLL must be in the same directory.

@ECHO OFF
SET STARTDIR=%CD%

pushd .

cd "%USERPROFILE%\My Documents"

IF EXIST ".\Visual Studio 2008" (
pushd .
echo "2008 Exists!"
cd ".\Visual Studio 2008"

IF NOT EXIST ".\Visualizers" (
 echo "Creating Visualizers Directory."
 mkdir Visualizers
)

copy "%STARTDIR%\GuidVisualizer.dll" .\Visualizers

popd
)

IF EXIST ".\Visual Studio 2010" (
pushd .
echo "2010 Exists!"
cd ".\Visual Studio 2010"

IF NOT EXIST ".\Visualizers" (
 echo "Creating Visualizers Directory."
 mkdir Visualizers
)

copy "%STARTDIR%\GuidVisualizer.dll" .\Visualizers

popd
)

popd

After creating it, I googled and found someone who came up with almost the same code, http://www.michelrenaud.com/?p=7 . This blog post contains pictures if you care to see the end result. Microsoft Connect has a similar resolved issue: https://connect.microsoft.com/VisualStudio/feedback/details/89801/show-guid-value-in-debug.

Friday, May 21, 2010

Use XQuery to convert a timestamp value to a Base64 string

SQL is a very powerful language, even with its limitations. SQL doesn't have the ability to convert Timestamp values to their base64 representations. However, you can use XQuery to do the conversion for you.

In the example below "Version" is of type Timestamp. I didn't notice any performance degradation during my testing.

SELECT  t1.Version
      , cast(N'' as xml).value('sql:column("t1.Version")', 'varchar(20)') 
FROM Table1 t1

This example opens up a new way to solve problems in SQL. It is intriguing to me to think about the other uses for leveraging XQuery to pick up SQL's slack.

Friday, February 5, 2010

GMail Style Multiple Checkbox Shift Selection

A while ago I ran into a situation where there were a list of check boxes in a ASP.NET GridView control and I wanted to be able to Shift+Click the check boxes like GMail or make a selection in Windows Explorer.

Here is the mocked up code that I came up with using jQuery. I make extensive use of is the predicate selector '$='. Which a very useful trick to get around injecting the ASP.NET client id into JavaScript.
var selectedCheckRow = 2;
function itemToggleSelect(cb, e) {
    var checkAll = $("input[id$='CheckAll']"),
        chkVal = cb.checked,
        idVal = cb.id;
    if (!chkVal && checkAll.attr('checked')) {
        $(".selectAllMsg").hide();
        selectAllPages('false');
        checkAll.attr('checked', false);
    }
    // -- Shift-Click Select on Item Grid -- //
    if (!e) e = event;
    CurrentCheckRow = $("#" + idVal)[0].parentNode.parentNode.rowIndex;
    if (e.shiftKey) {
        ((CurrentCheckRow > selectedCheckRow) ?
            $("input[id$='chkAction']").slice(selectedCheckRow - 2, CurrentCheckRow - 2)    // Selecting down
            : $("input[id$='chkAction']").slice(CurrentCheckRow - 2, selectedCheckRow - 2)  // Selecting up
        ).attr('checked', chkVal)
    }
    // Save checkbox row
    selectedCheckRow = $("#" + idVal)[0].parentNode.parentNode.rowIndex;
}
//Expects: 'true' if all pages should be selected
//         'false' if select only viewable items/page.
function selectAllPages(allPages) {
    $(".selectAllPages").val(allPages);
    var selectAll = $(".selectAllMsg > td");
    selectAll.html((allPages == "true") ?
        "All items on all pages have been selected.  <a  href='#' onclick='ToggleAll(false);return false;'>Clear Selection.</a>" :
        "All items on this page are selected.  <a href='#' onclick='selectAllPages(true);return false;'>Select All Items on All Pages.</a>");
}
function ToggleAll(cb) {
    var msg = $(".selectAllMsg"), selectAll,
        chkVal = cb.checked,
        idVal = cb.id;
    if (chkVal) {
        selectAll = $(".selectAllMsg > td");
        selectAll.html("All items on this page are selected.  <a href='#' onclick='selectAllPages(true);return false;'>Select All Items on All Pages.</a>");
        msg.slideDown(0);
    }
    else
    {
        msg.hide();
        selectAllPages('false');
    }
    $("input[id$='chkAction'],input[id$='CheckAll']").attr('checked', chkVal);
}

Demo
The demo code (view the source to see) is setup to mimic an GridView control. To make this demo function you can click a check box, perhaps '3' and then shift+click another check box, perhaps '7'. Not overly complicated, but could definitely save time over developing from scratch.





Select All




1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17

Sunday, January 31, 2010

Enumeration of All Users in a Group (traversing nested groups) in Active Directory

As a counter part to my previous post, I created a dual of the script which enumerates Groups and their members.

#
#    Enumerate All Users for a Group (including traversing nested groups) 
#        @param distinguishedName - The distinguished name of the object you want to traverse
#    Brock Moeller
#    12/16/2009
#
param (
    $distinguishedName = "CN=SuperGroup,OU=Groups,DC=serv,DC=ubercorp,DC=com" 
)

$roles = @{};
$indent = -1;
filter EnumMember {
    $indent += 1;
    if ($_ -is [System.DirectoryServices.DirectoryEntry]){
        $adsiObj = $_;
    } else {
        $adsiObj = New-Object System.DirectoryServices.DirectoryEntry("LDAP://" + $_);
    }
    if ((-not [String]::IsNullOrEmpty($adsiObj.cn)) -and (-not $roles.ContainsKey($adsiObj.cn))){
        $roles[$adsiObj.cn] = 1;
        $memberOfCount = $adsiObj.member.Count;
        $("`t"*$indent) + $adsiObj.cn + " [$memberOfCount]";
        if (($memberOfCount -gt 0) -and ($indent -lt 900)) {
            $adsiObj.member | EnumRoles;
        }
    }
    $indent -= 1;
}

$user = [adsi]"LDAP://$distinguishedName";
$user;
$buffer = $user.Path + "`n";
$user | EnumMember | % { $buffer += $_ + "`n" };
"Buffer: " + $buffer.ToString();
[System.IO.File]::WriteAllText("$pwd\$($user.cn).txt", $buffer.ToString());

Friday, January 29, 2010

Enumeration of All Groups for a User (traversing nested groups) in Active Directory

I ran into an odd situation where I needed to be able to enumerate all of the groups that a user was a member. I found a lot of programs and scripts that will list the groups for a user, but none that would traverse nested groups.

The script writes the information to a file for better reviewing later. The output adds indentation to help readability.

Here is my solution.

#
#    Enumerate All Groups for a User (including traversing nested groups) 
#        @param distinguishedName - The distinguished name of the object you want to traverse
#        Brock Moeller
#        12/16/2009
#
param (
    $distinguishedName = "CN=Joe Dirt,OU=Users,DC=serv,DC=ubercorp,DC=com" 
)

$roles = @{};
$indent = -1;
filter EnumRoles {
    $indent += 1;
    if ($_ -is [System.DirectoryServices.DirectoryEntry]){
        $adsiObj = $_;
    } else {
        $adsiObj = New-Object System.DirectoryServices.DirectoryEntry("LDAP://" + $_);
    }
    if ((-not [String]::IsNullOrEmpty($adsiObj.cn)) -and (-not $roles.ContainsKey($adsiObj.cn))){
        $roles[$adsiObj.cn] = 1;
        $memberOfCount = $adsiObj.memberOf.Count;
        $("`t"*$indent) + $adsiObj.cn + " [$memberOfCount]";
        if (($memberOfCount -gt 0) -and ($indent -lt 900)) {
            $adsiObj.memberOf | EnumRoles;
        }
    }
    $indent -= 1;
}

$user = [adsi]"LDAP://$distinguishedName";
$user;
$buffer = $user.Path + "`n";
$user | EnumRoles | % { $buffer += $_ + "`n" };
"Buffer: " + $buffer.ToString();
[System.IO.File]::WriteAllText("$pwd\$($user.cn).txt", $buffer.ToString());

Tuesday, January 26, 2010

Google Reader Grease Monkey Script

I was bored one day and decided that I wanted to fix up the Google Reader interface a little bit and this was the result. Sure there are more useful GM scripts, but this is a start.
// ==UserScript==
// @name           Google Reader Fixup
// @namespace      http://intellectualponderings.blogspot.com
// @version        1.0
// @description    Hides the sliding navigation pane.  Hides header below the blog name and the footer bar.  Adds "Info" button next to the blog name to toggle header and footer bar.  
// @include        htt*://www.google.*/reader*
// @include        http://www.google.com/reader/view/*
// ==/UserScript==

var cssHidechromeheader = <><![CDATA[
    #viewer-header, #viewer-footer { display: none; }
    ]]></>.toString();
var cssShowchromeheader = <><![CDATA[
    #viewer-header, #viewer-footer { display: inline; }
    ]]></>.toString();
var cssHideNav= <><![CDATA[
    #chrome-lhn-toggle { display: none; }
    ]]></>.toString();
 
function getElementPosition(element) {
    var pos = {x:0, y:0};
    if (element.offsetParent) {
        while (element.offsetParent) {
            pos.x += element.offsetLeft;
            pos.y += element.offsetTop;
            element = element.offsetParent;
        }
    } else if (element.x) {
        pos.x += element.x;
        pos.y += element.y;
    }
    return pos; 
}

function InfoMouseClick(e) {
    var gei = document.getElementById,
        header = gei('viewer-header'),
        hDisplay = header.style.display,
        footer = gei('viewer-footer'),
        entries = gei('entries'),
        entriesStatus = gei('entries-status');
    if ((hDisplay == "none")||(hDisplay == null)||(hDisplay == "")) {
        header.style.display = footer.style.display = "inline";
        entriesStatus.style.right = "0.5em";
    } else {
        header.style.display = footer.style.display = "none";
    }
    entries.style.height = String(d.documentElement.clientHeight - getElementPosition(entries).y - footer.offsetHeight) + "px";
}

(function () {
    //Initial Styles
    GM_addStyle( cssHidechromeheader );
    GM_addStyle( cssHideNav );
    var chrome = document.getElementById('chrome-header');
    //Button Element
    var buttonStr = " 
 
Info
"; var googbutton=document.createElement('div'); googbutton.className='goog-button-base goog-button-base-outer-box goog-inline-block'; googbutton.style.margin = "0px 0px 0px 6px"; googbutton.innerHTML=buttonStr; chrome.appendChild(googbutton); googbutton.addEventListener('click', InfoMouseClick, false); })();