Posts Tagged ‘SharePoint’

Pex and Moles Testing Framework for SharePoint

September 1, 2010

Here is a quickstart for working with unit testing framework for SharePoint. This Framework is called Moles. You can download it here. It is free academic use and Microsoft partners.

So how this Framework works: It allows you to replace any method with by you defined delegate. So here is a simplistic function:

Simple Intro

public static bool IsInFuture(DateTime date)
{
	return date > DateTime.Now;
}

So this function is not easily unit testable, because the DateTime.Now is not a constant value. What we can do with moles is following:

[TestMethod()]
[HostType("Moles")]
public static void IsInFutureTest()
{
      MDateTime.NowGet = () => new DateTime(2010,09,01);
      bool actual = SuperClass.IsInFuture(new DateTime(2010, 09,03));
      Assert.IsTrue(actual);
}

The interesting thing here is the MDateTime construct, that comes from moles and the function replaces the actual method call with by us defined function that returns a constant date.
So here is what we have to do when we want to use the MDateTime construct:

  1. Install Pex and Moles.
  2. Add a new item of type “Moles and Stubs for Testing”  into the unit test project.  This file has to be called mscorlib.moles, because  the DateTime class is located in the mscorlib.dll. When you add this file the moles Framework analyses the dll and create the stubs. These stubs are the classes with the “M” prefix.
  3. Add following attribute [HostType(“Moles”)] to the test method. This tells moles framework to replace the actual methods with custom delegates.
  4. For this type you have to also add following row to the assemblyinfo.cs of the test project [assembly: Microsoft.Moles.Framework.MoledType(typeof(DateTime))]

SharePoint Unit Testing

You can stub in this way all SharePoint objects e.g. SPContext, SPList etc. All you have to do is to add new moles file with the name Microsoft.SharePoint.moles. This has actually one drawback and it is that it is a lot of coding to fullfill all the expectations that you use in the method to be tested. There come behaviors for SharePoint in play. It offers stubs with predefined behaviors against you can unit test your code. In all these cases you  don’t access the physically SharePoint, in extreme there can be no SharePoint installed at all.

So where can you find Behaviors for SharePoint. They are part of the Moles project and you can find it on the machine where moles are installed on the following path \Program Files (x86)\Microsoft Moles\Documentation\behaviors.samples.zip\behaviors\Microsoft.SharePoint.Behaviors. All You have to do is to compile this project and you have an assembly called Microsoft.SharePoint.Behaviors.dll that you can reference in your test projects. Here is a short sample how you can work with SharePoint behaviors:

[TestMethod()]
[HostType("Moles")]
public static void  IsListNameCorrectTest()
{
BSPSite site = new BSPSite();
BSPWeb web = site.SetRootWeb();
BSPList list = web.Lists.SetOne();
list.Title = "TestList";
bool actual = MyClass.IsListNameCorrect(list);
Assert.IsTrue(actual);
}

public static class MyClass
{
public bool IsListNameCorrect(SPList list)
{
return list.Title.Length < 200;
}
}
Advertisements

Changing column type in a list template – upgrade scenario

July 29, 2010

In this article I would like to describe the scenarios that you can come across when changing  the structure of a list.

Changing column type

Consider following scenario: We have a list that should hold information about a person. the person has following fields: first name , last name and birth date. The part of schema.xml file, that defines the columns could look like this:

<pre><Field Type="Text" DisplayName="Firstname" Required="FALSE" ID="{168a8095-32a8-4b25-a4b6-046b3dc3d466}" StaticName="FirstName" Name="FirstName"Version="1" ColName="nvarchar1"/>
<Field Type="Text" DisplayName="LastName" Required="FALSE" ID="{168a8095-32a8-4b25-a4b6-046b3dc3d466}" StaticName="LastName" Name="LastName"Version="1" ColName="nvarchar2"/>
<Field Type="Text" DisplayName="BirthDate" Required="FALSE" ID="{168a8095-32a8-4b25-a4b6-046b3dc3d466}" StaticName="BirthDate" Name="BirthDate"Version="1" ColName="nvarchar3"/>

So far so good. Now we released this list template and the users happily created lists based on this template and filled thousands list items into these list. But there is an error in the xml: the birth date should not be of type text but DateTime. So we modify the schema.xml accordingly:

<Field Type="Text" DisplayName="Firstname" Required="FALSE" ID="{168a8095-32a8-4b25-a4b6-046b3dc3d466}" StaticName="FirstName" Name="FirstName"Version="1" ColName="nvarchar1"/>
<Field Type="Text" DisplayName="LastName" Required="FALSE" ID="{168a8095-32a8-4b25-a4b6-046b3dc3d466}" StaticName="LastName" Name="LastName"Version="1" ColName="nvarchar2"/>
<Field Type="DateTime" DisplayName="BirthDate" Required="FALSE" ID="{168a8095-32a8-4b25-a4b6-046b3dc3d466}" StaticName="BirthDate" Name="BirthDate" Version="1"/>

After the activation of the feature the SharePoint will update all columns in the list instances. However it is very probable that the existing list items will not be editable. In my case I become “Input string not in a correct format”. And if you e.g. convert  a column from DateTime to Text you can receive even a CATASTROPHIC_FAILURE. Cool. So this is not the way how to fix it.

Deleting column

If you want to create a robust scenario for updating columns do not ever change the type of the column, instead mark it as hidden and create a new field e.g. BirthDate2 with the correct data type. Then after the installation and activation of the feature you have to iterate through all the existing list instances of the type and transfer the data programmatically from the old to the new field, wherever possible. If you have a temptation to delete the old column and create a new column with another type and guid, be advised that SharePoint will update the list instances accordingly. This means in our case it would delete all data in the Birthdate column in all these lists. This is really dangerous side effect of updating the lists.

Simple advice

Don’t screw up in the first place, because it could be really time consuming to make it right.

SharePoint Solution Installer support for SP2010

February 28, 2010

I modified the SharePoint Solution Installer and now it supports SharePoint 2010.

I added following config entry into the setup.exe.config

<add key=”SupportedSharePointVersion” value=”2007″/>
If it contains value “2007”  then the solution can be installed only to MOSS 2007 and WSS 3.0

If it contains “2010” the the solution can be installed only to SharePoint 2010 and SharePoint Foundation.

If you leave it empty then no check for specific version of SP is done and you can install it to all above versions.

You can download the modified SSI binaries and source code from here. (It is actually a zip file renamed to jpeg because of WordPress policy.)

Is AllowUnsafeUpdates=true the right way?

February 24, 2010

Have you ever seen the following message?

System.Exception: Microsoft.SharePoint.SPException: The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again. —> System.Runtime.InteropServices.COMException (0×8102006D): The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.

Some programmers say immediately “You have to set AllowUnsafeUpdates on the Web to true and the error will be gone.” Some programmers will add: “And don’t forget to set it back to false when you’re done”.

However this brings some issues:

  • This will enable SharePoint to modify the data even during POST request types. So it can happen, that e.g the search server,  will modify the your SPListItems, while crawling.
  • Additionaly sometimes the AllowUnsafeUpdates is automatically set back to false, e.g. when calling a Parent web.

So how to deal with it?

If you want to enable the modifications only in GET request types (e.g. in OnClick handler), then use SPUtility.ValidateFromDigest(), before you want to modify the data in SharePoint.  This will automatically set AllowUnsafeUpdates to true if the request type is GET.

For more info see following cool posts:

What You Need To Know About AllowUnsafeUpdates

What You Need To Know About AllowUnsafeUpdates part 2

SPSiteDataQuery – useful class for querying multiple lists

December 17, 2009

This will be short.

This class allows you to query multiple lists with one CAML Query. For example you can fulfill folowing scenario with one query: Return all items with a specific contenttype in this sitecollection.

Here is the MSDN documentation from Microsoft.

Here  is an example how to use it

Programmatically enable/disable Scheduling on a SPList

December 9, 2009

SharePoint API does not allow to programmatically modify scheduling on a List. 

So here is the code that does this: 

 

using System; 

using System.Collections.Generic; 

using System.Linq; 

using System.Text; 

using System.Reflection; 

using Microsoft.SharePoint; 

