Sunday, January 23, 2011

Fixing Migrated SharePoint Sites: Missing Add Users Source Parameter

This was a really annoying problem that arose in a site that had been migrated from MOSS 2007 to SharePoint 2010 using the database attach approach with no visual upgrade:

In 2007, starting from the ‘people’ page, where the members of a given group are listed, the normal flow of adding users goes like this:

image

Basically, starting from the People and Groups page, you add a user, then end up right back where you started.

However, for an upgraded site, the 2010 flow goes like this:

image

Rather than ending up where you started out, you are taken to the site Permissions page and do not end up back where you started. The user or users do get added – so everything works - but ending up on the permissions page is definitely confusing, and it could lead to the belief that adding the user did not work – or worse: that the you must now grant permissions directly!

So why does this happen? Looking closer at what is going on behind the scenes, in 2007 there is a ‘Source’ querystring parameter that is passed to the Grant Permissions page (aclinv.aspx) that tells it where to redirect to upon completion. Once the site has migrated to 2010, the source parameter is missing when the ‘Grant Permissions’ page is navigated to via the ‘Add Users’ menu. It looks like this parameter is missing because SharePoint 2010 sites using the version 4 master page (or version 4 compatible) do not need it, since the ‘Grant Permissions’ form is actually a scripted browser dialog. In other words, there is no navigation involved, so there is no need to worry about where we came from. I dove into the SharePoint 2010 out of the box client script to confirm this: It checks to see if the page is a version 4 UI, and if it is, the slick modal shows up overlaying the current page:

image

In the case where the v4 UI is not present – like a migrated site that has not undergone the visual upgrade – the script simply navigates to the Grant Permissions page, without the Source parameter.

The How To Fix Section:

This script will intercept the call and add in the source parameter to the URL. It actually adds the source parameter to EVERY url passed to the ShowPopupDialog method – in case there is another place where this kind of problem is happening. I suppose an improvement would be to add a check to see if the source parameter was already there…

<script type="text/javascript">
var _origShowPopupDialog = null;
try
{
if (typeof (ShowPopupDialog) == "function" && _origShowPopupDialog == null) {
_origShowPopupDialog = ShowPopupDialog;
ShowPopupDialog = ShowPopUpDialogPreUI4;
}
}
catch(e)
{}

function ShowPopUpDialogPreUI4(a) {
_origShowPopupDialog(AddSourceToUrl(a));
}
</script>


 


There are a couple of ways to incorporate it:




  1. Add to master page. Make sure the system pages are all using that master page containing the fix script.


  2. Create a custom solution to wire it in via the AdditionalPageHead control. Here is a good article about this technique – where Jan Tielens is incorporating the jQuery library in the same way.



I did create a Visual Studio 2010 project that wraps this all in a nice site collection scoped solution – if there is any demand for it I will post it here.

Tuesday, January 18, 2011

Unexpected Response: System.ServiceModel.ServiceActivationException

Had a SharePoint site migrated from MOSS 2007 to SharePoint 2010 via the content DB detach/re-attach method. Not sure that was a factor here, but adding this little fact for posterity.

Problemo:

Editing a publishing page produced the following popup dialog in IE, FireFox, Chrome, etc when a user attempted to edit a publishing page that was already checked out by another user:

          image

“Unexpected response from server. The status code of the response is ‘500’. The status text of response is ‘System.ServiceModel.ServiceActivationException”

Investigation into the server’s event log showed this helpful tidbit of information:

WebHost failed to process a request.
Sender Information: System.ServiceModel.ServiceHostingEnvironment+HostingManager/2593506
Exception: System.ServiceModel.ServiceActivationException: The service '/_vti_bin/client.svc' cannot be activated due to an exception during compilation.  The exception message is: Operation is not valid due to the current state of the object.. ---> System.InvalidOperationException: Operation is not valid due to the current state of the object.
   at Microsoft.SharePoint.ApplicationRuntime.SPLayoutsMappedFile.MapLayoutsVirtualPath(String virtualPath)
   at Microsoft.SharePoint.ApplicationRuntime.SPVirtualPathProvider.GetCacheKey(String virtualPath)
   at Microsoft.SharePoint.Publishing.Internal.CmsVirtualPathProvider.GetCacheKey(String virtualPath)
   at System.Web.Compilation.BuildManager.GetCacheKeyFromVirtualPath(VirtualPath virtualPath, Boolean& keyFromVPP)
   at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)
   at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)
   at System.Web.Compilation.BuildManager.GetCompiledCustomString(String virtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.GetCompiledCustomString(String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.CreateService(String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.ActivateService(String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath)
   --- End of inner exception stack trace ---
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath)
   at System.ServiceModel.ServiceHostingEnvironment.EnsureServiceAvailableFast(String relativeVirtualPath)
Process Name: w3wp

Yet more evidence to be used in a future blog post: Why I hate WCF!

Solution-o:

So searching for this issue produces a few results – though none that had the exact ‘Operation is not valid due to the current state of the object’ wording. The results that did come back were ones that were all too familiar when I had made the mistake of using WCF in the past: cannot have multiple bindings, multiple authentication mechanisms, etc. With the solutions generally being along the lines of creating an extended site. Oh boy – another IIS site to manage! 

The deal with this particular site though did not fall in line with those solutions – it only had one binding (single AAM to 443) – though it was anonymous enabled (but not claims-enabled).

So how did I fix? Here are the steps:

  1. Travel to C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI on each WFE – or wherever your 14-Hive exists.
  2. Tip: Make a backup copy of the web.config file in that folder. You just never know…
  3. Edit the web.config file by adding the highlighted line to enable aspNetCompatibility:

<configuration>
  <system.web>
      …
     
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  </system.serviceModel>
</configuration>

Save your changes – that should be all you need to do. App pool will recycle…

Why does this work? Who the heck knows – ask the WCF team – you may find them working on the Office Assistant 2.0 project. My guess is that things work better (but maybe slower? more limitedly?) when the ASP.NET pipeline joins the party. Will post here if there are any side effects – so far so good though. 

Tuesday, January 11, 2011

SharePoint Saturday Virginia Beach 2011: Source Code

[placeholder for the Google Analytics project associated with my presentation]

Google Analytics works on your Intranet sites

That’s right – tested this out and was able to have a site on my local VM that I made up a name for (dev.schroeder.local – not resolvable outside the VM itself) successfully work with Google Analytics tracking.

image

 

Official word from Google on this: http://www.google.com/support/analytics/bin/answer.py?hl=en&answer=55510

 

The important caveats are:

  • You must use the latest version of their tracking code.

    • The latest version is the good async stuff, so this is a good move regardless.

 

  • The site must be accessed with a fully qualified domain name (FQDN).

    • I tried to trick it using the _setDomainName method in the client API, but no dice.
    • If your site does not support access via FQDN, you may need to:
      • Add an alternate access mapping to the site in Central Admin
      • Update DNS
      • Redirect the partial name (http://intranet) to the FQDN (http://intranet.company.local)
        • The URLRewrite Module may be able to help you do this: http://www.iis.net/download/URLRewrite
        • Could also go low tech: Add some script to default page to redirect if document.location is NOT the FQDN (though pages accessed directly would obviously bypass this measure)
        • Maybe move that script to the masterpage…
Monday, January 10, 2011

SharePoint Saturday Virginia Beach 2011

Once again, it was a fantastic event.  Thanks to the organizers for letting hack presenters such as myself present.

http://www.sharepointsaturday.org/virginiabeach/default.aspx

 
© I caught you a delicious bass.
Back to top