May 2010 - Posts

As a SharePoint developer, I’m sure you were excited to see the Developer Dashboard.  It’s a great way to see what’s going ton with the performance of a page.  Did you know you can add your own performance monitors to it though?  It’s actually quite easy with the SPMonitoredScope class.  Simply, put the code in question that you want to monitor inside a using block and SPMonitoredScope does the rest.  For today’s example, I want to monitor the performance of some code that inserts an item into a list.  Here is what it looks like.

using (SPMonitoredScope monitoredScope = new SPMonitoredScope("My Monitored Scope"))

{

    // put code to monitor performance on here

    SPList testList = site.Lists.TryGetList("Test List");

    if (testList != null)

    {

        SPListItem listItem = testList.Items.Add();

        listItem["Title"] = string.Format("Test Item {0}", Guid.NewGuid().ToString());

        listItem["City"] = "Somewhere";

        listItem["Quantity"] = 3;

        listItem.Update();

    }

}

I just give the SPMonitoredScope a name and put my code inside the using block.  Don’t you just love TryGetList?  This code assumes I already have access to a SPWeb.  In this case I am running it inside a Visual Web Part and I left out some of the other code involved.  When we view the page and have the developer dashboard running it looks like this.

SPPerformanceMonitorDashboard1

There you can see My Monitored Scope in the list at a runtime of 2442.77 ms.  Wow, that is some poorly performing code.  It would be nice if we could get some more detail.  Well what is cool is that you can actually nest using blocks to get performance data at a more granular level. 

using (SPMonitoredScope monitoredScope = new SPMonitoredScope("My Monitored Scope"))

{

    SPList testList;

 

    using (SPMonitoredScope getListMonitor = new SPMonitoredScope("Get List"))

    {

        testList = site.Lists.TryGetList("Test List");

    }

 

    using (SPMonitoredScope addListItemMonitor = new SPMonitoredScope("Add List Item"))

    {

        if (testList != null)

        {

            SPListItem listItem = testList.Items.Add();

            listItem["Title"] = string.Format("Test Item {0}", Guid.NewGuid().ToString());

            listItem["City"] = "Somewhere";

            listItem["Quantity"] = 3;

            listItem.Update();

        }

    }

}

Now, I have added blocks to track the time it takes to get an instance of the list as well as the time it takes to add the item.

SPMonitoredScopeDeveloperDashboard2

From here we can see that the bulk of the time spent is on adding the list item.  Almost a full two seconds.  You have to love virtual machines. :-)  I think this class is very powerful and I can see it quickly becoming a best practice to having one or more SPMonitoredScope wrapped around the code you are executing.  Start using it today!

One of the things that drove me absolutely nuts about Enterprise Search in MOSS 2007 was that there was no built-in way to export your managed property mappings and install them on a new server.  A third party utility on CodePlex helped, but it was still less than ideal.  With SharePoint 2010, well you still really can’t export your property mappings to a file, but you do get a lot of flexibility using PowerShell.  By taking a proactive approach, we can use PowerShell instead of the UI to create our property mappings. We can then use these same scripts later when its time to move these settings to production.  The SDK does a pretty good job with examples on how to use all of the commands we need, but I found a few minor errors and omissions.  We’ll look at some of the individual commands and then put it all together.  Our goal at the end of this is to have a .ps1 script that you can store in your source control system.

The first thing we need to do is get a reference to our search service application.  By default, it just so happens to be called Search Service Application.  However, if you installed it manually, or are using FAST, it is likely to be called something different.

$searchapp = Get-SPEnterpriseSearchServiceApplication "Search Service Application"

We assign this to a variable called $searchapp (or whatever you want) so that we can reference it later in the script.  In today’s example, I have some site columns on a document library that I want to use as managed properties.  In this case I have site columns called TestProperty1 and TestProperty2.  If I were to perform a full crawl, Enterprise Search would automatically create crawled properties called ows_TestProperty1 and ows_TestProperty2.  However, I want to save myself some time and skip that full crawl.  This is especially valuable when you have a large index.  Luckily, I can just create these crawled properties using PowerShell using the New-SPEnterpriseSearchMetadataCrawledProperty command (i know that’s a lot to type).  The syntax is pretty simple, but there are a few gotchas.  First the VariantType parameter isn’t entirely obvious.  I know 31 is text, but I’m not sure exactly what value to use on other types.  The link from the SDK give you quite a few values (note they are all in hex), but I still need to figure out the rest of the values sometime.  The other thing is the PropSet parameter is marked as optional when in fact it is required.  I’m really not sure what value you should use here and when so I just used the same GUID most crawled properties used (viewable from the UI), 00130329-0000-0130-c000-000000131346.  We also have to get a reference to the crawled property category that we want (in this case SharePoint) so we call Get-SPEnterpriseSearchMetadataCategory first and pass that to the Category attribute.   Here is what the commands looks like to create TestProperty2.

