Infosys Microsoft Alliance and Solutions blog

« January 2009 | Main | March 2009 »

February 26, 2009

Problem in Debugging .NET Reflection Code

The other day I was delivering a session on .net reflection and during the course of the session there were a few console based demo applications that I was showing to the audience. During one such demo, there was some change in code I did based on a query raised by one of the participants and to show how it worked, I put a breakpoint and happily started to debug.

Murphy, I guess had something against me that day and the debugging just won't work correctly.

The code as such worked fine, so if I just ran the application, I got the right results, but during debugging, nothing worked and in the local window in debugging, none of the reflected variables like MethodInfo, FieldInfo, PropertyInfo etc showed any values and the message displayed was - "Function evaluation disabled because a previous function evaluation timed out. You must continue execution to reenable function evaluation."

This was really strange. At this time if I would hit F5, to not worry about watching locals anymore and just the application run, it won't ! The application would hang. No further results were displayed and the process won't terminate. I could still stop the debugging from Visual Studio and that's about it.

I have been debugging code many times, but never seen this issue before. So I decided to take a dump and see if I could gather anything from it. Being on Vista, I could take the dump of the process directly from task manager by just right clicking on the process and selecting - Create Dump File. I then opened this in Windbg and started by displaying the currently executing threads.

0:000> !threads
ThreadCount: 11
UnstartedThread: 0
BackgroundThread: 7
PendingThread: 0
DeadThread: 2
Hosted Runtime: no
                                      PreEmptive   GC Alloc           Lock
       ID OSID ThreadOBJ    State     GC       Context       Domain   Count APT Exception
   0    1  ce4 00264498   201a228 Enabled  01f108dc:01f11fe8 00223438     0 MTA
   2    2 1f9c 0026cff0      b228 Enabled  00000000:00000000 00223438     0 MTA (Finalizer)
XXXX    3 1e90 04f35520  80010228 Enabled  00000000:00000000 00223438     0 Ukn
XXXX    4  370 04f49618  80010228 Enabled  01f192d8:01f19fe8 00223438     0 Ukn
XXXX    5    0 04f48ca8      9820 Enabled  00000000:00000000 00223438     0 MTA
XXXX    6    0 04f65728      9820 Enabled  00000000:00000000 00223438     0 MTA
   5    7 1a84 04f66ae8   180b228 Enabled  00000000:00000000 00223438     0 MTA (Threadpool Worker)
   9    8 273c 04f6b988     8b028 Enabled  01f24698:01f24798 00223438     0 MTA
   6    9  d38 04f66620       228 Enabled  00000000:00000000 00223438     0 Ukn
  10    a 1b04 04f65fa8     8b228 Enabled  01f1e38c:01f1ffe8 00223438     0 MTA
  11    b 1720 04f8a1b8     87028 Enabled  01f33b8c:01f33fe8 00223438     0 STA System.Threading.ThreadAbortException (01f33a34) 

Interestingly, there is a ThreadAbortException on thread 11. It is an STA thread and in all likelihood, the thread on which my console application code was executing. Doing a dump of the clrstack for thread 11 confirmed it.

0:011> !clrstack
OS Thread Id: 0x1720 (11)
ESP       EIP    
0623e994 009216a2 Reflection_Basics.Reflection.Main(System.String[])
0623ec74 6cf51b4c [GCFrame: 0623ec74]
0623f0bc 6cf51b4c [HelperMethodFrame_PROTECTOBJ: 0623f0bc] System.AppDomain._nExecuteAssembly(System.Reflection.Assembly, System.String[])
0623f34c 5f4d4aae System.AppDomain.ExecuteAssembly(System.String, System.Security.Policy.Evidence, System.String[])
0623f368 009214eb Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
0623f390 5f036cf6 System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
0623f39c 5f04019f System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
0623f3b4 5f036c74 System.Threading.ThreadHelper.ThreadStart()
0623f5dc 6cf51b4c [GCFrame: 0623f5dc]  

