Sunday 10 February 2013

Alternate Access Mappings and SPFieldURLValue fields

Be careful if you're trying to programmatically pull back the value of a Hyperlink field when your site is using Alternate Access Mappings (AAM).
If the value of the Hyperlink field is pointing to an object within the current SharePoint site, the SharePoint front end will automatically update the URL for the AAM site you are currently using.  BUT if you are pulling the value programmatically it will always default to the URL of the default AAM site.


UPDATE:
Better Way to Fix:
I discovered an even better to fix this problem and it all has to do with how you open your SPSite Object.
For example if you do
SPSite site = new SPSite(SPContenxt.Current.Site.ID)
It will open the site in the default zone, which will then always return the URL of the default zone.
But if you do the following:
SPSite site = new SPSite(SPContext.Current.Site.ID, SPContext.Current.Site.Zone)
It will open the site in the zone the user is currently in and return the correct URL.

To fix this, you must turn the URL into a relative URL and then it will go to the AAM of the site you are currently logged into.  One way to achieve this is as follows:

SPFieldUrlValue linkfield = new SPFieldUrlValue(listItem["URL"].ToString());

string returnValue = linkfield.Url;

            try
            {
                using (SPSite site = new SPSite(returnValue))
                {
                    return returnValue.Replace(site.Url, string.Empty);
                }
            }
            catch
            {
                //swallow exception from Site Not Found
                return returnValue;
            }

How to Properly use RunWithElevatedPrivileges

RunWithElevatgedPrivileges will run the code block with Full Control rights even if the current user does not have full control.  This piece can be very useful, but must be used carefully to avoid creating a security hole.
The interesting part of this method is that for any objects to be run with this elevated context, they must be created within the RunWithElevatedPrivileges block.  This may seem obvious but lets take a look at a couple examples:
  
SPWeb web = SPContext.Current.Web;
SPSecurity.RunWithElevatedPrivileges(delegate()  
       {  
         PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(web);
         ...
       })  

This method will result in an unauthorized error, unless the logged in user has enough permissions to open a Publishing Web object.  But we said the object must be created within the Elevelvated Permission block, so it looks like an easy fix to the above code:


SPSecurity.RunWithElevatedPrivileges(delegate()  
       {
        SPWeb web = SPContext.Current.Web;
         PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(web);
         ...
       })

This method will also result in an unauthorized error.  Wait you say, the SPWeb object is created within the Elevated block, so it should work.  The issue is that the SPContext.Current.Web method returns an SPWeb object under the context of the current user, not the Elevated user, regardless of where the method is run...so how do you get an SPWeb object to run under the elevated permission?  You need to open the web using the GUID constructor, like this:


Guid siteID = SPContext.Current.Site.ID;
Guid currentWebID = SPContext.Current.Web.ID;

SPSecurity.RunWithElevatedPrivileges(delegate()
            {
             using (SPSite site = new SPSite(siteID))
                {
                    SPWeb currentWeb = site.OpenWeb(currentWebID);
                    PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(web);
                    ...
                }
            })


The difference being the first and second examples are returning an already created SPWeb object, that was created under the current users context.  The last example is returning newly created SPSite and SPWeb objects, since they are within the elevated code block they will be created under the elevated context.  Now everything should work as expected, regardless of who is logged into the site.

             



Wednesday 6 February 2013

Problems opening office documents in SharePoint 365


I was trying to open a SpreadSheet from a SharePoint 365 site only to keep getting this error message:
The document could not be opened for editing.  A Microsoft Foundation compatible application could not be found to edit the program.

Which is really odd since I do have excel installed on my machine.  I found lots of blog posts suggesting to verify that certain SharePoint add ons are enabled in IE to ensure you are using the 32 bit version of IE, ensure office is installed, but nothing really useful as all I could check yes to all their suggestions: (http://community.office365.com/en-us/forums/175/t/59242.aspx).

Turns out that the activeX control that is used by SharePoint 365, and probably SharePoint on prem although I don’t know for sure, comes with the Office install.  So the suggestions were on the right track, you need to have office installed…but here is the kicker.  It all depends on which version of office you installed 32 bit or 64 bit.  If you have installed the 64 bit version of office, you need to run the 64 bit version of IE for this activeX control to work properly and vise versa.

Now you know.