$category = Get-SPEnterpriseSearchMetadataCategory –Identity SharePoint -SearchApplication $searchapp

$crawledproperty = New-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $searchapp -Category $category -VariantType 31 -PropSet "00130329-0000-0130-c000-000000131346" -Name ows_TestProperty2 -IsNameEnum $false

You can verify that it was created in SharePoint using the UI.

EnterpriseSearchCrawledProperty

Now, we need to create a managed property using the New-SPEnterpriseSearchMetadataManagedProperty command.  The documentation on the Type parameter for this command is a bit sketchy too.  Currently, it lists the six managed property types Text, Integer, Decimal, DateTime, YesNo, Binary, but it doesn’t say what the value for each one is (the parameter requires an int).  From the example, they give I was able to determine that 1 is a test.  At some point, I’ll go find the enum in the SDK and see what the rest of the values are.  The rest of the command is pretty simple, just specify a name and pass a reference to the service application.

$managedproperty = New-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $searchapp -Name TestProperty2 -Type 1

You may have noticed I am assigning the result of each New command to a variable.  This is so that we can pass that in to the New-SPEnterpriseSearchMetadataMapping command.  Just pass in references to the service application, managed property, and crawled property and you are done.

New-SPEnterpriseSearchMetadataMapping -SearchApplication $searchapp -ManagedProperty $managedproperty -CrawledProperty $crawledproperty

Here is what the command looks like in PowerShell.  It simply gives you info on what was created.

PowerShellCreateManagedPropertyMapping

If you need to map multiple crawled properties to a managed property simply call the command repeatedly with a reference to each crawled property.  Once you finish, you can verify in the UI that the managed property was mapped successfully.

PowerShelllManagedProperty

At this point, you need to do a full crawl to make use of your managed properties.  Here is what the whole script looks like put together with multiple mappings.

$searchapp = Get-SPEnterpriseSearchServiceApplication "Search Service Application"

$category = Get-SPEnterpriseSearchMetadataCategory –Identity SharePoint -SearchApplication $searchapp

$crawledproperty = New-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $searchapp -Category $category -VariantType 31 -PropSet "00130329-0000-0130-c000-000000131346" -Name ows_TestProperty1 -IsNameEnum $false

$managedproperty = New-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $searchapp -Name TestProperty1 -Type 1

New-SPEnterpriseSearchMetadataMapping -SearchApplication $searchapp -ManagedProperty $managedproperty -CrawledProperty $crawledproperty

 

$crawledproperty = New-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $searchapp -Category $category -VariantType 31 -PropSet "00130329-0000-0130-c000-000000131346" -Name ows_TestProperty2 -IsNameEnum $false

$managedproperty = New-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $searchapp -Name TestProperty2 -Type 1

New-SPEnterpriseSearchMetadataMapping -SearchApplication $searchapp -ManagedProperty $managedproperty -CrawledProperty $crawledproperty

$crawledproperty = New-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $searchapp -Category $category -VariantType 31 -PropSet "00130329-0000-0130-c000-000000131346" -Name ows_TestProperty2a -IsNameEnum $false

New-SPEnterpriseSearchMetadataMapping -SearchApplication $searchapp -ManagedProperty $managedproperty -CrawledProperty $crawledproperty

It seems like a lot but it really isn’t.  I create two managed properties (TestProperty1 and TestProperty2).  In the case of TestProperty2, I actually map two crawled properties to it. 

As far as I am concerned this is the only way to go from now on when it comes to doing property mappings.  Once you have the script down, it’s much faster than clicking through the UI and of course you can run it on other servers.  Be sure and give it a try as you start setting up search on all of your new SharePoint 2010 deployments.

A while back, Kevin Williams pointed out to me that certain web sites could be searched in Google Chrome using the syntax <ur> query in the address bar.  For example, once I have been to youtube.com, I can later type in youtube to initiate a search query.

ChromeOpenSearchYouTube

Pressing tab, give you a spot to enter your query or you can just type a space and put in your keyword.

ChromeOpenSearchYouTube2

As someone that does a lot of work with SharePoint Enterprise Search, this got me thinking.  I want my SharePoint site to show up in my browser too.  I did some research and discovered this is part of OpenSearch and that I can achieve the same result with any OpenSearch compatible search engine (which SharePoint is), so I knew this would be relatively easy to research.  I figured this kind of thing might already be included in SharePoint 2010 (and maybe it is and I just haven’t found it), but from what I can tell it’s not.  If anything, you can use this technique in SharePoint 2007 as well.  If this file is auto generated somehow, I would love to hear about it.