The top statement showed that this was indeed executing the main method of my demo sample, which is where my sample code was and the one I was trying to debug by putting a breakpoint. Next I tried to see where the exception was actually raised and this is what I got

0:011> !pe 01f33a34
Exception object: 01f33a34
Exception type: System.Threading.ThreadAbortException
Message: Thread was being aborted.
InnerException: <none>
StackTrace (generated):
    SP       IP       Function
    0623E1AC 5FDCA22A System_ni!System.Diagnostics.DiagnosticsConfiguration.Initialize()+0x3a
    0623E1DC 5FDA5449 System_ni!System.Diagnostics.DiagnosticsConfiguration.get_IndentSize()+0x9
    0623E1E8 5FDEECCF System_ni!System.Diagnostics.TraceInternal.InitializeSettings()+0x4f
    0623E1F4 5FDCDD8F System_ni!System.Diagnostics.TraceInternal.get_Listeners()+0x1f

StackTraceString: <none>
HResult: 80131530 

Seems like the exception happened when trying to Initialize the DiagnosticsConfiguration. To get to know what really was happening there I unassembled the code.

0:011> !u 5FDCA22A
preJIT generated code
System.Diagnostics.DiagnosticsConfiguration.Initialize()
Begin 5fdca1f0, size 11f
5fdca1f0 55              push    ebp
5fdca1f1 8bec            mov     ebp,esp
5fdca1f3 57              push    edi
5fdca1f4 56              push    esi
5fdca1f5 53              push    ebx
5fdca1f6 83ec1c          sub     esp,1Ch
5fdca1f9 8d7dd8          lea     edi,[ebp-28h]
5fdca1fc b906000000      mov     ecx,6
5fdca201 33c0            xor     eax,eax
5fdca203 f3ab            rep stos dword ptr es:[edi]
5fdca205 33c0            xor     eax,eax
5fdca207 8945e8          mov     dword ptr [ebp-18h],eax
*** WARNING: Unable to verify checksum for System.ni.dll
5fdca20a 8b0d0013c95f    mov     ecx,dword ptr [System_ni+0x1300 (5fc91300)]
5fdca210 bad7010000      mov     edx,1D7h
5fdca215 e82e8cfbff      call    System_ni+0xf2e48 (5fd82e48) (System_ni)
5fdca21a 8b80a8040000    mov     eax,dword ptr [eax+4A8h]
5fdca220 8945dc          mov     dword ptr [ebp-24h],eax
5fdca223 8bc8            mov     ecx,eax
5fdca225 e8de4dfbff      call    System_ni+0xef008 (5fd7f008) (System.Threading.Monitor.Enter(System.Object), mdToken: 0600122f)
>>> 5fdca22a 8b0d0013c95f    mov     ecx,dword ptr [System_ni+0x1300 (5fc91300)]

