by

How to create your own SharePoint HttpContext

Quick and short. Here's a function that I use to create my own SharePoint HttpContext objects outside the SharePoint websites domain. I hope it is somehow useful to someone out there as well.

    1         /// <summary>
    2         /// Enables a share point call from anywhere by creating your own context.
    3         /// </summary>
    4         /// <param name="siteCollectionUrl">The site collection URL where you want to create the context.</param>
    5         /// <example>
    6         /// EnableSharePointCallByCreatingYourOwnContext("http://mysite.com.au");
    7         /// </example>
    8         private void EnableSharePointCallByCreatingYourOwnContext(string siteCollectionUrl)
    9         {
   10             using (var site = new SPSite(siteCollectionUrl))
   11             {
   12                 using (var web = site.OpenWeb())
   13                 {
   14                     // assumes that context does not exists
   15                     var contextCreated = false;
   16 
   17                     // if it does not exists, then create it
   18                     if (HttpContext.Current == null)
   19                     {
   20                         contextCreated = true;
   21                         // creates a request object for the current web URL
   22                         var request = new HttpRequest(string.Empty, web.Url, string.Empty);
   23 
   24                         // open the pipe to output the http stream
   25                         HttpResponse httpResponse;
   26                         using (var responseWriter = new StringWriter())
   27                         {
   28                             httpResponse = new HttpResponse(responseWriter);
   29                         }
   30 
   31                         // creates the context
   32                         HttpContext.Current = new HttpContext(request, httpResponse);
   33 
   34                         // HttpHandlerSPWeb is a the property name where you must assign the current web
   35                         // in order to associate the newly created context to sharepoint
   36                         if (HttpContext.Current.Items != null)
   37                         {
   38                             HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
   39                         }
   40                     }
   41 
   42                     // ...
   43                     // do whatever you want to do here
   44                     // ...
   45 
   46                     // return the application context to the original state prior the execution
   47                     if (contextCreated)
   48                     {
   49                         HttpContext.Current = null;
   50                     }
   51                 }
   52             }
   53         }

See you later

By

by

How to Fix SharePoint MySite Auto-Creation Errors During Self Service ?

SharePoint MySites features is one of the best social features in the platform. It effectively gives to the end user control to his own area leveraging even more the collaboration capabilities of the enterprise.
One of these days we had a strange issue when creating my sites, which should be a trivial task. When an end user goes to his MySite link for the very first time the MySite creation can be automatically triggered, instead this error message was being displayed.
there-has-been-an-error-creating-the-personal-site-contact-your-site-administrator-for-more-information
there has been an error creating the personal site. Contact your site administrator for more information.

With not so many clues to inspect this case we went to take a look at the event viewer to see what's going on.
event-viewer-sharepoint-application-creation

When we saw this exception logged.
event-viewer-sharepoint-error-my-site
The site /personal/edge could not be created.  The following exception occured: Failed to instantiate file "default.master" from module "DefaultMasterPage": Source path "default.master" not found. For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
A little bit further, we see some more exceptions related to that previous entry where we can see a more detailed explanation for the error.
 event-viewer-sharepoint-error
My Site creation failure for user 'CORP\edge' for site url 'http://my.portaldev/personal/edge. The exception was: Microsoft.Office.Server.UserProfiles.PersonalSiteCreateException: A failure was encountered while attempting to create the site. ---> Microsoft.SharePoint.SPException: Failed to instantiate file "default.master" from module "DefaultMasterPage": Source path "default.master" not found. ---> System.Runtime.InteropServices.COMException (0x81070587): Failed to instantiate file "default.master" from module "DefaultMasterPage": Source path "default.master" not found.
   at Microsoft.SharePoint.Library.SPRequestInternalClass.ApplyWebTemplate(String bstrUrl, String& bstrWebTemplate, Int32& plWebTemplateId)
   at Microsoft.SharePoint.Library.SPRequest.ApplyWebTemplate(String bstrUrl, String& bstrWebTemplate, Int32& plWebTemplateId)
   --- End of inner exception stack trace ---
   at Microsoft.SharePoint.Library.SPRequest.ApplyWebTemplate(String bstrUrl, String& bstrWebTemplate, Int32& plWebTemplateId)
   at Microsoft.SharePoint.SPWeb.ApplyWebTemplate(String strWebTemplate)
   at Microsoft.SharePoint.Administration.SPSiteCollection.Add(SPContentDatabase database, String siteUrl, String title, String description, UInt32 nLCID, String webTemplate, String ownerLogin, String ownerName, String ownerEmail, String secondaryContactLogin, String secondaryContactName, String secondaryContactEmail, String quotaTemplate, String sscRootWebUrl, Boolean useHostHeaderAsSiteName)
   at Microsoft.SharePoint.SPSite.SelfServiceCreateSite(String siteUrl, String title, String description, UInt32 nLCID, String webTemplate, String ownerLogin, String ownerName, String ownerEmail, String contactLogin, String contactName, String contactEmail, String quotaTemplate)
   at Microsoft.Office.Server.UserProfiles.UserProfile.<>c__DisplayClass2.<CreateSite>b__0()
   --- End of inner exception stack trace ---
   at Microsoft.Office.Server.UserProfiles.UserProfile.<>c__DisplayClass2.<CreateSite>b__0()
   at Microsoft.SharePoint.SPSecurity.CodeToRunElevatedWrapper(Object state)
   at Microsoft.SharePoint.SPSecurity.<>c__DisplayClass4.<RunWithElevatedPrivileges>b__2()
   at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode)
   at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(WaitCallback secureCode, Object param)
   at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(CodeToRunElevated secureCode)
   at Microsoft.Office.Server.UserProfiles.UserProfile.CreateSite(String strRequestUrl, Boolean bCollision, Int32 lcid).

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp
So there we go. There is a clue indicating the a file called default.master was not found where it was supposed to be. We step into the Microsoft.SharePoint.Library.SPRequest class to understand what the method ApplyWebTemplate does but not much can be told from there as we can see in the picture. Also there is another method call to a private member, and probably obfuscated by Microsoft, which we can not debug.
ScreenShot013
In these cases, there is a straight forward thing to do which is if possible, compare against a working version of SharePoint and see the differences. Luckily we had one and we noted that (for some reason) the files in the SPSPERS were missing in the 12 hive.
  • \XML\onet.xml
  • blog.xsl
  • default.aspx
 sharepoint-12-hive-template-site-templates-spspers-blog-xsl
 sharepoint-site-templates-one-xml
