Monday, September 29, 2008

Mutual Exclusive CollapsiblePanelExtender

The following piece of code will allow you to have multiple ASP.NET 2.0 Ajax CollapsiblePanelExtender controls on a single page and only one of them will be expanded at a time. You can use this to keep the page length short. You must set the BehaviorId of the CollapsiblePanelExtender, that is what the $find javascript function looks for. Make sure to add all the BehaviorIds to the array in the pageLoad function.

<script type="text/javascript">

// WWB: Handles Mutual Exclusive Expansion.  Only One Extender Panel 
// Can Be Open At A Time

var extenders = [];
   
function pageLoad(sender, args)
{
    extenders[0] = $find("PanelExtender1");
    extenders[1] = $find("PanelExtender2");
    extenders[2] = $find("PanelExtender3");


    // WWB: Hook All The Extenders, If extenders[i] is null then
    // the extenders is not being displayed -- i.e. not visible
    for (var i=0; i< extenders.length; i++)
        if (extenders[i] != null)
            extenders[i].add_expandComplete( expandHandler );
}

function expandHandler(sender, args)
{
    for (var i=0; i< extenders.length; i++)
    {
        if ((extenders[i] != null) && (extenders[i] != sender))
            extenders[i]._doClose();
    }
}
</script>

6230289B-5BEE-409e-932A-2F01FA407A92}

Wednesday, September 17, 2008

Happier Coding

Dina says I am happier when I code and not just during coding.

Some of my friends my age, and yes I am getting older, are moving to management jobs where they don’t code at all. They might be development leads that train and deploy new technologies in bigger companies, or design systems and have others code.

Some of the same friends that interviewed at our smaller company and we didn’t hire because they just didn’t seem right (Where I work now you can’t just design or train since the company is so small). These friends fit right in with the bigger companies; in fact they got jobs as developers however aren’t really doing any development at all. I have a hard time calling these jobs management since they don’t have a lot of people under them; I really just want to call them a “Non-Productive” job – which is reflection of my perspective on how I like coding. I wonder if the bigger companies will “wake up” and make them do something, or force them to do development which they were hired for, or just fire them.

I am not jealous, in fact I tell them about the stuff I am coding in my spare time and they don’t really care at all. Which lead me to realize they really aren’t happier coding?

P.S.

Along with this profound thought, I was out for my afternoon walk in a park near where I work and there was a women spinning wool to yarn in the sun. The first thought is what a waste of time. If I had that time, I would be coding something. Why doesn’t she code, what is the point of spinning yarn – someone in China and do it faster, better with a machine. Doesn’t she realize that we are living in a quickly changing Internet world and she could make her mark on our era with just a single web site. Then again the screen glare on the laptop prevents me from coding in the park on a sunny day. I might be sick.

{6230289B-5BEE-409e-932A-2F01FA407A92}

Monday, September 15, 2008

Indoubt Transaction in MSDTC

For days I have been battling with MSDTC (Microsoft Distributed Transaction Server) and transaction that have the status of indoubt.  We are using the .NET System.Transactions.TransactionScope class to wrap many SQL Server calls together in a single transaction, which requires MSDTC to manage the transaction.  The application would run for 30 minutes then hang, timing out, and the table on SQL Server would end up being row locked -- hanging all selects, inserts, updates and deletes.  It took me a while to realize that the Kerbose error in the application log on SQL Server was the reason the MSDTC communication was failing -- by comparing the crash time with the error log.  Then doing some research I realized that all those virtual machines running our web servers that we copied around on our virtual servers had the same SID.  Even though we had renamed them and readded them to the domain, that didn't generate a new SID.  So I used Microsoft's NewSID utility to give them different SIDs and I am back in business.

NewId Application:

http://technet.microsoft.com/en-us/sysinternals/bb897418.aspx

Kerbose Error:

