| Subcribe via RSS

Create/Delete site collection with PowerShell

Februar 6th, 2010 | No Comments | Posted in Uncategorized

Today I played some minutes around with Powershell for SharePoint 2010 and easily created a new site collection and also deleted it.

Create new site collection:

New-SPSite  -url http://mymachine/sites/powershell -template STS#0  -OwnerAlias “mydomain\alexander.bruett“  -Name “Powershell Testsite”

Delete site collection:

Remove-SPSite -Identity http://hbv83025270/sites/powershell -Confirm:$False

If I were an IT-Pro, I’d love this :-)

Tags: , ,

Ribbon Hero rocks

Januar 28th, 2010 | No Comments | Posted in Office

Yesterday I stumbled about Ribbon Hero, a new addon from Microsoft Labs for Office 2007 and 2010. The idea is learning by playing and gaining achievments for using special features within Word, PowerPoint or Excel. The most funny part is the connection to facebook that lets you compare your score with your friends.

http://www.officelabs.com/ribbonhero

It’s not just funny, it’s also useful. The Ribbon Hero shows you very cool functions you haven’t used yet. Check it out, it’s fun. If you work in a company with lots of Office noobs, it’s a great way to educate them.

Good luck becoming a Ribbon hero :-)

If you want to compare your score to mine, invite me on facebook.

Tags:

SharePoint 2010 and Visual Studio 2010 Beta 2 target Framework problems

Januar 21st, 2010 | No Comments | Posted in Uncategorized

Today, I tried to add a reference to the assembly Microsoft.Office.Server.Search.dll and got this warning:

The primary reference "Microsoft.Office.Server.Search, Version=14.0.0.0,
Culture=neutral, PublicKeyToken=71e9bce111e9429c,
processorArchitecture=MSIL" could not be resolved because it has an
indirect dependency on the framework assembly
"System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35" which could not be resolved in the
currently targeted framework. ".NETFramework,Version=v3.5". To resolve
this problem, either remove the reference
"Microsoft.Office.Server.Search,Version=14.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL" or
retarget your application to a framework version which contains
"System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35

Solution:

Create a .reg file and add this lines:

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\
v2.0.50727\AssemblyFoldersEx\Chart Controls]
@="C:\\Program Files (x86)\\Microsoft Chart Controls\\Assemblies"

Run this file and the entry will be added to the registry. Restart Visual Studio and the warning will be gone.

Tags: , , , ,

SharePoint List vs. Database and Excel

Oktober 30th, 2009 | No Comments | Posted in SharePoint

Yesterday I had a discussion with my colleague about SharePoint lists. Some people use SharePoint to store documents and manage tasks. List data is often stored in Excel files within SharePoint like phone numbers or birthday lists.

We asked us: What would be the best place to store about five linked lists with a few hundred items. We didn’t come up with a final decision because of personal opinions so I tried to find some facts I can make my decision on.

SharePoint List Benefits

When you create a SharePoint List you get a couple of features a Database for example does not deliver:

  • User interface that allows you to edit, filter, sort, group the data
  • Ability to search
  • Security management on list level and item level
  • Integration with other lists and libraries
  • Recycle bin
  • Multiple users can edit data simultaneously
  • Rich text support
  • SharePoint alerts
  • RSS
  • Select data from other systems using BDC lookup columns

SharePoint List Limitations

Electronical processing of data

Automatic processing and modifying data within SharePoint lists using Event Receiver, Workflows oder Web Services is much more difficult and slower that using Excel or Databases.

Accessing the data from an external system

SharePoint lists cannot be accessed from systems outside of SharePoint very easily. You will have to fight security and the web services of SharePoint. If this is the case a dedicated database might be the best option even if you have to create a user interface for the data management. With SharePoint 2010 it looks like this will become veery easy without coding.

Complex relations between tables

Relations between SharePoint lists is something I try to avoid if there is some potential that things might grow.

Conclusion

I still am not sure where to store 5 linked lists with a few hundred items. But I do see lots of reasons to use SharePoint lists.

I will add more facts while the discussion goes on. If you have any suggestions, feel free to add your comments.

SharePoint Performance Checklist

September 7th, 2009 | No Comments | Posted in SharePoint

I’ve made lots of performance tunings during the last weeks and figured out that this can be a weird, long and complex task. On the one hand there are many built-in mechanism that can be configured and on the other hand there are lots of things you shound pay attention to when you develop your own web parts.

I’ve assmebled a little checklist you can walk through. I do not cover everything in detail but I’ve linked a couple of online posts and articles where you can start reading if you need more information on specific tasks.