We just put the files back in there and it is all good and back to normal. If you ever have this problem  also pay special attention if you have done any modifications in these templates.
See you later,

By

by

How to get connection string from BDC and use ADO.NET in your queries ?

The SharePoint BDC is great in a sense that once you target your data to be displayed, the end user can create and format many reports and data grids at his own convenience, however there is a price to pay for that: performance.
The operations executed via BDC can be extremely slow. Just so you know I will talk about a project I had to implement and how an alternative solution can be put in place to maximize the overall performance.
The task was to is to hit a specific database and bring a whole set of records in order to build a report. For many architectural reasons particular to the project, the BDC approach had to be used for the task.
The SharePoint web site makes the request to the BDC, the BDC then drags the data out of the external database and then this data is manipulated and displayed back in the end user report page. The transaction is much like the picture below:
bdc-performance-connection-string-sharepoint-2
In this specific case, the whole task takes approximately 6 minutes. Yeah, I know. Painful.
Let's run a profiler against that page and see what it tells about it. (I will blur all text which might contain sensitive information about the client.)
bdc-sharepoint-performance
Well, once we have analyzed that data in our hands outlining all the calls being executed during this specific SharePoint's page  life cycle and what's going on behind the scenes we can draw a few conclusions and the most important conclusion here is that 2 single calls are responsible for almost 99% of the total execution time. Now that an impressive bottleneck.
Let's dive a bit further on it into the internal calls and we can identify the very single calls responsible for these times.
 bdc-sharepoint-performance-5

 bdc-sharepoint-performance-4
When we go back to the source code to take a look at them, it turns out that they were the ones connecting and loading the data from the BDC.
The world would be perfect if we only could have done things our way, but unfortunately due to requirements restrictions this can not be changed.
As a good exercise I made myself a mirror copy of this environment to test a theory. What if we change the approach to loading data from the BDC?
The idea is to connect to the BDC and only extract the necessary connection string to the external data source and from there I would load the data via ADO.Net. That would be great because :
  • we are not performing any breaking changes in the current structure
  • the BDC still plays the game
  • All the permissions and security levels are still managed by the BDC definition
  • I have an opportunity to retrieve data from an external source much faster than via BDC
 bdc-performance-connection-string-sharepoint-3
  • 1 and 2 we would get the BDC connection string.
  • 3 and 4 we will query the external database and get the data displayed on screen. 
Using the properties in the code below you can get the properties returned from the BDC catalog and amongst them you can see the returned connection string with all the permissions etc for your use in your SharePoint code. Neat!
Note that the code is also using Entity Framework.
   25         public static void SetSharedServiceProvider(SPSite site)
   26         {
   27             try
   28             {
   29                 if (site != null)
   30                 {
   31                    
   32                     SqlSessionProvider.Instance().SetThreadLocalSharedResourceProviderToUse(
   33                         ServerContext.GetContext(site));
   34                 }
   35             }
   36             
   37             catch (Exception)
   38             {
   39                 // Ignore the exception if a provider
   40                 // is already set.
   41             }
   42             
   43         }
   44 
   45         public static EntityConnection GetOnePortalConnectionString(SPSite site)
   46         {
   47             const string instanceName = "TEST_Instance";
   48             SetSharedServiceProvider(site);
   49             LobSystemInstance instance = ApplicationRegistry.GetLobSystemInstances()[instanceName];
   50             var properties = instance.GetProperties();
   51 
   52            
   53             return GetEntityConnection(GetProperty(properties, "CONN Data Source"),
   54                                        GetProperty(properties, "CON Initial Catalog"));
   55         }

Once implemented the results are impressive. The page that use to load in minutes now takes a couple of seconds to run.
Now moving from the current scenario to the improved version is easier said than done and the lesson learned here is that BDC can be as great as mush as it can be plain dangerous to kill an application.
See you later,

By