Event Type: Error
Event Source: Kerberos
Event Category: None
Event ID: 4
Date:  9/12/2008
Time:  12:10:29 PM
User:  N/A
Computer: LE79TEST
Description:
The kerberos client received a KRB_AP_ERR_MODIFIED error from the server
XXXXX.  The target name used was
XXXX. This indicates that the
password used to encrypt the kerberos service ticket is different than that
on the target server. Commonly, this is due to identically named  machine
accounts in the target realm (XXXX), and the client realm.
Please contact your system administrator.

{6230289B-5BEE-409e-932A-2F01FA407A92}

Friday, September 12, 2008

DataBind() on Postback

Please junior developers don't Databind() your GridView on Postback.  You only need to databind your GridView once, when the page is first loaded (and anytime the data changes).  However, if you are lazy then you will DataBind on every postback forcing the GridView to go to the data source every postback and making your page slow. 

Your junior code:

protected void Page_Load(object sender, EventArgs e)
{
    ERSGridView1.DataBind();
}

My code:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
        ERSGridView1.DataBind();
}

But, But...

Yes DataItem will not be accessible on Postback, so this code will not work:

protected void ERSGridView1_SelectedIndexChanged(object sender, EventArgs e)
{
   object myData = ERSGridView1.SelectedRow.DataItem;
}
You will have to do this:
protected void ERSGridView1_SelectedIndexChanged(object sender, EventArgs e)
{
   Int32 primaryKey = (Int32)ERSGridView1.DataKeys[ERSGridView1.SelectedIndex].Value;
   // Fetch Object From Data Source
}

I know, you have to fetch the object if the row is selected, however this is much better performance and more scaliable then fetching the all the objects on every post back.  Yes, the gridview will display all the rows if you don't DataBind, that is becuase it saves that information in ViewState and repopulates the row.