checkbox

Limit global Navigation & Permission breaks

If you have a collaboration site collection with individual permissions on each website or at list level then your navigation controls can slow down your sharepoint performance. SharePoint has to check your permissions for each item listed in the navigation controls what can be very time consuming. Because the global navigation is placed on every web site this impacts your whole site collection.

So if you have lots of permission breaks either limit the items displayed by the navigation controls and eleminate the default navigation treeview or implement your custom navigation provider using caching mechanisms and activate object caching.

checkbox

Activate Blob Cache

The blob cache can be used to reduce the round trips between the WFE and the database server. If activated, all images stored within the site collection are cached on the hard disk of the WFE server. The blob cache can only be configured within the web.config of each web application.

Another big point of the blob cache ist the max-age attribute. It tells the browser not to request that image again for a given period of time. So you can use this attribute to reduce the requests between the browser and the WFE.

In the web.config file search for the <BlobCache …> section and set it to the following example:

<BlobCache location="C:\blobCache" path="\.(gif|jpg|png|css|js)$" maxSize="10" max-age="86400" enabled="true"/>

Now the cache is enabled and the files with the defined extensions are stored on WFE hard disk and the browser will not rerequest them for about 24 hours.

Selvagan posted a great article about the blob cache.

Tip: Store the cached files on a different hard disk as the web server to maximize the I/O throughput.

If you want to clear the blob cache on all WFE servers at once you need this codeplex solution.

checkbox

Activate Output Cache

Output caching enables SharePoint to cache HTML markup of Web Parts or complete web pages. This makes sense most if you have a publishing page with anonymous access enabled. If you enable output caching on a site with authenticated users the output is cached for each user individually. This can become a memory issue.

Read more in the output caching secion of this MSDN article.

checkbox

Activate Object Cache

SharePoint can cache objects like navigation elements and Cross-list query results. This should be activated on every SharePoint site. Microsoft has posted an article on how to activate and configure the object cache.

checkbox

Indexing of columns

If you have large list views that are ordered or filtered you should place an index on those list columns where you set the filter on. An index can also increase the performance if you have a lookup field with many items in the lookup list.

Have a look at this Microsoft article on managing lists and libraries with many items and read the Microsoft White Paper: Working with large lists in Office SharePoint Server 2007.

Andreas Grabner wrote an article on how list column indexing works under the hood.

checkbox

Be careful using the Content Query Web Part

If you use the Content Query Web Part to collect data from large lists or from your whole site collection you have to be knowing what’s happening in detail. You can increase CQWP performance using object cache and implementing your own CQWP. Ranjan Banerji wrote a great article on content query web part performance.

checkbox

Use Warmup Timer Job

If you restart your server for maintenance or reset your IIS during a solution deployment all your web applications are shut down. Now, when the first user requests your website it takes up to a couple of minutes until the web application is reloaded and caches are filled. It would be nice if theres someone who takes a browser and calls every website before the first user does.

Joel Oleson wrote a post about a script that acts like that “someone” and triggers all websites of your site.

Andrew Connell write a post on how to implement the script as a timer job. You can download the timer job from msdn.

checkbox

Watch your crawler

A misconfigured crawler can push your server cpu usage to 100%  from dusk till dawn. This can happen very quickly if you have an intranet website with lots of members creating new content and uploading tons of documents. Then the crawl duration is growing very quickly.

For example if you scheduled your crawler to run every 30 minutes and the crawl duration is longer than 30 minutes your server is crawling all the day. So you should check the crawl log periodically. If your crawl duration becomes too long you have to reconfigure your crawl schedule and crawl your content only once every two hours. If your search index may not be out of date for more than 30 minuts you have to add more search server to the farm.

Patrick Thisseghem wrote a great book about the SharePoint search and indexing engine: Inside the Index and Search Engines: Microsoft Office SharePoint Server 2007

checkbox

Use tools to measure site request performance

Use tools like Fiddler, YSlow and Firebug to find out whats going on between the browser and your SharePoint server.  Find out if there are long waiting times, too many server requests or ineffective java scripts slowing down your website. Use these tools to check if blob caching works.

SharePoint works best if used with Microsoft Internet Explorer but I love the Firefox plugins YSlow and Firebug because they are very easy to use, detailed and give lots of hints if your performance is bad.

checkbox

Measure your Web Part performance

Every custom web part can slow down your SharePoint website. The SharePoint API often performes not as expected and this can impact your Web Part performance. Use the Stopwatch class in your web part to measure critical code parts and write the results into the web part. Implement a Web Part property to switch on/off the stopwatch results.

