Wednesday, October 6, 2010

SharePoint 2010 Client Object Model: "(400) Bad Request" error

If you use Microsoft.SharePoint.Client.FileCollection.Add or Microsoft.SharePoint.Client.File.SaveBinary
method to create (or change) file in SharePoint 2010, you can get "The remote server returned an error: (400) Bad Request" error.

To resolve this issue you need to change default Maximum Message Size for WCF calls:

open SharePoint 2010 Management Shell
type:
$ws = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$ws.ClientRequestServiceSettings.MaxReceivedMessageSize = your_value
$ws.Update()

I recommend to set MaxReceivedMessageSize to Int32.MaxValue - 1 (2147483646).

Sometimes you may need to run "iisreset /noforce" to enforce changes applying.

Also you can use Microsoft.SharePoint.Client.File.SaveBinaryDirect approach that does not have this limitation.

Tuesday, September 7, 2010

How to add new aspx pages to SharePoint programmatically

There are two different solutions to create new aspx pages in SharePoint.

First one is using of SharePoint Services RPC Methods:
1. Create query in XML format to call NewWebPage method:
<?xml version="1.0" encoding="UTF-8"?>
<Batch>
<Method>
<SetList Scope="Request">DocLib_ID</SetList>
<SetVar Name="ID">New</SetVar>
<SetVar Name="Cmd">NewWebPage</SetVar>
<SetVar Name="Type">BasicPage|WebPartPage</SetVar>
<SetVar Name="WebPartPageTemplate">LayoutID</SetVar>
<SetVar Name="Title">AspxTitle</SetVar>
<SetVar Name="Overwrite">true</SetVar>
</Method>
</Batch>

Where:
  • DocLib_ID is ID (GUID) of document library where do you need to create new aspx file.
  • BasicPage|WebPartPage type of aspx. Use BasicPage for page without layout (LayoutID =0) and WebPartPage for all other terms
  • LayoutID specifies page layout [1...8]
2. Call SPWeb.ProcessBatchData method with this query.
3. If you need to create aspx file in document library subfolder, create it in doclib and move to the necessary subfolder with SPFile.MoveTo method.

But this approach doesn't work for meeting workspace where you can create several pages with access via convenient multi-page web part.
To create new pages there you need to use SPMeeting.AddPage (AspxTitle, InstanceID, out resNewPageUrl) method. Set InstanceID = 0 to create page directly in the Workspace Pages library.

Friday, August 20, 2010

Django cache (storage)

If you need to store something useful between client requests, you can use Django cache framework.

It allows you to use memory, file, database or custom storage type.

Its using is very simple:

Add CACHE_BACKEND = 'locmem://' in settings to use memory cache

Import cache: "from django.core.cache import cache" in .py file.
Get value: cache.get('stored_data'). It returns None if there is no 'stored_data'.
Set value: cache.set('stored_data', my_data, 60). '60' is optional - timeout of cache expiration.
Delete value: cache.delete('stored_data')

Thursday, June 24, 2010

WikiEditPage.InsertWebPartIntoWikiPage - does it have a bug?


SharePoint 2010 has new interesting feature "Team Site Wiki". It's enabled by default for each team site and replace original site home page (default.aspx) with sitepages/home.aspx. This new page is Wiki and can be edited very simply: you can just type any text there, insert image (without Image WebPart) and etc. Web Parts can be used also.

How to edit this wiki page programmatically?

First of all you need to open this aspx file:
SPFile wikiFile = web.GetFile(wikiUrl);

After that you can get access to its Item and LimitedWebPartManager.

Wiki page body is stored in wikiFile.Item["WikiField"] field.
Empty wiki page contains something like this
<div class="ExternalClassB93FFFFBB50E42E5B5D1BE5F906438A1">
<table id="layoutsTable" style="width:100%">
<tbody>
 <tr style="vertical-align:top">
  <td style="width:100%">
  <div class="ms-rte-layoutszone-outer" style="width:100%">
  <div class="ms-rte-layoutszone-inner"></div>
  </div>
  </td>
 </tr>
</tbody>
</table>
<span id="layoutsData" style="display:none">false,false,1</span>
</div>


So to add some text message to wiki page you need just to insert your text in HTML format:
<p> Welcome to our WIKI</p>

