June 2008 - Posts

The default file upload size in SharePoint is 50 MB.  Sometimes, you may have users that need to upload documents that are larger.  This is quite easy to change.  Simply go to Central Administration -> Web Application General Settings.  Select the Web Application you want to change, and you will see a textbox to specify the maximum upload size.  Before I remembered to look here, I tried changing it the old ASP.NET way, by changing the following line in the web.config.

<httpRuntime maxRequestLength="51200" />

Interestingly, the file size specified here is also 50 MB, but changing it here does not allow you to upload a larger file into a document library.  I also figured I might have to change it to match whatever I had set in SharePoint but you don't.  You can leave it the same and upload a 100 MB file into SharePoint just fine (provided you changed the setting).  So from what I can tell SharePoint does not use this setting at all and it would only apply if you had written a custom upload form using ASP.NET.

with 7 comment(s)
Filed under:

I really don't use SharePoint Designer all that much but on occasion I do find it really useful.  The case I am talking about today is using it to view and modify values in a site's property bag.  To do this, open SharePoint Designer and go to the Open Site menu.  When looking at the Open Site menu it isn't apparent at all that you can enter a URL there, but you can.  Enter the full path (i.e.: http://moss-server/MySiteCollection/MySite) to the site you want to look at then click Open.  Enter your credentials if necessary and then you should get a view of the site.  Ok, that part is pretty basic and you probably already knew how to do that.

To view the property bag.  Go to Site -> Site Settings.  Then click on the Parameters tab (not sure why they didn't just call it Property Bag).  On this tab, you can see the values of all of your custom property bag values (it doesn't show anything built-in).  If you need to, you can also modify and remove values from the property bag here.   Hopefully this tip is useful sometime in the future when you need to check the values of your property bag.  It sure beats the alternative of writing code to display it or firing up the debugger.

After having success with implementing wildcard search with MOSS, I decided to look into this whether or not I could inherit from the PeopleCoreResultsWebPart today to implement wildcard search functionality and unfortunately I did not get very far.  The issue is that the class is sealed.  This means that I can't just simply inherit from it and change the method that sets the query.  I now understand that the only reason CoreResultsWebPart is not marked sealed (its the only search web part that isn't) is because it had to be left unsealed so that the People Search web part could inherit from it.  I can probably do some more hacking by creating my own web part and using some reflection to load the PeopleCoreResultsWebPart and change what I need to, but that is going to take some time.  In the meantime, you can always use the WildcardSearchCoreResultsWebPart (but of course you give up all of the fancy PeopleCoreResultsWebPart functionality) or you can make use of Ramon Scott's handy JavaScript.

I repeatedly find that WSS_AdminService.log is reguarly a source of problem on the SharePoint servers that I work with.  The problem is that this file gets written to every minute and it keeps growing and growing and there doesn't appear to be any known way to tell SharePoint to truncate it or purge it like normal logs.  I examined the contents and there appears to be no valuable information in it compared to the regular logs in the 12 hive.  At one point, this log file on one of my servers had grown to be over 1 GB.  This can be a real issue on a virtual machine you use for development since you don't always have a lot of disk space available.  The file can be typically found in the location below.

C:\Documents and Settings\Default User\Local Settings\Temp\WSS_AdminService.log

You may want to rename it, move it, or do something with it, but I usually just delete it.  It would be nice if SharePoint would take care of this file for you, but for now it looks like you are going to just have to take care of it manually or write a script to delete it periodically.

with 2 comment(s)
Filed under:

I came in after the weekend to find out that someone reported the following error when trying to use my Enterprise Search page.

The search request was unable to connect to the Search Service.

As you may know, this is a very generic error that means something with Enterprise Search is really messed up.  Either that or the service isn't running.  I decided to check the Event Log and was pleasantly surprised to actually find something in it.  Here is what I found.

Query machine 'MOSS_SERVER' has been taken out of rotation due to this error: The content index is corrupt.   0xc0041800.  It will be retried in 15 seconds. Component: b1df2e81-4375-4110-b5b1-ddf3acb128bc.

Why my content index got corrupt, I don't know.  In this particular case it was a development machine running on a virtual machine.  Maybe there was an issue writing to the disk at some point, who knows.  After doing some searching on Google, about the only solution I saw found was to remove the Office SharePoint Server Search service and recreate it.  I didn't particularly like this solution, so I ended up making use of the Reset all crawled content link.  Not exactly an ideal situation, but that is what I did and then I recrawled all of my content.  Everything seems to be working great so far.  Hopefully it will not happen again.

Not too long ago, I talked about how to remove the Explorer View from a document library.  As part of the post, I mentioned that I would post how to build a custom document library in the near future.  That is what I am covering today.  I really don't know what the best practice is on how to create a document library, I am just going to show you how I have done it in the past.