There are developers out there saying perfomance measures should be part of productive code and rather be made using unit tests or console applications. Those developers are basically right but might have never been to the wild west of SharePoint. A Web Part lives within a SharePoint site and no unit test or console application can simulate that so you have to use your productive web part to make performance tests.

Tags: , , , , ,

What to do if SharePoint throws “500 Internal Server Error”?

Mai 28th, 2009 | No Comments | Posted in SharePoint

Yesterday we added a new server to the SharePoint farm. When calling a site over that new server we got an 500 Internal Server Error. There was no entry in the EventLog and even no information in the server log files. We wer trying lots of things but nothing got better. So what could we do to get more information?

We changed the diagnostics logging level from Unexpected to Verbose:

Diagnostics Logging Level

(Central Administration > Operations > Diagnistic Logging)

Then we recalled the website and finally got an error in the log files:

"Cannot make a cache safe URL for "init.js", file not found.
Please verify that the file exists under the layouts directory."

The file is part of every language pack so in our case we did not install a language pack on the new server that is used by the site.

Although this is a simple option to get more error information it’s forgotten or overseen very often.

Alex
Tags: , , ,

SharePoint Groups vs. Active Directory Groups

Mai 19th, 2009 | 3 Comments | Posted in SharePoint

I’ve discussed this topic quite often during the last months. After those discussions I figured out that its more a question when to use what kind of group rather than what kind is better than the other. In this post I just write down some advantages and disadvantages of the group types and let you choose what kind fits better for your needs.

SharePoint Group Active Directory Group
plus Members of this group can be added/removed from within SharePoint. The permission to add or remove users from the group can be delegated to SharePoint users. plus Members of this group can be managed within Active Directory. Only Active Directory administrators have the permission to modify group memberships.
plus Members of this group can be visible to users. minus Members of this group are not visible to users.
minus Cannot contain another SharePoint group as member. plus Can contain another Active Directory Group.
plus Must have a unique name on site collection level. The name is the unique identifier of the group. minus Can cause serious problems in lage scale scenarios: A user might only be a member of 1024 Active Directory groups (recoursively). If this number is reached the user is no longer able to log on to Windows.
Read the Microsoft documentation for more information.
plus Can contain SharePoint users that do not exist in the Active Directory.
Tags: , , ,

Create SPFieldLookup programatically

Februar 21st, 2009 | 3 Comments | Posted in .NET, SharePoint

There aren’t many posts describing how to add a SPFieldLookup column to a list programatically. Here’s how I do it:

I have a list named “MyList” and I have a list named “MyLookupList”. I want to create a lookup column within “MyList” looking up values from “MyLookupList”.

SPList myList = web.Lists["MyList"];
SPList myLookupList = web.Lists["MyLookupList"];
 
myList.Fields.AddLookup("Lookup", myLookupList.ID, false);
SPFieldLookup fieldLookup = myList.Fields["Lookup"] as SPFieldLookup;
// Display Title Column in lookup field 
// (this is shown by default but this way you can change it)
fieldLookup.LookupField = 
  myLookupList.Fields[SPBuiltInFieldId.Title].InternalName;
fieldLookup.Update();
Tags:

Low budget SharePoint Services 3.0 Development Environment

Februar 9th, 2009 | No Comments | Posted in Uncategorized

I tried to set up a development environment for SharePoint programming at home on my machine and found out that this isn’t a trivial task if you don’t want to use evaluation software and do not want to invest more than 1000 $.

The big cost factors are operating system and devlopment environment:

  • Windows Web Server 2008
  • Visual Studio 2008 Standard
First I evaluated Windows Home Server but this edition would format all drives during setup. Not a good choice if you want to use multiple Windows Systems on the same machine.
I’m not sure if it’s possible to build SharePoint extensions with Visual Studio Express. As long as many Visual Studio extensions do not work with VS Express I’d prefer Visual Studio Standard (or higher).

All else needed for SharePoint Services development is available for free:
  • SharePoint Service 3.0
  • Visual Studio Extensions for SharePoint Services 1.2 or 1.3
  • Tools

Simplify reading and writing field values of type SPFieldUser, SPFieldUrl and SPFieldLookup using extension methods

Februar 8th, 2009 | 9 Comments | Posted in .NET, SharePoint

To read or write values to fields of type SPFieldUser or SPFielLookup is an annoying task because you have to create field value objects bevore you can write your values into a field. The following post descripes how you can encapsulate those tasks to extension methods and slim your code to make it more readable.