To get started, you must first create an XML file which describes where to point search queries on your web server.  The filename does not matter (search.xml in my case).  The syntax is pretty simple, but there are a couple of things to watch out for.  I started with Microsoft’s description of how to create a file on MSDN.  However, it appears there is an issue in the documentation (or maybe something changed in a different version).  The issue I saw is that on the URL element, it says you an attribute called format.  I could not get this to work so I looked at working examples on site and discovered they had the attribute listed at type.  The other issue I ran into in this file is apparently the ShortName element cannot have capital letters in it.  Here is what my entire file looks like for my server called sp2010

<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">

  <ShortName>sp2010</ShortName>

  <Description>sp2010</Description>

  <Url

    type="text/html"

    method="get"

    template="http://sp2010/search/results.aspx?k={searchTerms}" />

  <Url

    type="application/rss+xml"

    method="get"

    template="http://sp2010/_layouts/srchrss.aspx?k={searchTerms}&amp;start={startIndex}&amp;cnt={count}" />

  <Image height="16" width="16" type="image/vnd.microsoft.icon">http://sp2010/_layouts/images/favicon.ico</Image>

</OpenSearchDescription>

The ShortName element specifies the keyword to type into Chrome to prompt you to do a search (i.e.: youtube.com up above, sp2010 in our case).  You need to already have a search center created.  In my case I have a site called Search and I will point to a results page in there called results.aspx.  You will change this according to your environment.  For browser based search results, we use a type of text/html.   We use the keyword URL syntax here so the browser passes in what you searched for as the {searchTerms} token to the k query string parameter.   You will notice I have a second Url element present.  This is here in case you want to use this same while to do Windows 7 federated search.  I’ll talk briefly about that in the end, but it uses the path to the RSS feed of your search results.  You can also include a custom image icon with the search results as well along with many other things.  Read the MSDN article for more information on what you can put in this file.

The next thing we need to do is put this XML file somewhere on the SharePoint server.  You can just open SharePoint designer and drag it to the root of the server or put it in a document library somewhere.  It doesn’t matter as long as you know the URL to it.  The next thing we have to do is put a link tag in your master page file specifying where this XML file is.  You should normally deploy master pages via solution package and feature, but for today’s purposes, I just opened SharePoint Designer and customized v4.master (gasp!).  Remember v4.master is the new default master page for sites running on v4.  Add the following line somewhere in the head tag and change the URL to your XML file.

<link rel="search" type="application/opensearchdescription+xml" href="/XmlLibrary/search.xml" title="SP2010" />

Remember to check the file in when you are done.  One thing to point out about SharePoint 2010 is that it won’t serve up some file type directly to the browser (it forces a download).  I think this may cause issues, so at the suggestion of @danluciano, I changed the browser file handling of my Web Application in central admin (Central Admin –> Web Applications –> General Settings).  It’s set to Strict by default and I changed it to Permissive.  You don’t need to worry about this in SharePoint 2007.  Honestly, it may work in SharePoint 2010 without changing this but when I was running into issues getting things working earlier this seemed to be a possible issue.  If you try it without, let me know. :-)

WebApplicationGeneralSettingsFileHandling

At this point, if you did everything right, you should be able to use your new keyword in Chrome after visiting your SharePoint site.  Here is what mine looks like after type in sp2010.

ChromeOpenSearchSharePoint

 

Hitting enter I get my usual search results page.

OpenSearchResults

I think this is pretty cool.  You should be able to use this in other browsers as well such as IE8, but I really like how Chrome handles it.  Now I mentioned Windows 7 federated search.  You can take the file you created above, save it to your desktop as .odcx file extension and install it. What makes this possible is the second URL element we specified using the application/rss+xml type.

OpenSearchInstallODCX

 

You will see the following prompt.

OpenSearchConnectorPrompt

When you open Windows Explorer, it will show your SharePoint site in the list of Searches.  It also adds it to your favorites.

Windows7FederatedSearchList

Clicking on the SP2010 search connector here allows us to search the SharePoint site directly.  You will be prompted for authentication if necessary.  Executing the same search query above looks like this.

Windows7FederatedSearch

Clicking on any of the links takes you directly to SharePoint.  Remember you can implement this now with SharePoint 2010 or SharePoint 2007.  It’s definitely cool and another great way to get data out of SharePoint.

SharePoint 2010 Enterprise Search has great wildcard search support built in now.  However, it requires the use to add an asterisk to their query every time they want a wildcard search.  This is a great step compared to what we had in MOSS 2007, but now it results in a training issue.  In 2007, many people wrote custom code or relied on the Wildcard Search Web Part that I built.  So I thought why not use the QueryManager object to override the query and add an asterisk to the query for the user. 

Since they’ve given us some methods to override now on the CoreResultsWebPart, these kind of changes can be done easily without using reflection.  We start by adding assembly references to Microsoft.Office.Server.Search.  Then we create a new web part inheriting from CoreResultsWebPart and add the following using statements.

