Bluedog Limited > SharePoint Thoughts > Posts > Q&A on the interface loader technique and AppDomains
February 20
Q&A on the interface loader technique and AppDomains
This post was migrated from an older system. Some links may point to content that no longer exists. Comments were not migrated.
Update 2/20/2007
Updated path to the perf mon image - and included it in the post now the v3 allows images in rich text fields :).

One of my first posts discussed the interface loader technique which allowed you to move beyond impersonation limitations of the SharePoint OM.  The original post did not discuss the details of how a RevertToSelf or LogonUser/Impersonate could/should be used.  Instead, I brushed over the topic and left it for the reader to determine which methodology was best for their application.

Over the past couple of months, I've received several email discussing a variety of issue surrounding impersonation and the SharePoint OM.  In each case, I would always offer two alternatives: try using AppDomains or use a COM+ solution.  Most folks decided to use the AppDomain technique... and invariably some of them would come back with failures.  Good or bad, my thought process was invariably "check your impersonation code, you must not be doing it right... the article on the loader technique is accurate and works".

Well, if enough people run across problems, then it's time to double check the source to make sure all the i's have been dotted and the t's crossed.  The truth is I was somewhat right, but I had forgotten a small trick that I had used in my own code.  Without a 1-line adjustment/fix to the impersonation code, you would run into the infamous "Cannot complete this action" error message even though everything else appeared to be working correctly.

On to a Q&A style to get things working...

What's the one line fix?
After you've called completed your impersonation magic (i.e. RevertToSelf, LogonUser, Impersonate), call the Impersonate method one more time in the context of the newly established identity.  Although this seems a bit counterintuitive, calling impersonate one more time resets the state in the Context in way that ensures the impersonation "takes hold".  If you don't do this, you will eventually run into the "Cannot complete this action" error message. 

Add the following line to your impersonation library immediately after you've done the heavy lifting of calling RevertToSelf, LogonUser, or WindowsIdentity.Impersonate (IntPtr):

// If the following call is not made, the Context is somewhat out of whack...
WindowsIdentity.GetCurrent().Impersonate();

Back to basics... isn't impersonation not supported?
Yes.  In a simple, inline manner as described by KB article 892866, impersonation is not supported.  You can't do the following and expect it to work all the time.

// Running as normal user...
// Now switch to privileged user...
MethodWhichImpersonates ();

// Execute a privileged task of some type. For example...
CreateSiteForMyUnderprivilegedUser ();

Doesn't using AppDomains or COM+ contradict the KB article?
Not really.  The whole purpose of using those techniques is to remove any knowledge of the http context.  The basis for the KB article is that the SharePoint OM may perform security checks relative to the original request/context identity and not the newly established one. 

If the http context space is eliminated, the SharePoint OM operates as though it's a console application.  Yes, the starting point may have well been an http request, but the code running in secondary AppDomains or as a COM+ application has no knowledge of the context.  This is where the power of those techniques shine through.  You get all the benefits of a console app. 

How about if I use the 1-line fix to my inline code... will that make the KB article go away?
No. You're still under the bounds of the KB article.  There is no guarantee everything will work as desired when you use impersonation and remain within the http context space.

Using the AppDomain technique, what type of parameters should I pass to methods?
Simple, serializable types.  Use simple types as method parameters (i.e. string, int, custom classes).  Whatever you do, don't try to pass an Assembly or any of the context types.  If you do so, you will force the operating domains to load (and subsequently lock) assemblies which were once isolated.

Should I specify shadow copying and other advanced properties for my AppDomain?
Yes, it's probably a good idea to walk through all of the AppDomainSetup methods and properties.  The following is how I generally setup my AppDomains to ensure I don't lock the main assemblies by caching them to a unique shadow copy folder:

AppDomainSetup appDomainSetup       = new AppDomainSetup();
appDomainSetup.ApplicationBase      = applicationBase;  // this is the value of this.Page.MapPath("/")
appDomainSetup.ApplicationName      = AppDomain.CurrentDomain.SetupInformation.ApplicationName + "_MyAppName";
appDomainSetup.CachePath            = AppDomain.CurrentDomain.SetupInformation.CachePath;
appDomainSetup.ConfigurationFile    = "web.config";
appDomainSetup.DisallowCodeDownload = true;
appDomainSetup.PrivateBinPath       = "bin";
appDomainSetup.PrivateBinPathProbe  = "true";
appDomainSetup.ShadowCopyFiles      = "true";

this.appDomain = AppDomain.CreateDomain (domainName,
                                         AppDomain.CurrentDomain.Evidence,
                                         appDomainSetup);

Please review the settings to ensure they generate the behavior you desire - there's a chance you don't want to deal with shadow copied files.

Can the AppDomain technique be used in a partially trusted environment?
Yes, your web part code (or whever you implement this technique) does not require Full trust.  This is a good homework assignment - can you tell me what set of permissions are needed to make the technique work?  :-)

How does the AppDomain technique look like with a debugger attached?
If you attach a debugger to the process, the output should look like the following color-coded section.  I've trimmed a good bit of the output to reduce the overall size of the post, but the general outline is still there.  The gray highlighted section is the normal information regarding your virtual server's primary AppDomain.  VS will list all the assemblies loaded in the active w3wp process.  When you commit an action which fires up a new AppDomain, the yellow highlighted section will represent all the actions taken by your new AppDomain.  Note that "DomainX" is created, then the necessary assemblies are loaded into that AppDomain.

In a perfectly working and synchronous world, the two section (gray and yellow) should be completely separate and not intermixed.  This is easy to witness on a developer's machine because you can isolate server usage.

'DefaultDomain': Loaded 'c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll', No symbols loaded.
Auto-attach to process '[5772] w3wp.exe' on machine 'WESTGATE' succeeded.
'DefaultDomain': Loaded '\gac\system.web\1.0.5000.0__b03f5f7f11d50a3a\system.web.dll', No symbols loaded.
'DefaultDomain': Loaded '\gac\system\1.0.5000.0__b77a5c561934e089\system.dll', No symbols loaded.
'DefaultDomain': Loaded '\gac\system.enterpriseservices\1.0.5000.0__b03f5f7f11d50a3a\system.enterpriseservices.dll', No symbols loaded.
'DefaultDomain': Loaded '\gac\system.data\1.0.5000.0__b77a5c561934e089\system.data.dll', No symbols loaded.
'/LM/W3SVC/1285842265/Root-3-127716846597562722': Loaded 'p3odzxx_', No symbols loaded.
'/LM/W3SVC/1285842265/Root-3-127716846597562722': Loaded '\gac\microsoft.sharepoint.intl\11.0.0.0__71e9bce111e9429c\microsoft.sharepoint.intl.dll', No symbols loaded.
'/LM/W3SVC/1285842265/Root-3-127716846597562722': Loaded 'RegexAssembly3132_0', No symbols loaded.
'/LM/W3SVC/1285842265/Root-3-127716846597562722': Loaded 'RegexAssembly3132_0.dll', No symbols loaded.
'Domain4': Loaded 'c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll', No symbols loaded.
'demo': Loaded '\microsoft.net\framework\v1.1.4322\temporary asp.net files\root\13e9a3d7\ec3137a3_testApp\assembly\dl2\bf0ad338\ee227dea_90bdc501\bluedoglimited.webparts.scratch.dll', Symbols loaded.
'demo': Loaded '\gac\system.web\1.0.5000.0__b03f5f7f11d50a3a\system.web.dll', No symbols loaded.
'demo': Loaded '\gac\microsoft.sharepoint\11.0.0.0__71e9bce111e9429c\microsoft.sharepoint.dll', No symbols loaded.
'demo': Loaded '\gac\system.xml\1.0.5000.0__b77a5c561934e089\system.xml.dll', No symbols loaded.
'demo': Loaded '\gac\system\1.0.5000.0__b77a5c561934e089\system.dll', No symbols loaded.
'demo': Loaded '\microsoft.net\framework\v1.1.4322\temporary asp.net files\root\13e9a3d7\ec3137a3_testApp\assembly\dl2\3926c5e3\27119fd6_8dbdc501\bluedoglimited.webparts.syndication.dll', No symbols loaded.
'demo': Loaded 'yzqk0nww', No symbols loaded.
'demo': Loaded 'vqusmshf', No symbols loaded.
The program '[5772] w3wp.exe: demo' has exited with code 0 (0x0).

Most importantly, though, note the very last line - "w3wp.exe: demo" has exited.  If you don't see your custom AppDomain exiting (in this example, my AppDomain was called "demo"), you've got a memory leak ... so be sure you always properly dispose of the your custom AppDomain. Technically, garbage collection will likely take care of reclaiming your memory, but don't wait - just do it yourself.

What does all of this look like in perfmon?
The following image shows what occurs when a postback is executed that fires off method which creates a new AppDomain and creates a site for an anonymous user. 

Note how the AppDomain count goes up by 1, process executes, then the count goes down by 1.  Correspondingly, available memory decreases and then returns to its original level.

Ok... how about a demo?
The following page contains a web part that allows an anonymous user to create a new site, get some data about a user, and get a list of sites.  It took me less than 10 minutes to create this web part.  In fact, I spent more time touching up the UI than I did coding up the interface loader.  :)

AppDomain - Interface Loader - Demo Page

Swing by check it out... then go crank your own custom apps that do all sorts of neat things!

-Maurice

Comments

There are no comments for this post.

Add Comment

Items on this list require content approval. Your submission will not appear in public views until approved by someone with proper rights. More information on content approval.

Title


Body *


captcha

Please verify the text shown in the image

Attachments


© Bluedog Limited 2004-2012
Aptillon, Inc.
Microsoft Certified Master - SharePoint 2010 & 2007
Sign In