Usually, the way I start is by taking a copy of the existing builtin SharePoint DocumentLibrary feature and add it to a new Visual Studio solution.  Typically I would put this in a 12 hive folder (i.e. TEMPLATE\FEATURES).  The next step is I rename the DocumentLibrary feature folder (i.e. CustomDocumentLibrary).  The next thing you will want to do is edit the Feature.xml file.  We have to make some basic changes so that this is considered a new feature.  Therefore, you will want to pick a new GUID for the Id and give it a new Title and Description.  You may also want to change Hidden to False so that you can activate it and deactivate it through the UI.

Next, we need to edit the ListTemplates/DocumentLibrary.xml file.  This file defines the list template itself.  The first thing you need to change is the Type.  The Type number for a Document Library is 101.  It is recommended that user defined list templates start with 10000, so pick any number in that range that isn't used.

The next file you need to modify is the DocLib/Schema.xml file.  On the root List element, you will want to change at the minimum the Title element.  You may also want to set EnableContentTypes to true if you want to use custom content types.  Set FolderCreation to false if you have a custom folder type and set VersioningEnabled to true if you want versioning enabled in the document library.  The Url property I believe is the default URL that you document library will use when created.  It is specified as a relative path (usually just the folder name).   Here is what a typical root list element looks like.

<List xmlns:ows="Microsoft SharePoint" Title="My Custom Document Library" Direction="$Resources:Direction;" Url="My Custom Documents" BaseType="1" xmlns="http://schemas.microsoft.com/sharepoint/" EnableContentTypes="True"  FolderCreation="false" VersioningEnabled="true">

 

I have been leaving the BaseType attribute set to 1 and things have been working fine.  However, I have a feeling that it should probably be set to 101 so that Document Library is the base type.  In the MetaData section, you can override the folder and document content types.  I discussed how to properly do that in this post.  You just need to reference the content types you are using and then also add Field elements for each custom site column you are using in those content types.  Again, the post mentioned above describes how to do that.   The Scema.xml file is also where you can remove (or create) different views for your document library.  This is where you would go to remove the explorer view that I mentioned a while back.

Once you have made these changes, you are ready for deployment.  There are other files in the DocLib folder, but I typically don't mess with them.  Your custom document library can be deployed by copying out the feature and using stsadm or you can create a solution file for it.  Once the feature is activated you are ready to create instances of your new document library.  Also note that the Visual Studio Extensions for SharePoint can also create a lot of these files for you, but you will still need to go through and customize your various XML files.

I have had countless people tell me that they want to be able to do wildcard search in MOSS Enterprise Search using the existing Search Center site templates.  The Search Center site template uses keyword query syntax which does not support wildcards.  To get wildcards you need to use a full text SQL query.  Until now the only solutions to getting wildcard search was either use Ontolica's Wildcard Search or write your own search page.  Neither option has ever been appealing to me.  Ontolica replaces the entire search center and provides an extra layer of abstraction to your managed properties.  I didn't want to write my own search page because the search center already produces great looking results and it would be a lot of effort to reinvent everything on the search page.  The reason why you would have had to write your own search page is that you could not get access via conventional means to the objects to change the query.

This is why I finally decided to take matters into my own hand.  I really just wanted to just inherit from CoreResultsWebPart, change out the keyword query with a FullTextSqlQuery and call it good.  Anyone who may have looked at this before knows it is not that simple.  The class that does all the work SearchResultsHiddenObject is marked internal.   Right now this seems an impossible task unless you bend the rules a little.  That's right.  I decided I am going to break OO rules and use reflection to get to the properties I needed.  Some people say you should never do this and that its a hack.  I agree to some extent, but when you are programming against an API and the provider of said API doesn't give you the tools you need to do your job, sometimes you have to bend the rules.  Let's face it.  Microsoft should have given us this support out of the box and at the minimum should have allowed us to change the query that the CoreResultsWebPart executes through the API.  They did neither so here we are.

So how does the code work?  Well, CoreResultsWebPart happens to be the one class in all of the Enterprise Search controls that isn't marked sealed.  That is good news.  Through the use of Reflector, I discovered the method I need to inherit from is SetPropertiesOnHiddenObject.  Microsoft was even nice enough to mark this method as virtual for me.  I then got access to the type and then used the base type to get a FieldInfo object for the private field srho (which is the SearchResultsHiddenObject). 

// get the type of the current object

Type coreResultsWebPartType = this.GetType();

 

// get the private field containing the searchResultsHiddenObject

FieldInfo searchResultsHiddenObjectField = coreResultsWebPartType.BaseType.GetField("srho", BindingFlags.NonPublic | BindingFlags.Instance);