in div with ms-rte-layoutszone-inner class:
<div class="ms-rte-layoutszone-inner"><<p> Welcome to our WIKI</p>/div>

Ok. But how to add new Web Part to this page. SharePoint 2010 Object Model suggests to use WikiEditPage.InsertWebPartIntoWikiPage method for this purpose.
But looks like it works incorrect: Position parameter is processed by the wrong way and you get non-working page after update.

Reflected source code:

public static void InsertWebPartIntoWikiPage(SPFile wikiFile, WebPart webpart, int position)
{
if (wikiFile == null)
{
throw new ArgumentNullException("wikiFile");
}
if (webpart == null)
{
throw new ArgumentNullException("webpart");
}
string str = (string) wikiFile.Item["WikiField"];
if (position < 0)
{
throw new ArgumentOutOfRangeException("position");
}
if ((str != null) && (position > str.Length))
{
throw new ArgumentOutOfRangeException("position");
}
SPLimitedWebPartManager limitedWebPartManager = wikiFile.GetLimitedWebPartManager(PersonalizationScope.Shared);
Guid storageKey = Guid.NewGuid();
string str2 = Utility.StorageKeyToID(storageKey);
webpart.ID = str2;
limitedWebPartManager.AddWebPart(webpart, "wpz", 0);
string str3 = string.Format(CultureInfo.InvariantCulture, "<div class=\"ms-rtestate-read ms-rte-wpbox\" contentEditable=\"false\"><div class=\"ms-rtestate-read {0}\" id=\"div_{0}\"></div><div style='display:none' id=\"vid_{0}\"></div>
</div>", new object[] { storageKey.ToString("D") });
if (str == null)
{
str = str3;
}
else
{
str = str.Insert(position, str3);
}
wikiFile.Item["WikiField"] = str;
wikiFile.Item.Update();
}
Insert call corrupts original WikiField value because, for instance, if your position =2, you get failed HTML. Even your position=0 and Wiki page looks nice - you cannot edit it.
So I don't recommend to use InsertWebPartIntoWikiPage in your work.

You can write own implementation which insert new str3 (check source code above) in the correct place: in div with ms-rte-layoutszone-inner class.

Note: Microsoft.SharePoint.WebPartPages.Utility.StorageKeyToID is internal, but you can replace it with own implementation also:
string StorageKeyToID(Guid storageKey)
{
if (!(Guid.Empty == storageKey))
{
return ("g_" + storageKey.ToString().Replace('-', '_'));
}
return string.Empty;
}

Addition: to have ability web part drag&drop you need to insert <p> </p> before and after your web part HTML node

Friday, June 18, 2010

SharePoint 2010 Client Object Model, get folder Item

Task: you need to apply permissions to the existing folder in the document library. But it can be done only for ListItem which corresponds to this folder. How to get this ListItem?

Resolution: In SharePoint Object model you can use SPFolder.Item property. But SCOM Folder doesn't have such prop. You need to use CAML query to get this item:


m_rootTrgUrl = web URL
mm_trgParentWebId = web ID
m_trgListId = existing list ID
srvRelativeURL = folder server-relative URL


using (var clientContext = new ClientContext(m_rootTrgUrl))
{
var trgWeb = clientContext.Site.OpenWebById(m_trgParentWebId);
var trgList = trgWeb.Lists.GetById(m_trgListId);
var query = new CamlQuery();
query.ViewXml = "<View Scope=\"RecursiveAll\"> " +
"<Query>" +
"<Where>" +
"<And>" +
"<Eq>" +
"<FieldRef Name=\"FSObjType\" />" +
"<Value Type=\"Integer\">1</Value>" +
"</Eq>" +
"<Eq>" +
"<FieldRef Name=\"Title\"/>" +
"<Value Type=\"Text\">" + folderName + "</Value>" +
"</Eq>" +
"</And>" +
"</Where>" +
"</Query>" +
"</View>";

query.FolderServerRelativeUrl = srvRelativeURL;

var folderItems = trgList.GetItems(query);

clientContext.Load(trgList);
clientContext.Load(folderItems);
clientContext.ExecuteQuery();

switch (folderItems.Count)
{
// process query result
}
}

Thursday, June 17, 2010

SharePoint 2010 Client Object Model, attachment creation

Unfortunately SCOM doesn't support attachment creation. It doesn't have any API which allows to create attachments if item has no attachment already.

Microsoft recommends to use Lists.asmx SharePoint web service if you need to create attachment remotely. Or create own WCF service in the SharePoint context.

If item already has attachments (at least one) you can add new attachments with using next approach:

using Microsoft.SharePoint.Client;
using SP = Microsoft.SharePoint.Client;
using System.IO;

public static void AddListItemAttachment(string attachFilePath, string listUrl, string itemId)
{
ClientContext clientContext = new ClientContext(listUrl);
Uri url = new Uri(listUrl);

using (FileStream strm = new FileInfo(attachFilePath).Open(FileMode.Open))
{
var attachUrl = url.AbsolutePath + "/Attachments/" + itemId + "/" + Path.GetFileName(attachFilePath);
SP.File.SaveBinaryDirect(clientContext, attachUrl, strm, true);
}
}

This method is based on the knowledge that SharePoint stores item attachments in the special folder with path: ListURL+"/Attachments/" + itemID.
But I didn't find a way to create this folder if it doesn't exist so this method works only if folder exists already (it means that item has at least 1 attachment already). Usual way for folder creation by SCOM doesn't work in this case(with error "Unable to complete action").

SharePoint Web Parts don't work with "Incorrect properties format" error

Issue: Sometimes, when you open SharePoint 2007 site, you see that all web parts show

"Web Part Error: One of the properties of the Web Part has an incorrect format. Windows SharePoint Services cannot deserialize the Web Part. Check the format of the properties and try again."

Furthermore, sometimes this site and its web part work correctly: you see all web part working. This behavior doesn't dependent from browser version or host. You're just clicking "Refresh" and see different results: web parts work or don't work.

Possible reason: If you have more than 1 SharePoint front-end on the target farm, check, please, how do they work. If some of front-ends have problem with free disk space, you can observe problems with web part functionality. Eventlog on this front-end contains errors with ASP .NET 2.0 problems during the page generation.

During the "Refresh" in browser you can get results from different front-ends, it depends from your SharePoint load-balancing infrastructure. So you can see correct pages from "good" front-end and bad pages from "unhealthy" SharePoint front-end.

Issue is absent after disk cleanup on the "unhealthy" SharePoint front-end.

Thursday, April 22, 2010

Introduction to querying lists with REST and ListData.svc in SharePoint 2010

http://www.dotnetmafia.com/blogs/dotnettipoftheday/archive/2010/01/21/introduction-to-querying-lists-with-rest-and-listdata-svc-in-sharepoint-2010.aspx

When you are getting started, the first thing you want to do is check and see if you have ListData.svc up and running. Like any SharePoint web service, it’s located in the _vti_bin folder of any existing site, so it will work with items relative to that site. Here is what a typical URL might look like.
http:///_vti_bin/ListData.svc

To get the data for this list via REST we simply just add the list name to the URL. In my case the name of the list is called Tasks. Here is what the URL would look like.
http:///_vti_bin/ListData.svc/

you just want to know the status for a specific task (note that the site column is actually called StatusValue here), you can simply add it to the URL like this.
http:///_vti_bin/ListData.svc/()/()
In my case:
http://sp2010/_vti_bin/ListData.svc/Tasks(3)/StatusValue


You need to install ADO.NET Data Services v1.5 CTP2 on SharePoint front-end to get it working.

Friday, April 9, 2010

SharePoint 2010 Client Object Model

Now you can work with SharePoint remotely. Client code communicates to the server through Client OM which uses Client.svc WCF service to communicate with SharePoint Server. Client.svc service uses Server OM as per client request and returns the result to the client in JSON format.

Thursday, April 8, 2010

Built-in SharePoint constants

http://blog.hompus.nl/2010/02/05/prevent-hardcoded-sharepoint-ids-in-your-code

The SPBuiltInFieldId class contains 314 GUID’s for the default SharePoint fields.
The SPBuiltInContentTypeId class contains 34 content type ID’s for the default SharePoint content types.
The FeatureIds class contains 16 GUID’s for the MOSS publishing features
The FieldId class contains 61 GUID’s for the publishing fields.
The ContentTypeId class contains 10 content type ID’s for the publishing content types.
The PropertyConstants class contains 42 names of the standard user profile properties

The WssFeatureIds class however is public and the only place the 24 WSS feature id’s are available.

Because this class is not documented I list all fields:

AnnouncementsList
BasicWebParts
ContactsList
CustomList
DataConnectionLibrary
DataSourceLibrary
DiscussionsList
DocumentLibrary
EventsList
GanttTasksList
GlobalContentTypes
GlobalFields
GlobalMobilityRedirect
GridList
IssuesList
LinksList
NoCodeWorkflowLibrary
PictureLibrary
SurveysList
TasksList
TeamCollaboration
WebPageLibrary
WorkflowHistoryList
XmlFormLibrary

Wednesday, April 7, 2010

Django sessions and forms in IE


Django framework allows to store user data in the current browser session.

Each HttpRequest request has session attribute which is dictionary-like object:
request.session['context'] = '2k3'

But keep in the mind that this operation changes current session and it can affect the browser behaviour.

For instance, Internet Explorer enforces page refreshing during previous page loading by "Back"operation. So if you had completed form there (on the previous page) - form's data is lost with "Back" in browser.

Tuesday, March 30, 2010

Test Lint (Beta): Find common problems in your unit test code

http://site.typemock.com/test-lint/

I think it can be interesting for developers who use C# and VS2010:

Writing unit tests is easy. Writing good unit tests – that are readable, maintainable and trust-worthy is a bit harder if you’ve never done it before. So we took Roy Osherove (author of The Art of Unit Testing) and asked him to write down, based on his massive experience with unit testing, common problems that people do when they first start unit testing. Then we put that knowledge inside a Visual Studio 2010 extension– it’s like having your own personal coach letting you know of problems as you type them, really.

Test Lint parses your code as you type it, and looks for common problems in your unit test code – from missing asserts to having tests depend on other tests – Test Lint will notify you on the spot about each possible issue with a visible queue right inside your editor, right next to the link where the issue appears.

Test Lint will detect issues in tests written with:

  • Microsoft Test Framework
  • NUnit
  • MbUnit
  • XUnit.NET
  • CsUnit

Tuesday, March 23, 2010

Move a SharePoint Content Database


It's pretty easy:

Sometimes it's the easy things that are hard to track down concrete instructions for! Here are step by step instructions for moving your MOSS content database to a new server, followed by the things to watch out for.

You have two initial options, doing a backup and restore within MOSS to move the data, or doing it at the SQL/STSADM level. I prefer the latter, as it isn't nearly as inclined to fail and leaves you with more flexibility.

1) Find the content Database