using Microsoft.Office.Server.Search.Query;

using Microsoft.Office.Server.Search.WebControls;

We then override the GetXPathNavigator method and get a reference to the QueryManager and override the UserQuery property.  In reality, there are only two lines of code involved.

QueryManager queryManager = SharedQueryManager.GetInstance(this.Page).QueryManager;

queryManager.UserQuery = string.Format("{0}*", queryManager.UserQuery);

You can look at the code in the CodePlex project for specifics.  Instructions to add the solution package are included in the readme.txt file.  You can use PowerShell to add the solution package or use stsadm still if you like.  Once the solution is installed, activate the Wildcard Search Core Results (DotNetMafia.com) site collection feature.

WildcardSearchFeatureActivated

Now, go edit any search center results.aspx page you have and use the add web part button on the bottom zone.

WildcardSearchResultsBottomZoneAddWebPart

Click on the Search group, and choose the Wildcard Search Core Results (DotNetMafia.com) web part.

WildcardSearchAddWebPart

Remove the existing CoreResultsWebPart from the zone and drag it into place.  You can then stop editing (or publish) the page.  Try a wildcard query and you should get results like the one below.

WildcardSearchResults

Notice how i search for accoun and yet I get matches for Accounting and Account.  Very cool.  I’ll warn you that this is a very preliminary release.  It definitely needs more testing so if you run into issues, please let me know.  This was compiled against the release version of SharePoint 2010.  Give it a try and let me know what you think.

Wildcard Search Web Part for SharePoint 2010

Follow me on twitter.

As some of you know by now, I’ve really been pleased with the performance and features that are offered by Sun VirtualBox.  I get asked about it quite a bit when I give talks.  Specifically people ask me what I think about it and why I chose it.  Simply put, it allows me to run 64 bit guests on my Windows 7 machine and the price is right (free).  Other virtualization platforms simply either can’t run 64 bit guests, can’t run on Windows 7, or cost money.  You can infer which solutions I am referring to right there. :-)  Some of my friends are probably in shock right now since I am recommending a non-Microsoft product. :-)  Another nice benefit of it is that it can open both VMware and Virtual PC hard disk images.

Since I’m on a laptop, I am often switching between wired and wireless networks.  This can prove to be a pain in your Virtual Machine if you don’t either shut it down and reconfigure the network or make this one simple change.  For those familiar with virtualization, this probably already seems obvious.  For those out there that are relatively new to this, you might appreciate this simple tip I have for today.  My goal?  To have Internet access on my virtual machine regardless of which physical network adapter is used.  To do this, we make use of the Bridged Adapter setting as seen below.

VirtualBoxNetworkAdapter1

Note how it is bound to a specific network adapter on my laptop.  In this case, it is the Gigabit Ethernet adapter.  I want my VM to have Internet access when I am on a wireless network too, so the way to do this is simply enable a second virtual network adapter.

VirtualBoxNetworkAdapter2

Note, this one is configured to use my wireless network adapter.  The Bridged Adapter setting is not the default so you have to select it.  If you don’t have working Internet access on one of your virtual machines, try this technique using bridged adapters and it should get you going.  As a remind, the Virtual Machine has to be fully powered off before you can change any of these settings.  If you are using another virtualization platform, you can also use this same trick.  I would love to see virtualization software just default to settings like these but I am sure there is a good reason to do it the way they are. :-)

We wanted to do something special for the launch of SharePoint 2010.  It’s just such a cool product that we wanted to make it special.  So next week on a special night, we are doing a mini-launch event at Dave & Buster’s (6812 S. 105th East Ave) on May 13th at 6pm.  David, Dennis, and Chris did an excellent job finding sponsors and organizing the event.  I didn’t get to help organize as much as I would have liked due to being out of town and what not, so be sure and thank those guys when you see them.  Our speaker will be the SharePoint Cowboy himself, Mr. Eric Shupps.  It’s guaranteed to be entertaining.  As of right now there are only 13 tickets left, so be sure to claim yours today!  Register now!

Thanks again to K2, GDH, and Metalogix for sponsoring the event and help make this possible.

I had a great time this weekend at SharePoint Saturday Houston.  The event was well run and @danluciano, @victor_chat, @davidfrette, and everyone else involved did a great job.  I’m not sure what the final turnout numbers were, but it sounds like there was more than 400.  I had the privilege of doing two talks: PowerShell Basics in SharePoint 2010 and Introduction to SharePoint 2010 Enterprise Search.  The PowerShell talk was a joint talk with Kyle Kelin (@SPKyle) and was a lot of fun.  As promised, the slides are attached.  If you were in the PowerShell talk, I mentioned the post about building a cmdlet, so here is the link.

Slides

Thanks for coming to my talks.  I look forward to seeing every one at the next event.