Its seems that SharePoint has a knack for surprising me with seriously strange errors sometimes. Usually at the core of the error there is a sound explanation as to why this is happening but nonetheless I am not pleased with the obscurity of them sometimes. Case in point, while working on a Console application that would load FBA (Forms Based Authentication) users into a sharepoint sie collection and then create a site for each one (granting permissions and so on) I came across a very strange error - SPException: SharePoint cannot find the user.
This kind of surprised me at first and I was wondering if somehow my CustomMembershipProvider setup stopped working on my portal site, but that was fine. So after hammering away at it for a while I came across a great article written by Waldek Mastykarz on this exact problem. After reading through his investigation it makes sense why it doesn't work in a console application but it works under the context of a SharePoint website. Essentially the web application has access to a context object and this has access to the providers node in your web.config file, BUT the console application does not have this information available. So when the SharePoint assemblies attempt to access this information they cannot because it does not exist.
The way around this is to create an HttpContext in your application before attempting to run SPWeb.EnsureUser("blah") like so:
if (HttpContext.Current == null)
{
HttpRequest request = new HttpRequest("", web.Url, "");
HttpContext.Current = new HttpContext(request,
new HttpResponse(new StringWriter()));
HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
}
Then add the system.web/membership/providers node to your app.config file (which you may have to create in the project).. Mine looks like so:
<system.web>
<membership>
<providers>
<add name="CustomSqlProvider" applicationName="/Portal"
connectionStringName="sqlData"
type="CustomProviders.CustomSqlMembershipProvider,
CustomProviders, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=91a4fcd60b73a0e8" />
</providers>
</membership>
</system.web>
<connectionStrings>
<add name="sqlData" connectionString="Data Source=sqlpd;
Initial Catalog=PUsers; Integrated Security=True;
MultipleActiveResultSets=True "
providerName="System.Data.SqlClient" />
</connectionStrings>
After adding this information and running a few tests it started to work. In fact it worked really well on my dev box...the only problem was it was a little intermittent on my production machine. Which is funny because the provider on the site itself works just fine all the time but in order to get my console application working (the EnsureUser() portion) the site would require an IIS reset. This is the one MAJOR stumbling block that I have yet to overcome...the only saving grace I have is that I can import the users manually into the system first using the UI and then run my console application that will load the sites and grant permissions to sites based on an external configuration file.
Many thanks to Waldek Mastykarz for all his help on this one so far...I know I will be coming back to this one in the near future but my head hurts a little and I need a beer.
Canadian SharePint event anyone?
Technorati Tags: Development, IIS, MembershipProvider, Security, SharePoint