SharePoint enable iFilter for TIFF OCR

In some companies, paper documents are scanned into TIFF formats and stored electronically.  To search for them, you'll need to enable the TIFF OCR iFilter to allow SharePoint to index TIFF documents.

1. Install Windows Server feature Windows TIFF IFilter:

clip_image002

 

2. Enable OCR filter

clip_image002[7]

 

clip_image002[10]

 

3. You may need to restart the machine

4. Force SharePoint to perform a full crawl from Search Administration

5. Search for your file - here, I'm searching for "Therefore"

tiff-ifilter2

SharePoint 2010 GlobalNavigationNodes Moved

This is a very short blog, but it appears that the GlobalNavigationNodes member on the PublishingWeb class has moved in SharePoint 2010.

http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.publishing.publishingweb.globalnavigationnodes(office.12).aspx

In SharePoint 2007, this was under Microsoft.SharePoint.Publishing.PublishingWeb.GlobalNavigationNodes

http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.publishing.navigation.portalnavigation.globalnavigationnodes.aspx

In SP2010, this has moved under Microsoft.SharePoint.Publishing.PublishingWeb.Navigation.PortalNavigation.GlobalNavigationNodes

 

This particular property is used to read a publishing site's navigation settings - I've used this to export site navigation as XML to accompany a site export.  Since site exports doesn't seem to include any customized site navigation information.  (It still doesn't in SP2010).

 

SharePoint 2010 with IIS URL Rewrite 2.0

Or, how do you remove /Pages/ from SharePoint URL.

Almost all the hard work is done by Waldek Mastykarz (@waldekm)
http://blog.mastykarz.nl/friendly-urls-sharepoint-site-4-steps-iis7-url-rewrite-module/

These are just my extra notes for SharePoint 2010, I'm going to assume you are reading Waldek's article with this blog as a supplement.

How to install IIS URL Rewrite

The easiest way is via the MS Web Platform Installer

clip_image002

On a good connection you are good to go within 30 seconds - faster if you already have MS Web Platform Installer on the server.

Installed, IIS URL Rewrite 2.0 lives here

clip_image004

IIS URL Rewrite 2.0

I seriously think there's a bug with IIS Url Rewrite 2.0's Regex

Waldek's regex pattern for step 3 is perfect:

^(.*/)?Pages/([^/]+)\.aspx$

and so is step 4:

^(.*/)?Pages/default.aspx$

BUG: IIS URL Rewrite matches badly - see screenshot:

clip_image006

Regex will try to maximize to match as many characters as it can. But this simply does not explain why group 1 match includes Pages/ - Why was Pages/ included in the match? This doesn't make any sense.

You can test the pattern with any other regex library, including .NET (via PowerShell), and you still won't get the stupid buggy match that is IIS URL Rewrite's regex…

(Sorry I'm annoyed that this caused a lot of problem for something that shouldn't have existed...)

$pattern = [regex] "^(.*/)?Pages/default.aspx$"

$result = $pattern.match("Publishing/Pages/default.aspx")

$result.Groups[1]

Success : True

Captures : {Publishing/}

Index : 0

Length : 11

Value : Publishing/

Anyway, to fix this we need to tweak the pattern

^(.*?/)?Pages/([^/]+)\.aspx$

^(.*?/)?Pages/default.aspx$

This will finally force IIS URL Rewrite to work properly.

clip_image008

the extra ? tells regex to try to match as little as it can, while still making a match.

clip_image010

Final result – the order is important – see Waldek’s article

 

TRICKS: Debugging URL Rewrite by enabling trace

When things don't work - this is your only hope. Read trace logs.

clip_image012

clip_image014

clip_image016

clip_image018

clip_image020

Fortunately it's not very hard to read, I mean we read SharePoint logs and survived. It's just tedious to read logs in general.

Open the log in Internet Explorer - which picks up the XSL and gives you a nicer looking UI. Head over to the compact view tab, and look for URL_REWRITE_START

clip_image022

 

HORRIBLE PITFALL: URL Rewrite Cache