namespace YourNameSpace{ 

/// <summary> 

/// Class for operation that enables operations that are not enabled via standard SharePoint API 

/// </summary> 

public static class PublishingUtilities 

{ 

const string SharePointPublishingAssemblyName = "Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"; 

const string ScheduledItemClassName = "Microsoft.SharePoint.Publishing.ScheduledItem"; 

/// <summary> 

/// Registers Scheduling on a List 

/// </summary> 

/// <param></param> 

public static void EnableSchedulingEventOnList(this SPList list) 

{ 

Assembly assembly = Assembly.Load(SharePointPublishingAssemblyName); 

Type type = assembly.GetType(ScheduledItemClassName); 

MethodInfo dynMethod = type.GetMethod("RegisterSchedulingEventOnList", BindingFlags.NonPublic | BindingFlags.Static); 

dynMethod.Invoke(type, new object[] { list }); 

} 

/// <summary> 

/// Unregisters Scheduling on a List 

/// </summary> 

/// <param></param> 

public static void DisableSchedulingOnList(this SPList list) 

{ 

Assembly assembly = Assembly.Load(SharePointPublishingAssemblyName); 

Type type = assembly.GetType(ScheduledItemClassName); 

MethodInfo dynMethod = type.GetMethod("DisableSchedulingOnList", BindingFlags.NonPublic | BindingFlags.Static); 

dynMethod.Invoke(type, new object[] { list }); 

} 

/// <summary> 

/// Gets scheduling state on the List 

/// </summary> 

/// <param></param> 

public static bool GetIsSchedulingEventRegisteredOnList(this SPList list) 

{ 

Assembly assembly = Assembly.Load(SharePointPublishingAssemblyName); 

Type type = assembly.GetType(ScheduledItemClassName); 

MethodInfo dynMethod = type.GetMethod("GetIsSchedulingEventRegisteredOnList", BindingFlags.NonPublic | BindingFlags.Static); 

bool? result = dynMethod.Invoke(type, new object[] { list }) as bool?; 

if (result != null) 

return result.Value; 

else 

throw new ArgumentException("Call of the function GetIsSchedulingEventRegisteredOnList failed"); 

} 

} 

} 

Enable AJAX history in SharePoint Webpart pages

July 17, 2009

The problem:
You want to enable the back button in browser for the actions that are done through Ajax calls. It is pretty simple in a normal .NET 3.5 aspx web app. You can find the quidance here.

However this guidance did not work for me in a SharePoint webpart page. The history points in the back button browser history worked fine, the problem occured when I actually clicked the back button. The page changed back to the previous page  and then came back to the original page. After some fiddling I found out that this is because the __eventtarget parameter in the history page request is wrong. The parameter was set on the button and not on the scriptmanager as it should be. Therefore the button event click was fired when the history page wass loaded and then the original page was loaded again

The solution:
Create a new custom web part page. See Ted Pattison guide how to create a custom web part page. When done modify it and add a ScriptManager directly into the aspx code of the web part page. From now the browser history should work correctly.

Note:
When I used the Publishing page I did not come across this problem. Why? Did not have time to find out. 🙂

Note2:
This feels rather like a workaround, if anybody ever reads this blog and has a better solution please let me know.

RunWithElevatedPrivileges behavior in different hosts

July 3, 2009
  Normal code RunWithElevatedPrivileges
w3wp.exe account of the currently loggedin user to sharepoint account under which runs the “sharepoint web application” application pool
owstimer.exe account under which runs the owstimer.exe service default it is NETWORK SERVICE account under which runs the owstimer.exe service default it is NETWORK SERVICE

As you can see runwithelevatedprivileges in owstimer.exe has no effect.

Custom membership provider:

Under which account runs the request when you use custom membership provider and there is no windows account associated with the user logged in to sharepoint? From my observations it is “Internet Guest Account”.

owstimer must be restarted after solution deployment

July 2, 2009

True….

SendEmail activity does not work from custom SequenceActivities

May 18, 2009

The SendEmail activity works only when it has assigned the correlation token of the current workflow. When you add a SendEmail activityto a custom created sequence activity, it does not have access to the the parent workflow token and when you try assign a  different correlation token it throws following exception:
Correlation value has not been initialized on declaration [token]  for activity [sequenceActivity]
The workaround is simple just use the SPUtility.SendEmail wrapped in a CodeActivity.
Another solution is to create your own activity that would wrap the SPUtility.SendEmail.