5fdca230 e8838cfbff      call    System_ni+0xf2eb8 (5fd82eb8) (System_ni)
5fdca235 83b8ac08000000  cmp     dword ptr [eax+8ACh],0
5fdca23c 7418            je      System_ni+0x13a256 (5fdca256)
5fdca23e c745e400000000  mov     dword ptr [ebp-1Ch],0
5fdca245 c745e8fc000000  mov     dword ptr [ebp-18h],0FCh
5fdca24c 6806a3dc5f      push    offset System_ni+0x13a306 (5fdca306)
5fdca251 e994000000      jmp     System_ni+0x13a2ea (5fdca2ea)
5fdca256 e81da2fbff      call    System_ni+0xf4478 (5fd84478) (System.Configuration.ConfigurationManagerInternalFactory.get_Instance(), mdToken: 060035ac)
5fdca25b 8bc8            mov     ecx,eax
5fdca25d ff154462cb5f    call    dword ptr [System_ni+0x26244 (5fcb6244)] (System_ni)
5fdca263 85c0            test    eax,eax
5fdca265 75d7            jne     System_ni+0x13a23e (5fdca23e)
5fdca267 8b0d0013c95f    mov     ecx,dword ptr [System_ni+0x1300 (5fc91300)]
5fdca26d e8468cfbff      call    System_ni+0xf2eb8 (5fd82eb8) (System_ni)
5fdca272 c780ac08000001000000 mov dword ptr [eax+8ACh],1
5fdca27c 8b0d0013c95f    mov     ecx,dword ptr [System_ni+0x1300 (5fc91300)]
5fdca282 e8898cfbff      call    System_ni+0xf2f10 (5fd82f10) (System_ni)
5fdca287 8945d8          mov     dword ptr [ebp-28h],eax
5fdca28a e81193fbff      call    System_ni+0xf35a0 (5fd835a0) (System.Diagnostics.DiagnosticsConfiguration.GetConfigSection(), mdToken: 06000e14)
5fdca28f 8bc8            mov     ecx,eax
5fdca291 8b45d8          mov     eax,dword ptr [ebp-28h]
5fdca294 8d9034040000    lea     edx,[eax+434h]
5fdca29a e8c98bfbff      call    System_ni+0xf2e68 (5fd82e68) (System_ni)
5fdca29f c745e400000000  mov     dword ptr [ebp-1Ch],0
5fdca2a6 c745e8fc000000  mov     dword ptr [ebp-18h],0FCh
5fdca2ad 68e1a2dc5f      push    offset System_ni+0x13a2e1 (5fdca2e1)
5fdca2b2 eb00            jmp     System_ni+0x13a2b4 (5fdca2b4)
5fdca2b4 8b0d0013c95f    mov     ecx,dword ptr [System_ni+0x1300 (5fc91300)]
5fdca2ba e8f98bfbff      call    System_ni+0xf2eb8 (5fd82eb8) (System_ni)
5fdca2bf c780ac08000002000000 mov dword ptr [eax+8ACh],2
5fdca2c9 58              pop     eax
5fdca2ca ffe0            jmp     eax
5fdca2cc c745e400000000  mov     dword ptr [ebp-1Ch],0
5fdca2d3 c745e8fc000000  mov     dword ptr [ebp-18h],0FCh
5fdca2da 68fda2dc5f      push    offset System_ni+0x13a2fd (5fdca2fd)
5fdca2df eb09            jmp     System_ni+0x13a2ea (5fdca2ea)
5fdca2e1 c745e800000000  mov     dword ptr [ebp-18h],0
5fdca2e8 ebe2            jmp     System_ni+0x13a2cc (5fdca2cc)
5fdca2ea 8b4ddc          mov     ecx,dword ptr [ebp-24h]
5fdca2ed e8264dfbff      call    System_ni+0xef018 (5fd7f018) (System.Threading.Monitor.Exit(System.Object), mdToken: 06001231)
5fdca2f2 58              pop     eax
5fdca2f3 ffe0            jmp     eax
5fdca2f5 8d65f4          lea     esp,[ebp-0Ch]
5fdca2f8 5b              pop     ebx
5fdca2f9 5e              pop     esi
5fdca2fa 5f              pop     edi
5fdca2fb 5d              pop     ebp
5fdca2fc c3              ret
5fdca2fd c745e800000000  mov     dword ptr [ebp-18h],0
5fdca304 ebef            jmp     System_ni+0x13a2f5 (5fdca2f5)
5fdca306 c745e800000000  mov     dword ptr [ebp-18h],0
5fdca30d ebe6            jmp     System_ni+0x13a2f5 (5fdca2f5)
 

Comparing the IP where the exception happened, I got to what was happening at the time the exception was raised. The code seems to have entered a monitor and then tried to move some data to ecx and that seems to have caused the exception. At this point, unfortunately, my debugging skills failed me and I could go further.

However here are some other findings

1. This issue happened only with a console based application. If I had the same code in a winform application, the debugging worked perfectly.

2. The issue also didn't happen if I disabled the Visual Studio host process. This meant that when I was debugging earlier the code was running inside of <app>.vshost.exe and with it switched of, it was the EXE that was directly being debugged and it worked fine.

