This week I am teaching COM+ again for employees of the Belgian Post. Three years ago, I worked together with MCS on PostStation, an application automating the Post offices relying on VB6 components hosted in COM+, Web Services, HTA and element behaviors on the client. This week I train some of the internals of the team in these technologies and sometimes it is hard to remember again how things worked :-)
Anyway, COM+ knowledge can also be important for SharePoint Web part developers. Earlier this year I had a posting on dangerous Web parts and discussed how COM+ can help you solving those problems. Since my archive on Userland is for some reason missing, I will repost it here again.
A lot of times you will need to work with the SharePoint (WSS or Portal) object model from within your Web part. When doing this, you have to know that some (not all) operations with the SharePoint objects require specific rights. So it could be that you are developing a Web part on your development machine (and testing it of course with administrator role, or contributor role in SharePoint), and that your user (poor one only has reader role) does not even get to the page hosting the Web part anymore. You have probably guessed that this happened to me :). More interesting is how this can be avoided. To illustrate I have a stupid Web part that shows us the number of Webs.
Here is the code executing in the RenderWebPart method (nothing special you might say!):
protected override void RenderWebPart(HtmlTextWriter output)
{
SPWeb web = SPControl.GetContextWeb(HttpContext.Current);
int c = web.Webs.Count;
output.Write("Number of Webs: " + c.ToString());
}
Everybody has access to this page except the users with a reader role. They will have the nagging logon dialog everytime they want to access the page. After three attempts, they see the page requesting access to the administrator of the site.
First of all, you can avoid this nagging dialog and display a friendly message in the Web part itself. You can make use of the famous CatchAccessDeniedException property (see Austin Wheat's blog <http://blog.austinwheats.net/archive/2004/04/12/166.aspx> for a good explanation of this property).
SPSite site = SPControl.GetContextSite(HttpContext.Current);
site.CatchAccessDeniedException = false;
try
{
SPWeb web = SPControl.GetContextWeb(HttpContext.Current);
int c = web.Webs.Count;
output.Write("Number of Webs: " + c.ToString());
}
catch
{
output.Write("Oeps.. it seems you have no rights to do this!");
}
OK. Readers now see the 'Oeps' message.
Those of you who read my article on processing InfoPath data maybe have tried out the impersonation code that allows you to impersonate an account in code. Is this helping? Well, unfortunately not. Your code is running with that impersonated account, but at the lower level (in the object model itself), SharePoint is always using the account of the logged-on user. Here is the proof:

WindowsImpersonationContext wic =
UserImpersonation.CreateIdentity("account","domain","pwd").Impersonate();
SPSite site = SPControl.GetContextSite(HttpContext.Current);
site.CatchAccessDeniedException = false;
try
{
SPWeb web = SPControl.GetContextWeb(HttpContext.Current);
int c = web.Webs.Count;
output.Write("Number of Webs: " + c.ToString());
}
catch
{
string u = WindowsIdentity.GetCurrent().Name;
string s = base.Context.User.Identity.Name;
output.Write(u + " -- " + s);
}
wic.Undo();
Too bad! This would be too easy! I then tried out scenarios where I Assert permissions within my Web part, but that only gave me more problems. Looking in the newsgroups for some help I found one person who commented that he is using COM+ to solve this problem. I also have the Nintex Smart Library <http://www.nintex.com> installed and noticed that they also use a small COM+ application hosting objects that do dangerous operations within SharePoint. I quickly discovered that this is probably the way to go. Another benefit is that it looks professional, isn'it? Your Web part is calling a .NET assembly hosted in a COM+ application running the code under an identity you specify yourself.
The new assembly of course must follow some rules in order to be able to be hosted in a COM+ app. I went for a server library and for the lazy registration of the DLL. The assembly also needs to have a strong name and your Web part does need a reference now to the System.EnterpriseServices assembly. Here is the code for the COM+ dll.
using System;
using System.Security.Principal;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.EnterpriseServices;
namespace U2U.WebParts.Samples
{
public class SiteOperations: ServicedComponent
{
public SiteOperations()
{}
public int GetCountWebs(string vserverUrl, string siteName, Guid webName)
{
SPGlobalAdmin ga = new SPGlobalAdmin();
SPVirtualServer vs =
ga.OpenVirtualServer(new Uri(vserverUrl));
SPSite site = vs.Sites[siteName];
SPWeb web = site.AllWebs[webName];
int retValue = web.Webs.Count;
return retValue;
}
}
}
And no, the SPWeb is not serializable. You cannot have a reference to it as incoming parameter. Going back to the Web part code, you now simply create an object of this class, delegating all of the dangerous work to the COM+ hosted dll and you should have no problem anymore with operations on the SharePoint object model for which you need specific rights.
Hope this helps some readers writing their own custom Web parts and experiencing the same problems. As always, I am open to any remarks on this. Do feel free to comment your own solutions!