I've noticed that when you reshuffle a rule (or add a condition to a rule), it doesn't force the cache to bugger off. So you thought you tweaked the rule but it doesn't seem to have any effect. The trace log will tell you that it actually is ignoring your rule reshuffle because it is listening to the "Url Rewrite Cache".

clip_image024

This is OK, until you have a bad URL cached, then suddenly it's annoying. IIS Reset doesn't cut it.  My tip that I ended up with is to toggle a rule's disable/enable state to trigger the URL Rewrite cache to refresh.

clip_image026

 

SharePoint Authenticated

WARNING: I've had SharePoint on various unknown occasions suddenly raise a login dialogue. I can't reproduce this on demand, but it happens frequent enough that I think it's no accident. It also sometimes goes away when I hit F5 refresh and Windows Authentication just works and I don't see any login prompt at all.

The experience reminded me highly of the days in 2007 where sometimes SharePoint will mysteriously ask you to sign in when you are supposedly browsing the site anonymous.

Please test thoroughly.

 

SharePoint Anonymous

For a public anonymous website, this works absolutely great - no authentication to worry about either.

clip_image028

I didn't do much testing with the postbacks and the ribbon. They do work, but I think I'll need a lot more testing to work out if everything is still OK.

My gut feeling is that SharePoint 2010 relies a lot more on AJAX-based client side calls without a full page postback. While the URL rewrite would have affected the postback somewhat, AJAX calls would be largely immune to this problem.

Summary

Definitely try this out on your SharePoint site and I think you'll be surprised how well it worked (once you get it to work). Thanks Waldek for sharing!

Sydney SharePoint User Group 20 July 2010

Presented an updated version of my Silverlight and SharePoint solutions talk in the Sydney user group tonight.  I don't think I timed the presentation well and lost way too much time in the beginning in XAML - which made everything seemed harder, and getting to the fun part much later.

  • Will improve - won't type XAML again, will highlight what's interesting but avoid fiddling live.

Honestly lots of room to improve but I think it was still interesting to a lot of people.  If you were there tonight and feels otherwise please let me know!

Feedback I've received:

  1. Demo at least "worked" even though really slow going in the beginning
    • Will improve, in fact given 1hr I don't think I'll type out the XAML again in the future - this will give me far more time to spend in the code, as well as getting to the fun part a lot quicker
  2. Need more time spend to show end-user Silverlight debugging (no modification to the server required)
    • Which I think would be a lot better use of the time
  3. Need more time to show some nice integration examples
    • Such as my Silverlight Camera which definitely raised eyebrows.
    • And if I can ever get my Silverlight PivotViewer to a decent, presentable state…
    • But basically, people need to see the features that Silverlight and SharePoint brings to the table separately, and why they are suddenly super awesome together.  Have an idea to draw a chart that'll blow everyone away - wait for it on SharePoint Saturday.
  4. Something went wrong at the one-hour mark, where my IE decided to go offline, which made further demo really difficult.  My suspicion is that Fiddler2 died somehow and IE thinks everything has gone funny and offline. 
    • Might have fixed itself by restarting IE.
  5. Definitely need more question time, and end with more links

 

 

Lots of links for news:

A bunch of links I promised Brad Saide, to add to the SharePoint news for the past month:

Productivity Hub 2010
http://www.microsoft.com/downloads/details.aspx?familyid=4AAA9862-E420-4331-8BC3-469D7BAE0FF1&displaylang=en

SPF2010 Update via @dougleung http://sharepointsix.blogspot.com/2010/07/sharepoint-2010-sharepoint-2010-just.html 
http://support.microsoft.com/kb/2032588

Windows Update broke WSS3 (with Windows Internal Database)
http://blogs.msdn.com/b/sharepoint/archive/2010/06/22/installing-kb938444.aspx 
Lesson - don't use automatic windows update on your production SharePoint farm

Silverlight - code behind back to MVVM

Philosophical difference between code-behind and the ViewModel