So conclusion is something went wrong when debugging via VS host process for a console based application. If you have seen similar issue and know what really has gone wrong, I will be happy to hear from you. If you have any tips on how to further debug in Windbg, even that will be welcome.

February 22, 2009

Video of Infosys Solution on Channel 9

Watch the Infosys video on Channel 9 http://channel9.msdn.com/shows/Inside+Out/Infosys-Data-Integration-in-the-Cloud/ where we talk about how can Infosys Integration Solution help organizations augment the power of Cloud Computing with their existing IT investments and realize scenarios of Partner Integration and Collaboration.

February 20, 2009

Silverlight 2 GDR 1

Earlier this week Microsoft released an updated patch for Silverlight 2 called GDR 1. You can find more details on Tim's blog. Needless to say that this will install on top of SL 2 and the updates developer tools for it for VS 2008 SP1. If you have this GDR installed, the SL version will be now set to 2.0.40115.0.

February 17, 2009

DSL as a Means of Improving Developer Productivity

The reduction of the transformation activities between man thoughts and executable software has been the quest of the software development world for a very long time, and though Domain-Specific Modeling is a major step in that direction, maintaining different levels of abstraction and making them work together is never an easy task.

The key to achieving mature development of software systems lies in the understanding of Business Domain and the Problem Domain that the software is expected to solve. An obvious observation is that one single model (in a single file or single repository) will not suffice for describing a complete application. Multiple Models driven by many Meta-Models integrating in a defined cohesion controls the modeling and the eventual representation of the actual software.

Shawn Wildermuth is writing a series of articles on building and using domain specific languages for developing software. Read the first part of the series here http://msdn.microsoft.com/en-us/library/dd441702.aspx.

Domain Specific Modeling is a key aspect of developer productivity as I would be discussing them in my columns here. This article series would be a good reference point complementing my ideas.

February 13, 2009

Business capabilities met on the cloud

Enterprise concerns with the cloud, primarily revolve around Data Security, Privacy and to a certain extent the relibaility of the cloud. However in these times of economic recession; cost optimization and improving TCO are some key value propositions that enterprises see which will primarily drive the adoption of cloud today. This new model of computing will not only address these value propositions but also provide enterprises with a platform to innovate and come out with some ingenious solutions tackling typical IT problems that have hindered enterprise growth over the past few decades . Here are a few business scenarios where I see cloud computing being applied in that fashion today:
  1. Businesses that need to be elastic to meet seasonal loads
  2. Enterprises looking at consolidating their existing infrastructure and moving towards Green IT
  3. Enterprises that want to have a quick and seamless way to integrate with their partners and suppliers
  4. Provide collaboration solution for desk-less or the mobile workforce
  5. Software Development teams seeking quick and cost effective ways to set up their development infrastructure
  6. Offsite facility to backup and archive data
  7. Processes which have high demand for processing computational intensive tasks such as billing, brokerage calculations etc
  8. Applications needed for relatively shorter period(tactical applications/non strategic/opportunistic)
The above is not an exhaustive list but a generic one. Unique scenarios exist in enterprises today which may have evolved or driven by the demands of the domain it operates in. If you have any such unique scenario or others which I might have missed out and would like to share. Please do.

February 11, 2009

Multiple AppDomains and Loader Optimizations

In my earlier blog Working with Application Domains in WPF, I had touched upon the usage of LoaderOptimization attribute. In recent days I have been playing around with WinDBG and hence thought to see how this attribute really affected to loading of assemblies and memory consumption of the application.

I used the the same application as mentioned in my earlier blog and handled 3 cases

1. No loader optimization
2. LoaderOptimization.MultiDomainHost
3. LoaderOptimization.MultiDomain

In all 3 cases, I ran the application and took the memory dump after launching the other appdomain. The physical size of memory dump file for option 2 was smaller than that for option 1, which is expected since we expect the assemblies to not be loaded multiple times.

Following is what I observed from WinDBG. Note that the output shown below is truncated in many places so that I can highlight the relevant pieces only.