Once, I got access to the hidden object, I read the value of the KeywordQuery property to get what the user searched for.  I then had to set this value to null, because I was replacing the keyword query with a FullTextSqlQuery. 

// get the actual internal srho object attached to CoreResultsWebPart

object searchResultsHiddenObject = searchResultsHiddenObjectField.GetValue(this);

 

// get the type of the srho

Type searchResultsHiddenObjecType = searchResultsHiddenObject.GetType();

 

// get the keyword query property

PropertyInfo keywordQueryProperty = searchResultsHiddenObjecType.GetProperty("KeywordQuery", BindingFlags.Instance | BindingFlags.Public);

 

// read what the user searched for

string keywordQuery = (string)keywordQueryProperty.GetValue(searchResultsHiddenObject, null);

 

// set the keywordProperty to null so we can change it to a fullTextQuery

keywordQueryProperty.SetValue(searchResultsHiddenObject, null, null);

It was then just a matter of forming a new SQL query string (check the code on how I did that), and setting some additional fields _IsFullTextQuerySetFromForm and m_bIsKeywordQuery

 

// get the fullTextQuery field

PropertyInfo fullTextQueryProperty = searchResultsHiddenObjecType.GetProperty("FullTextQuery", BindingFlags.Instance | BindingFlags.Public);

 

// create a new query and set it

string fullTextQueryString = GetFullTextQuery(keywordQuery, keywordsAsQuery);

fullTextQueryProperty.SetValue(searchResultsHiddenObject, fullTextQueryString, null);

 

// this field needs to be set to true to use a full text query

FieldInfo fullTextQuerySetField = searchResultsHiddenObjecType.GetField("_IsFullTextQuerySetFromForm", BindingFlags.NonPublic | BindingFlags.Instance);

fullTextQuerySetField.SetValue(searchResultsHiddenObject, true);

 

// tell the srho that it is not a keyword query any more

FieldInfo isKeywordQueryField = searchResultsHiddenObjecType.GetField("m_bIsKeywordQuery", BindingFlags.NonPublic | BindingFlags.Instance);

isKeywordQueryField.SetValue(searchResultsHiddenObject, false);

The code for this is really pretty simple (aside from the reflection).  Had the SearchResultsHiddenObject been marked public, we could have had this functionality over a year ago, but oh well. 

Installation

Installation is relatively simple and instructions are included in a readme file in the document.  A solution package has been provided for ease of installation.  Once the package has been installed activate the Wildcard Search Web Part feature on your site collection.  I went with a site collection feature because the search center site does not have a web part gallery in it.  Now that the feature is activated, go to your results page in your Search Center, edit the page, and add the Wildcard Search Core Results Web Part to the Bottom Zone.  You can then remove the old CoreResultsWebPart.  Also note that this web part requires .NET Framework 3.5 because I used LINQ to XML to parse through the SelectColumns property.

Usage

Once you have the web part installed, you can perform a wildcard search by just adding an asterisk to whatever you type in the search box.  For example app* would return mataches on app, apple, and application.  You can also set the Always Use Wildcard property in the Miscellaneous property settings to always perform a wildcard search.

One thing to note.  Wildcard searches reek havoc on your search relevance.  Where you might be used to having nice clean looking results with your keyword searches, your wildcard searches will look different.  It might not always be obvious why a particular item was returned in the search results.  The best thing to do is try and see if it works for your particular situation.

This type of web part probably could have been sold, but I thought it was more important to give it to the community.  This feature gets asked for by MOSS customers all the time.  Finally there is an easy solution to implementing it.  Since this web part is new, I am sure there are going to be issues with it.  Please, log any issues you run into in installation or in us on the issue tracker of the CodePlex site.  Currently, it only supports simple keyword queries.  I still need to implement support for passing scopes and managed properties, so look for that in an update soon.

You can find the release files at CodePlex.

Corey Roth is a MOSS consultant for Stonebridge.

Back in February when version 1.1 of the Visual Studio Extensions for SharePoint came out, I really complained about the lack of support for Visual Studio 2008 and Windows XP / Vista.  Version 1.2 finally came out so I decided to look and see if operating systems other than Windows Server 2003 are supported and I was surprised to see Windows XP and Windows Vista on the list.  I immediately downloaded it, tried the installer but saw that there was still a requirement to have WSS installed.  Luckily, in the last week or so the guys at Bamboo, posted a utility to allow WSS to be installed on Windows Vista.  I decided to give the utility a try and it worked flawlessly.  I then tried installing the extensions again and everything worked.  The Visual Studio Extensions are nothing all that exciting, but they can be useful from time to time.  I am just glad I was able to get them to install. 

I did notice that Windows Server 2008 was missing from the list so no telling if it will work there or not.

WSS 3.0 Tools, Visual Studio Extensions 1.2