Because VS.NET is firstly a visual tool, it tries very hard to give developers an easy starting point where you can create your layout and easily add code to various events.

The problem this creates, is that the end result code in the events is a mixture of two type of code:

  • Data access, relating to service calls, maintaining in memory state of the object.
  • Updates to the UI.

The former is what we’re trying to test, whereas the UI is always difficult to test, especially if compounded with animation or frequent changes to the UI.

 

Why do we need to do this?

  • Code-behind is part of the View, application logic doesn't belong here
  • Prolonged mixing of application logic WITH UI login in the code-behind leads to spaghetti code, the main issue is maintenance cost
  • Unable to easily separate and test functionality

 

Refactor and take control - bring Code Behind back into MVVM

I tackle this problem in stages, without stages the problem is too big and you may not be able to stop halfway.

Stage 1 - creating a ViewModel

A ViewModel is a model for a view.  So in your ViewModel you should have any information that is necessary for the UI (view) to render properly.  Remember to implement INotifyPropertyChanged

public class MainViewModel : INotifyPropertyChanged
{
}

 

Add the ViewModel to your View - this can be done in the XAML

 <UserControl.Resources>
    <ViewModel:MainViewModel x:Key="MainViewModelInstance"/>
  </UserControl.Resources>

You can reference the ViewModel in your code behind this way:

var resourceMainViewModel = this.Resources["MainViewModelInstance"];
_mainViewModel = resourceMainViewModel as MainViewModel;

 

Stage 2 - moving application state variables to ViewModel

A typical sign of a lot of code-behind is when we have a lot of member variables in the View.

  1. A majority of them can be moved directly into the ViewModel.
  2. Provide property get/set on the ViewModel and re-wire the Code-behind logic to use the ViewModel for now.

Exercise some judgement here - not all variables should go to the ViewModel, references to UI elements for example, should remain in the code-behind (view).

 

Stage 3 - moving application methods to ViewModel, hooking UI events

Once you've moved your variables to the ViewModel - then you can start looking at moving the methods to the ViewModel.

The trickiest part here, if you have started with code-behind, is that there will be methods that have a mixture of application logic along with UI update calls.

An easy, intermediate way to handle these UI calls is to have the VM raise an event at the specific time, and have the View bind to those events and make the UI updates.

Change any UI update code to UI binding syntax - this should be the normal for most VM entity or collections.

 

Stage 4 - you can start creating Silverlight Unit Tests

By stage 3 - you should have more and more application logic moved back to the ViewModel.  Add a Silverlight Unit Testing project and start instantiating the ViewModel and test the collections and entities can be populated correctly.

From this point onwards because you have the unit tests available you can start to do a lot more refactoring with the methods without worrying that you'll be breaking stuff. 

 

Stage 5 - calling application methods via Commands

Create a DelegateCommand class - unfortunately one isn't provided with Silverlight (I don't know why)

public class DelegateCommand : ICommand
{
    Func<object, bool> canExecute;
    Action<object> executeAction;
    bool _canExecuteCache;

    public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute)
    {
        this.executeAction = executeAction;
        this.canExecute = canExecute;
    }

    public DelegateCommand(Action<object> executeAction)
        : this(executeAction, null)
    {
    }
    #region ICommand Members

    public bool CanExecute(object parameter)
    {
        if (canExecute == null)
        {
            return true;
        }

        bool temp = canExecute(parameter);
        if (_canExecuteCache != temp)
        {
            _canExecuteCache = temp;
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(this, new EventArgs());
            }
        }
        return _canExecuteCache;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        executeAction(parameter);
    }

    #endregion
}

In the ViewModel - change the direct method call from the view into a property DelegateCommand, then in the View, change the Click event handler to Command property via Binding to the ViewModel.DelegateCommand

 

 

Stage 6 - break UI event hooks by binding storyboards via triggers

This is by far the most trickiest - depending on what sort of UI updates you had in the code-behind, it may be very tricky to convert them into storyboards.

Do your best, but don't go overboard on this one - I don't have a good all-round-fix for this one yet.