These are listed under Central Admin->Application Management->Site Collection List

2) Backup the content database

You could alternatively detach it, and copy it. Just doing a backup in SQL Server 2005 Management studio is easier.

3) Restore content database to new server

Copy the BAK file to new server. Create an empty DB in Management Studio, restore from backup, you may need to change an option in the "options" tab of the restore dialog to get it to work. (Overwrite db).

4) Create Web App on new Server

Central Admin->Application Management->Create or extend Web App->Create New Web App.

5) Associate restored DB with new Web App

Central Admin->Application Management->SharePoint Web Application Management->Content Databases->

Remove Content Database from your new web app.

Now use STSADM to add restored DB to this web app

c:\program files\common files\microsoft shared\web server extentions\12\bin on new server is where you can find the STSADM.

run this command from there.

stsadm -o addcontentdb -url http://yourwebapp:port -databasename yourcontentdb -databaseserver yoursqlserver

6) Run ISSRESET from command prompt.

Caveats:

  • Make sure your running the same service pack level on both source and destination sharepoint if possible.
  • Make sure you install all webparts, solutions, features, etc on new server before you restore the content database, so that it can find all the features it's looking for.
  • Make sure you copy any files that may be living in the file system that you need, sometimes people have css/javascript here. (This refers to files in the hive)
  • Leave your old site and contentDB intact until you get the backup running on the new server, this way your ok if there is a problem.
  • DON'T try this with your config database! It won't work!

