Sunday, October 30, 2011

Custom Timer Jobs

Some great advice here: http://www.codeproject.com/KB/sharepoint/debugging-sharepointjobs.aspx
…especially the part about restarting the timer service to see code changes take effect. So obvious… now! Would have saved me a plethora of time…

HTTP Header Manager Feature for SharePoint 2010

What is it?
This is a Web Application scoped feature that will strip HTTP response headers out of configured content.

WTH?
Ever forced to download your PDF after uploading it to a document library? Tried to embed a Shockwave/Flash file in a SharePoint 2010 page and have it not work? Then you searched for the solution and it was “just downgrade your server’s security level by changing the Web App’s file handling mode from strict to permissive”. Yeah – downgrading server security is always a great solution. Just make sure you add your SSN to the footer of every page. </sarcasm> Wrote a post on all this – you probably missed it… but that’s cool.

What it does is…

  • Adds a HttpModule to the web app it is activated in. I know, I know – performance blah blah. It is a very quick check to the requested file extension, so it should impact your precious pipeline minimally. Got a better way? Let me hear about it.
     
  • Adds a custom config section to the web.config of the web app. The section references an external configSource…
     
  • Adds a config file named ManagedHeaders.config to the root of the web app. This is where the action is – update this file to add new file types to be 'excluded’ from the strict mode handling.


Below is the default ManagedHeaders.config. Once it is in place, change it to be whatever you want. It is pretty self-explanatory – add an extension, then configure the headers to remove from the response. Also possible to add headers, but that is a different blog post… 

<?xml version="1.0" encoding="utf-8" ?>
<ManagedHeaders>
<extensions>
<add extension="html" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="pdf" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="swf" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="flv" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="csv" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
</extensions>
</ManagedHeaders>


The Files:
Below are links to a WSP as well as a Visual Studio 2010 project, in case you want to look at what is in the WSP, or make any changes.






Friday, June 24, 2011

Inline file types under SharePoint 2010 WITHOUT security downgrade

So you got your site migrated to 2010 and were crazy enough to include Flash and PDF content. Have your testers tried clicking on links to those files yet? Or worse, looked at a page with embedded objects that link to those file types? If so, you have probably discovered that those files are on the SharePoint 2010 naughty list and are no longer served as inline content. While I suspect that this may be a subtle form of revenge from MS directed at Adobe (cannot help but like this), it would be way better if there was some way we could control it…

If you Google this issue, many people proudly report (in their blogs) the solution to be changing the Browser File Handling mode from ‘Strict’ to ‘Permissive’ for the web application:

Browser File Handling
You can specify whether additional security headers are added to documents that are served to Web browsers. These security headers specify that a browser shows a download prompt for certain types of files (for example, .html), and to use the server's specified Multipurpose Internet Mail Extensions (MIME) type for other types of files.
The Permissive setting specifies that no headers are added. The Strict setting adds headers that force the browser to download certain types of files. The forced download improves security for the server by disallowing the automatic execution of Web content. By default, the setting is Strict.

ref: http://technet.microsoft.com/en-us/library/cc262107.aspx

Am I the only one who has a problem with downgrading a SharePoint security setting like this? Apparently so.

To resolve this, here is what I did so that an application may server PDF and Flash (and any other specific content) inline while remaining in strict mode for all other content currently on the ‘no inline’ list:

1. Create a Feature that deploys a new HttpModule in IIS. Say what you want about how they inspect every request, do it right and the impact is almost undetectable.

2. Within that HttpModule, check the current requested file’s extension.

3. Using a custom configuration section, allow a set of ‘handled’ extensions to be defined, along with a set of HTTP headers to be removed.

4. Deploy your solution and add in sections to remove the X-Download-Options, X-Content-Type-Options, Content-Disposition headers from FLV, PDF, and SWF files

Simple. Here is an example of what one of our config files looks like to allow PDF, SWF, and FLV files to be served inline:

<add extension="pdf" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="swf" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />
<add extension="flv" removedHeaders="X-Download-Options;X-Content-Type-Options;Content-Disposition" />

As you might be able to tell, the solution also allows you to add headers to a specific file type, which would let you add to SharePoint’s inline naughty list if you should some day have a need for it.

If you are reading this and say to yourself ‘Hmmm – this sounds useful, sure wish I had the code for it…’ then you are in luck – just leave a comment and the code shall be posted!! Otherwise, I ain’t going to bother with it – already bothered enough firing up Live Writer to post this post.

[Update!] I finally got around to posting the files! They are at the bottom if this post here.

Thursday, March 31, 2011

SharePoint Migration: A Case Where Different == Good