SPFieldUser

The following code displays a couple of extension methods extending the SPListItem class for simple reading and writing access to fields of type SPFieldUser.

using System;
using System.Collections.Generic;
using Microsoft.SharePoint;
 
namespace ExtensionMethods
{
    public static class SPListItemExtensions
    {
        /// <summary>
        /// Returns the login name of an User-Field.
        /// </summary>
        public static string GetFieldValueUserLogin(this SPListItem item, 
          string fieldName)
        {
            if (item != null)
            {
                SPFieldUserValue userValue = 
                  new SPFieldUserValue(
                    item.Web, item[fieldName] as string);
                return userValue.User.LoginName;
            }
            else
            {
                return string.Empty;
            }
        }
 
        /// <summary>
        /// Sets the value of a User-Field to a login name.
        /// </summary>
        public static void SetFieldValueUser(this SPListItem item, 
          string fieldName, string loginName)
        {
            if (item != null)
            {
                item[fieldName] = item.Web.EnsureUser(loginName);
            }
        }
 
        /// <summary>
        /// Sets the value of a User-Field to an SPPrincipal 
        /// (SPGroup or SPUser).
        /// </summary>
        public static void SetFieldValueUser(this SPListItem item, 
          string fieldName, SPPrincipal principal)
        {
            if (item != null)
            {
                item[fieldName] = principal;
            }
        }
 
        public static void SetFieldValueUser(this SPListItem item, 
          string fieldName, IEnumerable<SPPrincipal> principals)
        {
            if (item != null)
            {
                SPFieldUserValueCollection fieldValues = 
                  new SPFieldUserValueCollection();
 
                foreach (SPPrincipal principal in principals)
                {
                    fieldValues.Add(
                      new SPFieldUserValue(
                        item.Web, principal.ID, principal.Name));
                }
                item[fieldName] = fieldValues;
            }
        }
 
        /// <summary>
        /// Sets the value of a multivalue User-Field to 
        /// a list of user names.
        /// </summary>
        public static void SetFieldValueUser(this SPListItem item, 
          string fieldName, IEnumerable<string> loginNames)
        {
            if (item != null)
            {
                SPFieldUserValueCollection fieldValues = 
                  new SPFieldUserValueCollection();
 
                foreach (string loginName in loginNames)
                {
                    SPUser user = item.Web.EnsureUser(loginName);
                    fieldValues.Add(
                      new SPFieldUserValue(
                        item.Web, user.ID, user.Name));
                }
 
                item[fieldName] = fieldValues;
            }
        }
    }
}

The following lines of code demonstrate how these extension methods can be used.

using ExtensionMethods;
 
SPList list = web.Lists["MyList"];
SPListItem item = list.Items[0];
 
// Get a user login of a SPFieldUser field
string userLogin = item.GetFieldValueUserLogin("Author");
 
// Set a SPFieldUser field to a user using the login
item.SetFieldValueUser("Person", "alexander.bruett");
 
// Set a SPFieldUser field that allows multiple values to a list of users
string[] persons = { "alexander.bruett", "paul.panzer" };
item.SetFieldValueUser("Mehrere Personen", persons);
 
// Set a SPFieldUser field to a SPUser
SPUser user = web.Users[1];
item.SetFieldValueUser("Person", user);
 
// Set a SPFieldUser field to a list of SPPrincipal
SPGroup group = web.Groups[0];
SPUser user = web.Users[0];
SPUser user2 = web.EnsureUser("alexander.bruett");
SPUser user3 = web.EnsureUser("Domain Users"); ;
SPPrincipal[] principals = { group, user, user2, user3 };
item.SetFieldValueUser("AssignedTo", principals);

Especially setting fields that allow multiple values now needs only a couple of code lines.

SPFieldLookup

The SPFieldLookup field is a little bit more complicated if you want to set the field only by the lookup string. You have to query the ID of the lookup value before you can set the field value. The following extension methods simplify this task.

/// <summary>
/// Returns the value of a Lookup Field.
/// </summary>
private static string GetFieldValueLookup(this SPListItem item, 
    string fieldName)
{
    if (item != null)
    {
        SPFieldLookupValue lookupValue = 
            new SPFieldLookupValue(item[fieldName] as string);
        return lookupValue.LookupValue;
    }
    else
    {
        return string.Empty;
    }
}
 