Monday, March 22, 2010

Get all users with Full Control for the web

Instead of user enumeration and check roles for each user, you can get role assignments for web and get all users for corresponding role.

Like this:

using(SPWeb web = SPSite(webUrl).OpenWeb())

{

SPRoleDefinitionCollection roleDefinitions = web.RoleDefinitions;

SPRoleDefinition roleDefinition = roleDefinitions["Full Control"];

foreach (SPRoleAssignment roleAssigment in web.RoleAssignments)

{

if (roleAssigment.RoleDefinitionBindings.Contains(roleDefinition))

{

SPPrincipal oPrincipal = roleAssigment.Member;//it can be SPUser or SPGroup, you can process and add it to the result

}

}

}

MSDN forum

Friday, March 19, 2010

Interview with Uncle Bob Martin (TDD, craftsmanship)

http://blog.typemock.com/2010/03/finally-entire-interview-with-uncle-bob.html

What is software craftsmanship all about?

Why TDD is not stupid

Confessions of a TDDer

TDD and unit testing adoption

Wednesday, March 17, 2010

Import WSS 3.0 Doclib to SharePoint 2010 with Content Migration API

It works.
You need just to change the schema version in SystemData.xml file to new SharePoint 2010 version ("14.0.0.0" Build="14.0.4730.1010" for my lab).