Doing a !dumpdomain for the first case (without loader optimizations) showed the results as

0:000> !dumpdomain
--------------------------------------
System Domain: 6841d058
LowFrequencyHeap: 6841d07c
HighFrequencyHeap: 6841d0c8
StubHeap: 6841d114
Stage: OPEN
Name: None
--------------------------------------
Shared Domain: 6841c9a8
LowFrequencyHeap: 6841c9cc
HighFrequencyHeap: 6841ca18
StubHeap: 6841ca64
Stage: OPEN
Name: None
Assembly: 0025a1f8
--------------------------------------
Domain 1: 00262f58
LowFrequencyHeap: 00262f7c
HighFrequencyHeap: 00262fc8
StubHeap: 00263014
Stage: OPEN
SecurityDescriptor: 002688f8
Name: WPFAppDominTest.exe
Assembly: 0025a1f8 [C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader: 0025a268
SecurityDescriptor: 002790b0
  Module Name
63d41000 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
00232354 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sortkey.nlp
00232010 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sorttbls.nlp
00232698 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\xjis.nlp

Assembly: 0025a3b8 [D:\Work\Code\VS2008\WPF\WPFAppDominTest\WPFAppDominTest\bin\Debug\WPFAppDominTest.exe]
........................................
........................................
........................................
--------------------------------------
Domain 2: 076d1838
LowFrequencyHeap: 076d185c
HighFrequencyHeap: 076d18a8
StubHeap: 076d18f4
Stage: OPEN
SecurityDescriptor: 0027ea60
Name: test
Assembly: 0025a1f8 [C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader: 0025a268
SecurityDescriptor: 0030e648
  Module Name
63d41000 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
00232354 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sortkey.nlp
00232010 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sorttbls.nlp
00232698 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\xjis.nlp

Assembly: 003228b8 [D:\Work\Code\VS2008\WPF\WPFAppDominTest\DummyApp\bin\Debug\DummyApp.exe]
........................................
........................................
........................................ 

The key things to note in the above output are
1.  There are 4 domains created for the process. The first two are standard (System and Shared) and the third is hosting the application that I was running - WPFAppDominTest. The forth is the test domain that I created in code and used to launch DummyApp.

2. The Shared domain hosts only mscorlib at the address 0025a1f8. This same assembly is shared with Domain 1 and Domain 2 as can be seen by the address for this assembly in these domains in the output above.

3. I can additionally verify by doing a !dumpassembly and confirming that the Parent Domain matches with the address of Shared Domain.

0:000> !dumpassembly 0025a1f8
Parent Domain: 6841c9a8
Name: C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
ClassLoader: 0025a268
SecurityDescriptor: 000ccc88
  Module Name
63d41000 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
00232354 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sortkey.nlp
00232010 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sorttbls.nlp
00232698 C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\xjis.nlp

4. There are other assemblies also loaded in Domain 1 and 2 which are common, but since no optimization is done, they are loaded twice. For example, let's check on WindowsBase.dll

Domain 1: Assembly: 0025a7a8 [C:\Windows\assembly\GAC_MSIL\WindowsBase\3.0.0.0__31bf3856ad364e35\WindowsBase.dll]

Domain 2: Assembly: 00322b58 [C:\Windows\assembly\GAC_MSIL\WindowsBase\3.0.0.0__31bf3856ad364e35\WindowsBase.dll]

You can see that the addresses are different. It is this aspect that we address when we use loader optimization. Let's now look at option 2 where we used LoaderOptimization.MultiDomainHost attribute. The significant change is seen in the Shared domain in this case, as seen below

--------------------------------------
Shared Domain: 6841c9a8
LowFrequencyHeap: 6841c9cc
HighFrequencyHeap: 6841ca18
StubHeap: 6841ca64
Stage: OPEN
Name: None
Assembly: 0025a7a8
Assembly: 0025a968
Assembly: 0025a888
Assembly: 002c0090
Assembly: 0025a1f8
Assembly: 0025a6c8

-------------------------------------- 

You will notice that unlike the single mscorlib earlier, we now have a total of 6 assemblies loaded in Shared domain. The dump for Domain 1 and 2 in this case will confirm that some assemblies loaded in there are at these addresses and essentially are the same assemblies. Thus we get the benefit of loading these additional 5 assemblies only once and this helps reduce the memory foot print and also the load time, since these 5 assemblies need not be loaded again. So which are these additional 5 assemblies. In my case, these are

WindowsBase.dll
PresentationCore.dll
PresentationFramework.dll
PresentationFramework.Aero.dll
System.dll

These can be confirmed by doing a !dumpassembly on all the assembly addresses shown in Shared domain. Eventually I tested for option 3 as well where I used the LoaderOptimization.MultiDomain attribute. The difference between this and LoaderOptimization.MultiDomainHost attribute as per the documentation is that in the former maximum possible resources will be loaded in shared mode and in the later only assemblies from GAC should be loaded in shared domain. This means that if I use LoaderOptimization.MultiDomain attribute I should possibly see more assemblies loaded in Shared domain and this is confirmed by taking a dump and analyzing in WinDBG.

--------------------------------------
Shared Domain: 6841c9a8
LowFrequencyHeap: 6841c9cc
HighFrequencyHeap: 6841ca18
StubHeap: 6841ca64
Stage: OPEN
Name: None
Assembly: 004998a8
Assembly: 003ba818
Assembly: 003ba9d8
Assembly: 003ba428
Assembly: 00499a68
Assembly: 003ba8f8
Assembly: 0041ca50
Assembly: 003ba1f8
Assembly: 003ba738
Assembly: 00499bb8
Assembly: 00499c98
--------------------------------------

Notice that in case the shared domain has total of 10 assemblies loaded (excluding mscorlib). Running !dumpassembly on above addresses I realized the following additional assemblies were loaded in shared domain

WPFAppDomainTest
DummyApp
WpfControlLibrary2
System.Xml
System.Configuration

In this case, the WPFAppDomainTest was really used only in Domain 1 and DummyApp and WpfControlLibrary2 only in Domain 2, so loading these in shared domain doesn't really gives any specific advantage and hence we should only use LoaderOptimization.MultiDomainHost attribute. However in your case, based on your assembly usage pattern, you can decide which attribute works better for you.

The one aspect that I didnot understand was the loading of System.Xml and System.Configuration assemblies. These are assemblies that reside in GAC and hence as per definition should have been loaded in shared domain even when I had used the LoaderOptimization.MultiDomainHost attribute. I haven't been able to figure this out as yet. If you have an idea on this, do share. And In case you want to understand more about assembly loading and domain neutral assemblies (those loaded in shared domain) you can check this MSDN entry.

February 4, 2009

Impersonation and Delegation - There is too much confusion!

In various trainings, internal forums, general discussions with developers, I feel that there is a bit of confusion in the understanding of impersonation and delegation. In this blog I attempt to clear some of these. Though I use the context of MS, .NET and more specifically ASP.NET, the basic theory remains the same for any technology.

Let’s start by impersonation. The dictionary meaning of the word goes something like – “to assume or act the character of” or “pretend to be”. The easiest way I can explain this to compare this with mimicry artists. When they mimic someone else’s way of talking, walking, dressing etc, they are pretty much impersonating that person. If the mimicry artist is good, he/she can pretty much pass on as the real person. In software terms, the general meaning remains the same. Since we are really going to “pretend” to be someone, we should be able to authenticate on that person’s behalf and hence ID and password are required to be able to impersonate.

The idea of impersonation is essentially to assume identity of a particular person when accessing resources on a thread. The resources could be files, event log, data base etc, but pretty much on the local machine and these resources typically need to be protected by appropriate ACLs (access control list), else impersonation has no real significance. Here also note that “thread” is important. All code execution essentially happens on some thread and it is this threads identity that we are addressing. Threads typically inherit the process identity and hence will access all local resources using that identity. In case you want to access the resources using some other identity, you need to resort to impersonation. By doing impersonation, you can either increase or decrease your access rights on the resources.

Who do you impersonate? This really depends on the needs and also on the type of application. In windows (thick client) application, the process and threads run under the identity of the person logged onto the machine, so they are essentially impersonating the logged in user. All local machine resource access is done by using that identity and since most of us are administrators on local machines, we are able to access all resources without any security issues. This typically is the cause of “works on local machine but fails on remote machine” type of issues. In most thick client applications, we don’t have a need to impersonate, though theoretically we can.

In case of windows service, the process runs under the identity configured for that service and hence in turn the threads run in the same context. This is usually the “log on as” setting for the services and by and large most services run under “local system” account. Now this account is again a high privilege account and typically has full rights on the local system. If you change the “log on as” identity, you are essentially setting which identity the service should impersonate when accessing resources.

Finally let’s look at ASP.NET and this is typically where things become a bit more complex. By default the ASP.NET process runs using ASPNET (if on IIS 5) or NETWORK SERVICE (if on IIS 6 onwards) identity. All local resource access is done using this identity. Typical issues like can’t create a new event log via a web application or can’t access file is due to this, since the default identities don’t have these privileges on the local system. Multiple ways exist for impersonation

1.       Impersonate the logged in user. Note that this really has meaning if you are using Windows or forms authentication. If you have set your site to “Anonymous”, then impersonating logged in use has no real meaning.

2.       Impersonate a specific user by providing the ID and password in web.config

3.       Impersonate a specific user by setting it as process identity. In IIS 6 onwards, this means setting the identity of the application pool within which the asp.net application is running.

4.       Localized impersonation in code. You can create an impersonation context in code, invoke some APIs and then return to original thread identity

Options 1 and 3 are the more often used approaches. If you want to know how to put this in practice in ASP.NET, c heck this support article - http://support.microsoft.com/kb/306158.

In summary, impersonation is pretending to be someone else, other than the process identity, and access local resources.

Moving onto delegation, the dictionary meaning is something like “empowering someone to act on behalf of another”. A analogy with legal world is the power of attorney, which confers legal rights on someone to take decisions on behalf of someone else. The key difference to note here is that we know that this is another person that whom we are expecting, but this other person has been given rights to act on behalf of the person we were expecting. Just like impersonation required ID and password, delegation, will also require this other person to carry some credentials. Here however the requirement is dual. The person being delegated may have to prove his/her own identity and also show some evidence of being delegating on behalf of someone else.

In application development, delegation comes into picture when there is a machine-hop. Mostly typically this is seen when a client connects to an ASP.NET application on a web server and then a request is sent across the machine to either application tier or database tier. The web server, in this case needs to authenticate with the application tier or database tier on behalf of the user. This can be done by the web server by passing the ID and password to the next tier or look for some other mechanism by using some third party intermediary.

Since we are talking about web applications, let’s take the various authentication mechanisms possible and then discuss how that impacts delegation.

Anonymous: In this there is no credentials recorded from the logged in user and hence the web server has no data to share with next tier and thus delegation isn’t possible. In this case, it is the ASP.NET process identity that can be used for further delegation or impersonation of specific account be done using web.config file.

Basic: User is authenticated by taking the ID and password in clear text and this the web server can easily pass onto the next tier and hence delegation is possible.

Digest: User is authenticated by taking the ID and password, but it is encoded and hence the web server can’t pass these further. Thus delegation isn’t possible.

Windows: User is authenticated by taking the domain credentials by doing a handshake between client and server without really exchanging password. Web server only has access to ID and hence delegation isn’t possible.

Forms: User is authenticated by taking ID and password and depending on what encryption mechanism is used, these can be passed further and delegation may be possible.

Kerberos: Extension to Windows authentication (NTLM) where-by web server is authenticated by a third party and is also given rights to delegate on behalf of logged in users. The web server credentials provided by the third party are taken as evidence for right to delegate and hence delegation becomes possible. The rights to delegate are configured in AD. The default NETWORK SERVICE account under which ASP.NET runs has delegation rights.

In summary delegation is authentication across machine boundary on behalf of someone else.

Another important aspect is do impersonation and delegation work together? Well, they can, but not necessary. If you want to authenticate to the remote machine using the same identity as that used to log into the first machine (web server) then impersonation and delegation go hand in hand, else not. This may not be a good idea. Take for example accessing a database on remote machine. If we impersonate and delegate, all valid users of the application will need to be granted rights on the database and this can easily become a maintenance nightmare. This also additionally works against connection pooling, though gives benefit in terms of maintaining appropriate audit trail. Usually following approaches are possible

1.       Use trusted connection, where the identity of the application pool is set to a domain account and this same account is granted appropriate rights to the database. This domain account will need to be granted Kerberos authentication rights by creating appropriate SPN in AD.

2.       Use specific impersonation account. Same as previous point, but the credentials in this case come from the web.config file of the web server. This is using SQL authentication.

3.       Create specific read/write type accounts in SQL and they are used from the code. Using different read and write accounts enforces additional security based on which account is used to authenticate with database.

That's it for this discussion. I would be interested in any comments you may have to share on this topic.

February 2, 2009

BI Dashboards: Best Practices and Design Ideas

Based on multiple dashboard design projects  I have worked on in past, here are some quick points about deploying  ‘dashboard’ like displays for tracking business performance indices (popularly called as ‘Key performance Index’ or KPIs).

As score-carding and performance management initiatives get traction in 2009 through implementations featuring Microsoft Performance Point Server (PPS), the use of scorecard like displays is expected to intensify further.


1.       ‘Dashboard’s have become very popular with business managers as they
         Help gain quick insights into data and trends
         Monitor performance indices and track leading as well as lagging indicators
         Convert the business data into a ‘picture’ to easily communicate the story.
         But dashboards mean different things to different people


2.       Dashboards  v/s Reports
       Dashboards, by the analogy they refer to, should incorporate ‘information display’ and ‘controls to manipulate the information display’.
       Quite often, BI Dashboards are just reports with value added features to filter data, track trends or spot performance deviations.
       That is ok, but it falls short of true potential of Dashboards as a close-loop management tool.


3.       Why Dashboards?  For business goals.
           Business users should have some key, concrete business goals driven by business context.
           Some common goals that drive the development of BI Dashboards are
          One view of the (business) world
          Management by exception
          Corporate Performance Management
          Connecting Performance Data (historical data) with Forecasting Data (projections)
           From Data to Decisions to Actions


4.       What to Show on Dashboards? 
       As few things as you can and need… …And more leading than lagging data!
       Dashboards are not reports. If you show more information than necessary, you are hurting your own efficiency of using this tool.
       Numbers by themselves have no meaning..it is when they are presented in corporative context ( this quarter v/s last quarter) that the true picture emerges
       So, Edward Tufte likes to stress, help them compare!!


5.       What to Show on Dashboards? 
         Positive and negative performance deviations from plan
         Fastest rising KPIs that were previously in negative territory
         Fastest falling KPIs that were previously in positive territory
        Alerts about things that are out of tune
        Comments and notes about alerts and other deviation indicators to give extra context
        Pace and size of the business trends impacting the business
        Contributing factors behind trends


6.       How to Leverage Dashboards? 
        Connect forecasting data to historical data. Allow contextual simulations and ‘what-if’ scenarios to allow informed problem solving
        Allow saving of scenarios and sharing of scenarios to foster collaboration around Dashboards
        Allow navigation along business organization entities to get low level insights
       Add ‘controls’, not just the ‘displays’ - thereby allowing the user to modify date ranges and switch perspectives.


7.       How to Develop Dashboards? 
        Document and refine usage scenarios
        List and prioritize business goals
        Understand and model the relationship between historical and forecasting data
        Understand and factor in inter-relationship between corporate communication practices and this new business decision tool
        Understand the linkages between data tools, decision analysis tools and operational action tools. Feed key performance indicators that really matter - to get a pulse of the business.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter