During the development I faced a major problem. To display the items the user has the right for, I need to look in every list and use methods that requires admin rights.

For example, to loop through a collection of List, you need to have access to all Lists. Same thing if you one to use “Count” on a collection.To fix this problem, I used “Impersonation”. According to Microsoft, the Best Practice for Impersonation is to use the application pool account. In many cases that is enough. If you start coding a web part try this before going into an Application Domain.I did many tests because there are many ways to impersonate. The best I’ve found is this one. I only slightly modified the class to optimize some methods.

But in my case it wasn’t enough. Indeed, the code security was still pushing access denied exception.I found out that it double check the security. When you impersonate, you take the Windows Identity, but the Original HTTP User will always stay “alive”. Than the code fails because it checks both places (Windows Identity AND HTTP Users) to be sure the code is not being hijacked.Fortunately, there is a work around for this. Although neither recommended nor supported by Microsoft, it is quite the only solution I found at the moment. The use of a custom Application Domain.I was first directed to this blog to get the “How-to”:http://www.bluedoglimited.com/SharePointThoughts/ViewPost.aspx?ID=7This blog article is very good and recommend all over the world ;-) but has some minor errors in the code. I recommend that you read the whole thing to get a better understanding so I do not write the same text here.To know a little about appdomain at MSDN select his url: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemappdomainclasstopic.asp

Again, BlueDogLimited did a great job here. As they say, the code is not optimized; I kiss their toes… ;-) Because if wouldn’t have been redirected to their site, I would never had been able to finish this web part. Based on that, take my explanation as a research that began with their example.

One problem with their code is that you need to place the assemblies in the GAC to make it works. This is something I do not perform for 2 reasons: Even if strongly named (Required to be in the GAC) It opens a breach for hijackers. Next, it adds complicity when you are debugging, because it is also not recommender to output the assemblies directly to the GAC from Visual Studio.

With the help of a great guy at Microsoft, I modified the code so the Application domain look in the Bin directory for ALL the assemblies required for the web part. Yes, it will also load the .dll means,Their code to load the assembly is this one:

// Create an instance of the RemoteMethods class in the secondary domain

// and get an interface to that instance. This ensures you can use the

// instance but are not loading the instance into the primary AppD

}

catch(Exception ex)

{

Debug.WriteLine(ex.Message+" "+ex.StackTrace);

throw(new ApplicationException(ex.Message, ex));

}

} // End of RemoteInterfaceFactory</pre>

If you already know about the implementation of an AppDomain, that will definitely help you. But if you don’t know… here is excerpts of each methods required to make it works.My web part use Asynchronous calls, cache, impersonation and AppDomain. All of this has direct and indirect impact on the code and the execution of the code. I will not provide explanation on Asynchronous calls and Cache to reduce the amount of text. Maybe on another article.As for any web part, RenderWebPart is called. Note that what you see about Async is not required if you intent to remove or not use the Asyncrnous calls. You may leave doWebPart() followed by the output.Write(buffer.ToString()); and it would do the work.

Code:

protected override void RenderWebPart(HtmlTextWriter output)

{

if(!USE_ASYNCRONOUS_CALL)

doWebPart();//This is commented by the web part is now using asynchroneous call.

//buffer is filled by doWebPart()

//If no errors

output.Write(buffer.ToString());

}

Here DoWebPart() implement the Cache functionality. _cacheTimeOut is an integer from a custom web part property. If you intent to skip the Cache feature, you get bypass this method and directly call GetMyWebPart(); .

Code:

private void doWebPart()

{

try

{

//Write to cache content ONLY if Cache Emtpy AND CacheTimeout is Greather than 10 seconds. Lower than this, it may cause emtpy content.

//Retrieve cached output and write it to the StringBuilder "buffer". Is then used by RenderWebPart()

//Grab cache content ONLY if CacheTimeout is Greather than 10 seconds. Lower than this, it may cause emtpy content.

string appendThis = GetMyWebPart();

if(appendThis!=null)

buffer.Append(appendThis);

}

}

//+++++++ This is the last catch of the application

catch(Exception cx)

{

Debug.WriteLine(cx.Message +" "+cx.StackTrace);

string exceptionMessage="There has been an error while creating "+this.Title+" web part.";

buffer.Append(exceptionMessage ++cx.Message+" "+cx.StackTrace);

}

}

Here begin the process for the application domain.With “string SecondaryAppDomain = this.EffectiveTitle.Replace(” “,"")+"AppDomain";” I ensure that I have a unique string to create the name of the ApplicationDomain. I did this modification because I thought that if I had many web part using that kind of specific application domain, it could lead to some mixing has it can arise when closing SPWeb objects.

Note the argument I for BuildwebPart = remoteFactory.Loader.BuildWebPartHTML(………). When the AppDomain is loaded, the is absolutely no connection between the to Application Domain. So if you need to access vars that are created arlier than here, you must pass them through this methods and all along the process. Another important warning… You cannot pass any complex type. Even an array may fail. You’ll receive a strange error message (Sorry, can’t remember wich one). Even the Sharepoint Context object cannot go through (Instead you can use the URL to open SPWeb or/and SPSite.)

remoteInterface = (IRemoteMethods)appDomain.CreateInstanceFromAndUnwrap(an, “webpartlibrary.RemoteMethods"); //replace Namespace.RemoteMethods by the full name of your own class. NOTE THAT THIS COULD BE AUTOMATED USING Reflection BUT I DID’NT TOOK THE TIME TO DO IT. ALSO, FOR OUR COMPANY’ IT WILL NEVER CHANGE… THAT IT ALSO WHY IT IS NOT A Var.