Two years ago this might not be as important.  However when you start Ajaxing your page (with Microsoft's ATLAS Extenders) there ends up being a lot more PostBacks that don't involve data changes.

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

 

RaisePostBackEvent and RegisterRequiresRaiseEvent

ASP.NET 2.0

You do not have to call Page.RegisterRequiresRaiseEvent() in order for IPostBackEventHandler.RaisePostBackEvent() event to be called. In fact calling Page.RegisterRequiresRaiseEvent() will interfer with all other controls on the page that need post back events. The only way calling Page.RegisterRequiresRaiseEvent() actually works is if that is the only control on the page. GridView doesn't have to call Page.RegisterRequiresRaiseEvent().

However, implementing just IPostBackEventHandler isn't good enough, you need to implement: IPostBackDataHandler also on your control. If you don't then IPostBackEventHandler.RaisePostBackEvent() will never be called.

{6230289B-5BEE-409e-932A-2F01FA407A92}

Monday, September 8, 2008

/useenv on the command line.

/useenv as s command line switch in Visual Studio 2005 is described as: "Use the following command line switches to display the integrated development environment and perform the described task." as opposed to: "Use the following command line switches to perform the described task. These command line switches do not display the IDE."  Reference: http://msdn.microsoft.com/en-us/library/xee0c8y7(VS.80).aspx  Which would make you think that /useenv is a switch for the IDE, however if you don't use it on the command line your settings for INCLUDE and LIB enviormental variables will not be used, making it very difficult to switch between platform SDK include files for your different OS versions.

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

Sunday, September 7, 2008

Warning As Error CS1668 -- Not the Usually Excuse

You can get CS1668 if you set your LIB path like this in your .bat file that builds your project using devenv.exe:

SET LIB="c:\Program Files\Microsoft SDKs\Windows\v6.0\Lib\"

instead of like this (the right way):

SET LIB=c:\Program Files\Microsoft SDKs\Windows\v6.0\Lib\

Note the quotes. Time Wasted: 2 hours.

The usual suspect:

http://msdn.microsoft.com/en-us/library/tcbs315h(VS.80).aspx

{6230289B-5BEE-409e-932A-2F01FA407A92}

Friday, September 5, 2008

Google Chrome And IIS 5.0

Don't get me wrong, I like Google Chrome, and it's application shortcut that makes a web application appear like a windows application is an eye opener.  However, it reminds me of IIS 5.0.  When IIS 5.0 was released everyone was so excited that you could run the web site application in a separate process, giving you one process per web site.  This meant if a web site crashed it wouldn't take down the rest of the sites on the server.  However, it was soon realized that windows can only handle a finite amount of threads somewhere between 500 - 800 before it slows to a crawl.  This is why you need to be very careful when multi-threading. All the IIS 5.0 web sites with 5-10 threads a piece where chocking the OS.   So IIS 5.0 was replaced with IIS 6.0 where you could group web sites into a single process.  Back to Chrome: 26 threads just to run Pandora.com in one process.  The other processes are running 9 threads a piece.  Just for you that don't know, each tab in Chrome runs in a separate window process and closing a tab closes the process, freeing the OS resources, threads, memory, etc... A noble idea to contain and isolate web applications that have run away javascript.  However, this isn't Linux -- you can't just fork as much as you want.

{6230289B-5BEE-409e-932A-2F01FA407A92}

Wednesday, September 3, 2008

Mapping in SQL Server Reporting Services

n honor of William Vaugh showing up at our local .NET user group, I am posting a SSRS article about how to add maps to your SQL Server Reporting Service reports. Google Map has static mapping functionality in their API set. Static maps are the ability to call a URL on the Google server and get back a single image of the map. This is different then using the Ajax objects in your web page, since those objects need the javascript engine to excute. With SSRS you don't get a javascript engine and you can't be guareenteed that it will be a web page, the export might be a PDF. Google Maps API for static maps takes a Query string like this example: http://maps.google.com/staticmap?center=40.714728,-73.998672&zoom=14&size=512x512&maptype=mobile\&markers=40.702147,-74.015794,blues%7C40.711614,-74.012318,greeng%7C40.718217,-73.998284,redc\&key=MAPS_API_KEY With good eyes you can see that it sets the center, zoom, and some markets on the map. First thing to do is drop the zoom and center, the map will auto center with the markers. Here are the steps: 1) Create a new Report in SSRS, try to avoid the wizard, however if you can't use some Random T-SQL to get past it. 2) Delete the table or matrix the wizard created for you. 3) Create a Image, using a Web image, and add the URL above. 4) Create a new Data Set, Here is the T-SQL I used to create my markers:
DECLARE @Markers varchar(max) 
DECLARE @latitude float 
DECLARE @longitude float 

SET @Markers = 'markers=' 

DECLARE _cursor CURSOR FOR 
SELECT DISTINCT TOP 50 Latitude, Longitude 
FROM MapTable 
WHERE (NOT Latitude IS NULL) AND (NOT Longitude IS NULL) 

OPEN _cursor 
FETCH NEXT FROM _cursor 
INTO @latitude, @longitude 

WHILE @@FETCH_STATUS = 0 
BEGIN 

IF ((NOT (@latitude IS NULL)) AND (NOT (@longitude IS NULL))) 
SET @Markers = @Markers + CONVERT(varchar(max),@latitude) + ',' + CONVERT(varchar(max),@longitude) + ',tinyred%7C' 

FETCH NEXT FROM _cursor 
INTO @latitude, @longitude 

END 

CLOSE _cursor 
DEALLOCATE _cursor 

SELECT @Markers AS Marker 
5) Click on the Image in your preview window and open the properties. Change the Value from the static URL to this dynamic URL: ="http://maps.google.com/staticmap?size=640x640&maptype=mobile&" + Fields!Marker.Value + "&key=YourKey" Notes: - Google Static Map API only allows you to map 50 markers, that is why the SELECT is TOP 50 - There are two property windows for SSRS reports, you need the one that is dockable, not the pop-up property dialog. The Value property is only in the dockable one. Use the tool bar, choose View, Then Property Window. - You will need to insert your Google Key, note that with static image it isn't related to the web site the image on, since the image might be in a PDF, it is just a way to track your usage. More Info: http://code.google.com/apis/maps/documentation/staticmaps/ {6230289B-5BEE-409e-932A-2F01FA407A92}