/// <summary>
/// Returns the value of a Lookup-Field with multiple values.
/// </summary>
public static IEnumerable<string> GetFieldValueLookupCollection(
    this SPListItem item, string fieldName)
{
    List<string> result = new List<string>();
    if (item != null)
    {
        SPFieldLookupValueCollection values = 
            item[fieldName] as SPFieldLookupValueCollection;
 
        foreach (SPFieldLookupValue value in values)
        {
            result.Add(value.LookupValue);
        }
    }
    return result;
}
 
/// <summary>
/// Returns the SPFieldLookupValue instance of a lookup value. 
/// The ID value will be obtained using SPQuery.
/// </summary>
private static SPFieldLookupValue GetLookupValue(
    SPWeb web, SPFieldLookup field, string lookupValue)
{
    string queryFormat = 
        @"<Where>
            <Eq>
                <FieldRef Name='{0}' />
                <Value Type='Text'>{1}</Value>
            </Eq>
          </Where>";
 
    string queryText = 
        string.Format(queryFormat, field.LookupField, lookupValue);
    SPList lookupList = web.Lists[new Guid(field.LookupList)];
 
    SPListItemCollection lookupItems = 
        lookupList.GetItems(new SPQuery() { Query = queryText });
 
    if (lookupItems.Count > 0)
    {
        int lookupId = 
            Convert.ToInt32(lookupItems[0][SPBuiltInFieldId.ID]);
 
        return new SPFieldLookupValue(lookupId, lookupValue);
    }
    else
    {
        return null;
    }
}
 
/// <summary>
/// Sets the value of a Lookup-Field.
/// </summary>
public static void SetFieldValueLookup(
    this SPListItem item, string fieldName, string lookupValue)
{
    if (item != null)
    {
        SPFieldLookup field = 
            item.Fields.GetField(fieldName) as SPFieldLookup;
        item[fieldName] = GetLookupValue(item.Web, field, lookupValue);
    }
    else
    {
        item[fieldName] = null;
    }
}
 
/// <summary>
/// Set the values of a Lookup-Field with multiple values allowed.
/// </summary>
public static void SetFieldValueLookup(this SPListItem item, 
    string fieldName, IEnumerable<string> lookupValues)
{
    if (item != null)
    {
        SPFieldLookup field = 
            item.Fields.GetField(fieldName) as SPFieldLookup;
 
        SPFieldLookupValueCollection fieldValues = 
            new SPFieldLookupValueCollection();
 
        foreach (string lookupValue in lookupValues)
        {
            fieldValues.Add(
                GetLookupValue(item.Web, field, lookupValue));
        }
        item[fieldName] = fieldValues;
    }
}

That’s been a lot of code but take a look at the following lines of code. Especially the setting task becomes very easy now.

// Reads the value of a SPFieldLookup field
string value = item.GetFieldValueLookup("LookupFieldName");
 
// Read lookup values of a SPFieldLookup field 
// with multiple values allowed
IEnumerable<string> values = 
  item.GetFieldValueLookupCollection("MultiLookupFieldName");
 
// Set the value of a SPFieldLookup field
item.SetFieldValueLookup("LookupFieldName", "LookupValue");
 
//Set the value of a SPFieldLookup field with multiple values allowed
string[] values = {"Hamburg", "London" };
item.SetFieldValueLookup("MultiLookupFieldName", values);

SPFieldUrl

Setting and getting SPFieldUrl field values is very simple:

/// <summary>
/// Returns the value of an Url-Field.
/// </summary>
public static string GetFieldValueUrl(
    this SPListItem item, string fieldName)
{
    if (item != null)
    {
        SPFieldUrlValue urlValue = 
            new SPFieldUrlValue(item[fieldName] as string);
        return urlValue.Url;
    }
    else
    {
        return string.Empty;
    }
}
 
/// <summary>
/// Sets the value of an URL-Field.
/// </summary>
public static void SetFieldValueUrl(this SPListItem item, 
    string fieldName, string url, string description)
{
    if (item != null)
    {
        item[fieldName] = 
            new SPFieldUrlValue() 
                { 
                    Description = description, 
                    Url = url 
                };
    }
}

The following lines of code show how to get and set values of the SPFieldUrl field using the extension methods above:

// Get the url of a SPFieldUrl field
string url = item.GetFieldValueUrl("URL");
 
// Set the url and description of a SPFieldUrl field
item.SetFieldValueUrl("URL", "http://www.alexbruett.net", "Alex' Blog");

Conclusion

Using extension methods to simplify the access to complex and SharePoint list fields makes your code more readable and reduces the lines of code.

You could also use helper classes instead of extension methods but you will have to write more code to call a helper method instead of calling a extension method.

Tags: , , , , , , ,