Ghosted vs Unghosted and where the file lives

Ghosted == Uncustomized == lives on the file system

These are generally deployed using features or site definitions


Unghosted == customized == lives in the content databse.

These files are either files that have been modified using SharePoint designer or uploaded through the user interface.

Generally Ghosted/unghosted were the terms used with SP 2003, while customized/uncustomized were introduced with 2007, supposedly to make the terms easier to understand.

http://platinumdogs.wordpress.com/2009/08/13/uncustomized-ghosts-vs-unghosted-customizations/

From MSDN forum: Original thread

Wednesday, March 10, 2010

SPExportSettings.FileMaxSize - limitations

MSDN describes that FileMaxSize allows to set 2GB.
But it looks like that it works with range from 1 to 1023 only, at least it tries to work :)

For any values >= 1024 the export uses default cmp size = 24MB

Also is interesting that stsadm has 1024 as a maximum cabsize value.

FileMaxSize works, at least I can get 10MB package. But the export fails on my lab with FileMaxSize > 100: "FatalError: Export ran out of memory while compressing a very large file. To successfully export, turn compression off by specifying the -nofilecompression parameter."

I have tried to export 6GB site and export works only with FileMaxSize <= 100. I think "100" can depend from real site data size.

There is interesting point that error can be raised due the manifest.xml size. I think that true is somewhere near, because compression works with default size. Probably the compression can not split some long description of object from manifest.xml between several files.
Looks like a bug.

Wednesday, March 3, 2010

SPExportObject.IncludeDescendants vs SPExportObject.ExcludeChildrens, what's the difference?

Really, what's the difference between children and descendants?

MSDN doesn't say about this difference: IncludeDescendants, ExcludeChildren.

But it looks like that IncludeDescendants is more flexible.

Export result shows that:

· ExcludeChildren = true is the same with IncludeDescendants = SPIncludeDescendants.Content.

· ExcludeChildren = false goes to IncludeDescendants = SPIncludeDescendants.All.

Ok, let check how the export depends from IncludeDescendants value and ExportObject type.

SPDeploymentObjectType.Web:

SPIncludeDescendants.All all web content and its sub-containers (like doclibs and lists) with sub-sites is exported

SPIncludeDescendants.Content – only root web content (doclibs, lists) is exported, without sub-sites

SPIncludeDescendants.None – exports only web property and service containers (like galleries). Usual doclibs and lists are not exported. In this mode export result doesn’t contain any custom aspx files from root web folder. /_themes, /images subfolders are excluded from the export also.

SPDeploymentObjectType.List

SPIncludeDescendants.Content, SPIncludeDescendants.All – full list content is exported

SPIncludeDescendants.None – only list properties are exported, no content

ExcludeChildren – doesn’t work for List because it maps to SPIncludeDescendants.Content or SPIncludeDescendants.All, those have the same export result. Note: MSDN says that ExcludeChildren works for List, but I do not see difference between results for ExcludeChildren = true or false. But it works for Folder!

SPDeploymentObjectType.Folder

SPIncludeDescendants.All (or ExcludeChildren = false) full folder and its sub-folders content is exported

SPIncludeDescendants.Content (or ExcludeChildren = true) and None – only folder properties is exported!

Tuesday, March 2, 2010

About SharePoint limitations

For URLs (by Joel)

For item&doc count (by Keith)

It was pretty easy.

I didn't think that blog creation is very easy. But it's true.