So there I was, moving a 2007 Web from a site collection in a 2007 Farm to a site collection in a 2010 Farm [Some day I will get around to a long post about that – don’t hold your breath though] and I was going through the differences between the 2007 web and the 2010 web with a fine toothed comb (aka custom utility I wrote up for the purpose) when I found a difference in list templates:


2007 Web


<listTemplate Name="Document Library" BaseType="DocumentLibrary" CategoryType="Libraries" Description="Create a document library when you have a collection of documents or other files that you want to share.  Document libraries support features such as folders, versioning, and check out." DocumentTemplate="101" FeatureId="00bfea71-e717-4e80-aa17-d0c71b360101" Hidden="False" InternalName="doclib" IsCustomTemplate="False" Type="DocumentLibrary" Unique="False" />

2010 Web


<listTemplate Name="Document Library" BaseType="DocumentLibrary" CategoryType="Libraries" Description="A place for storing documents or other files that you want to share. Document libraries allow folders, versioning, and check out." DocumentTemplate="121" FeatureId="00bfea71-e717-4e80-aa17-d0c71b360101" Hidden="False" InternalName="doclib" IsCustomTemplate="False" Type="DocumentLibrary" Unique="False" />

See the difference? You should, since I highlighted it and all. Yes, the descriptions are also different, but I think you are safe from that difference causing widespread problems...


Having different doc templates for the doc library lists warranted some further investigation – just to make sure this was not going to be an issue. So checking into the document templates referenced by each, we have:


Template 101


<DocumentTemplate Path="STS" DisplayName="$Resources:core,doctemp_Word97;" Type="101" Default="TRUE" Description="$Resources:core,doctemp_Word97_Desc;">

Template 121


<DocumentTemplate Path="STS" DisplayName="$Resources:core,doctemp_Word;" Type="121" Default="TRUE" Description="$Resources:core,doctemp_Word_Desc;">

Result: Rather than have SharePoint 2010 date itself (2010 is last year at the time of this writing), it now shows the generic ‘Microsoft Office Word document’ as the type name, as opposed to ‘Microsoft Office Word 97-2003 document’. So this turns out to be a welcome change and a good idea – especially when it is 2015 and I am deploying SP 2010 to a datacenter on the moon (dark side of course).



Tuesday, March 1, 2011

Windows 2008 VM Freeze

This has come up multiple times now – so recording it for posterity:

Having VMWare Server based development workstations is usually great for controlling a SharePoint development environment. On several occasions a new VM for SharePoint 2010 development (Windows Server 2008 R2, Visual Studio 2010, SharePoint 2010) has frozen on us. And not frozen as in “it is all slow because the host is low on resources” – frozen as in “will be uncovered by alien scientists in a few thousand years who will recreate a scene with it’s adopted mother” (AI was interesting, if nothing else, right?)

So looking at all the usual suspects proved fruitless in the usual way: VMWare tools was installed and up to date. Physical disk was fine, as were the virtual ones. No viruses or malware detected. This all would have been too easy.

I stumbled upon the answer by observing that the machine still had a heartbeat once frozen – there was just no way to interact with it (including pause/shutdown commands) – but there were a few things that indicated life – network activity, CPU cycles, etc. So that narrowed the focus to video. Like I mentioned before, VMWare tools was installed and up to date – the VM was also using the VMWare SVGA II adapter.

The Fix

Disable video hardware acceleration.

If you think about it, it makes sense that you would not have hardware acceleration enabled within a VM. Problem is, these were all clean vanilla installs – so it was defaulting to a hardware acceleration configuration. If you think about it more, having hardware acceleration on should NOT cause a complete video freeze within a VM, since in theory the hardware ‘exists’ – it is just virtual is all.

In case you are wondering how to get to the place to view and modify video hardware acceleration, it is a little hidden in Windows 2008 R2:

image    image

Tuesday, February 15, 2011

SharePoint 2010: Email A Link….Sample?

This was some strange behavior: The ‘E-mail A Link’ option in the ECB – or whatever the SharePoint 2010 name for ‘context menu’ is – was opening up the email client (in this case Outlook 2010) with a new email that contained the word ‘Sample’ – no link to the document, just the word ‘Sample’.

image

image

I will not reveal that in 2010 that the ‘E-mail a Link’ action results in a round trip to the server for no good reason (oops) – but I will reveal that it is this round trip that caused the issue.

Resolution

Since WCF is messing with you again just because you probably wanted a site with multiple authentication schemes and did not want the headache of extending the site,  add this to the site’s root web.config to make WCF clam up:

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

That is strike #3,9343,091, WCF!!!  

image

BTW, this also had the nice side effect of fixing SPDesigner 2010 access to the site. Once change in place, SPDesigner could access the site.

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