Showing posts with label SharePoint. Show all posts
Showing posts with label SharePoint. Show all posts

Monday, December 12, 2011

Powershell and search metadata properties

Scenario:
While working with one of client we created a quick script for creating / recreating metadata properties for search. Thought of sharing :)

This script will drop exiting property with same name [ if exist ] and create it again. Also I have provided samples of different field types.

Code:


#####################################################################
# Main Function
#####################################################################

function PromptUser {param($message)

write-host -f Red $message

write-host -f Red "Press enter to continue ... and N to exit"

$keyentered = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

If ($keyentered.VirtualKeyCode -eq 78)
{
exit
}
}

function DropMetadataProperties {param ($ServiceApplicationName, $MetadataPropertyName)

$category = Get-SPEnterpriseSearchMetadataCategory –Identity "Business Data" -SearchApplication $searchapp

If (Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $searchapp -Identity $MetadataPropertyName -ea "silentlycontinue")
{
write-host -f Green "MetaProperty already exists, we delete it so it can be reacreated."
$prop = Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $searchapp -Identity $MetadataPropertyName
$prop.DeleteAllMappings()
$prop.Delete()
$searchapp.Update()
}

if (!$?)
{
PromptUser("An error has occurred")
}
}

function CreateMetadataProperties {param ( $ServiceApplicationName, $MetadataPropertyName, $CrawledProperty, $VariantType, $Type, $HasMultipleValues, $IsSortable)

$category = Get-SPEnterpriseSearchMetadataCategory –Identity "Business Data" -SearchApplication $searchapp

$crawledproperty = Get-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $searchapp -Category $category -VariantType $VariantType -Name $CrawledProperty
If (!($crawledproperty -eq $null))
{
$managedproperty = New-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $searchapp -Name $MetadataPropertyName -Type $Type

If ($IsSortable -eq $True)
{
$managedproperty.MaxCharactersInPropertyStoreIndex = 64
$managedproperty.Update()
}

If ($HasMultipleValues -eq $True)
{
$managedproperty.HasMultipleValues = $true
$managedproperty.Update()
}


New-SPEnterpriseSearchMetadataMapping -SearchApplication $searchapp -ManagedProperty $managedproperty -CrawledProperty $crawledproperty
}
else
{
write-host -f Red "Crawl property is missing, you might need to recrawl your content source to get it."
}

if (!$?)
{
PromptUser("An error has occurred")
}
}

###################################################################################
# Drop metadata properties
###################################################################################

$searchapp = Get-SPEnterpriseSearchServiceApplication
if (!$?)
{
PromptUser("Could not find a valid Search Service Application.")
EXIT
}

$searchAppName = $searchapp.Name


# Client Metadata properties
DropMetadataProperties $searchAppName "xxClientName"

###################################################################################
# Create metadata properties
###################################################################################

# VariantType = (31 for string , 20 for integer , 11 for boolean , 64 for datetime )
# Type = (1 for string , 2 for integer , 5 for Yes/No , 4 for datetime )

### Text Field
DropMetadataProperties $searchAppName "xxClientName"
CreateMetadataProperties $searchAppName "xxClientName" "Client.ClientName" 31 1 $False $True

### Integer Field
DropMetadataProperties $searchAppName "xxClientID"
CreateMetadataProperties $searchAppName "xxClientID" "Clients.ClientID" 20 2 $False $False

### YES/No Field
DropMetadataProperties $searchAppName "xxIsActive"
CreateMetadataProperties $searchAppName "xxIsActive" "Clients.IsActive" 11 5 $False $False

### Date Field
DropMetadataProperties $searchAppName "xxEndDate"
CreateMetadataProperties $searchAppName "xxEndDate" "Clients.EndDate" 64 4 $False $False
Please do leave comments on if it worked for you or any suggestion to improve it.

Sunday, December 4, 2011

SharePoint reading version programatically

Scenario:
Recently doing a new project we needed to display version information of a list but we decided to make it more generic to support both document library and lists. There were lot of learning , I would say.. so I thought of sharing as always

Lesson Learned:
1. List version information + current version information can easily be retrieved using 'SPListItemVersionCollection' class

2. List version doesn't support version comment

3. SPListItemVersionCollection class is sorted by version number

4. Library version information can retrieved using 'SPFileVersionCollection' class but this will not return current version information.

5. Library version does support a version comment if same name file is uploaded. No comment is supported if 'Edit Properties' feature is used.

6. For Library , SPFileVersionCollection class is not guaranteed to be sorted by version number. So additional headache need to be taken to sort them.

7. For Library , Title column information/changes are stored in "vti_title" column.

About Helper Class Code:
Helper class below supports

1. Retrieving versions information for list/library

2. Retrieving all the changes for one particular field only

3. Support returning all versions / only versions which have changes for a particular field.

Helper Class Code:

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;

namespace SKN
{
public static class SharePointHelper
{
/// <summary>
/// Adds columns to the table.
/// </summary>
/// <param name="dtVersions">Version History Columns.</param>
public static void AddColumns (DataTable dtVersions)
{
dtVersions.Columns.Add("Source");
dtVersions.Columns.Add("Item");
dtVersions.Columns.Add("ColumnOldValue");
dtVersions.Columns.Add("ColumnValue");

dtVersions.Columns.Add("Version");
dtVersions.Columns.Add("Modified");
dtVersions.Columns.Add("Modified By");
dtVersions.Columns.Add("Comments");
}

/// <summary>
/// Redirection method for list\library
/// </summary>
/// <param name="dtVersions"></param>
/// <param name="web"></param>
/// <param name="listName"></param>
/// <param name="fieldName"></param>
/// <param name="showOnlyChanges">Show only rows which have changes</param>
/// <returns></returns>
public static DataTable GetAllVersions (SPWeb web, string listName, string fieldName, bool showOnlyChanges)
{
DataTable dtVersions = new DataTable();
AddColumns(dtVersions);

SPList spList = web.Lists[listName];
{
if (spList.BaseTemplate == SPListTemplateType.DocumentLibrary)
{
return GetAllLibraryVersions(dtVersions, web, listName, fieldName, showOnlyChanges);
}
else
{
return GetAllListVersions(dtVersions, web, listName, fieldName, showOnlyChanges);
}
}
}

/// <summary>
/// Show all versions of a list
/// </summary>
/// <param name="dtVersions"></param>
/// <param name="web"></param>
/// <param name="listName"></param>
/// <param name="columnName"></param>
/// <param name="showOnlyChanges">Show only rows which have changes</param>
/// <returns></returns>
public static DataTable GetAllListVersions (DataTable dtVersions, SPWeb web, string listName, string columnName, bool showOnlyChanges)
{
SPList spList = web.Lists[listName];
SPListItemCollection listItemColl = spList.Items;

// for each item
foreach (SPListItem listItem in listItemColl)
{
string columnOldValue = "NULL";
bool relavantRow = true;

SPListItemVersionCollection versionColl = listItem.Versions;
for (int i = versionColl.Count - 1; i >= 0; i--)
{
try
{
DataRow dr = dtVersions.NewRow();
dr["Source"] = listName;
dr["Item"] = listItem.Title;

dr["Version"] = versionColl[i].VersionLabel;
dr["Modified By"] = versionColl[i].CreatedBy.User.Name;
dr["Modified"] = GetDateDisplay(web, versionColl[i].Created);

dr["Comments"] = string.Empty;

dr["ColumnOldValue"] = columnOldValue;

if (null != versionColl[i][columnName])
{
dr["ColumnValue"] = versionColl[i][columnName];
}
else
{
dr["ColumnValue"] = "NULL";
}
if (showOnlyChanges)
{
relavantRow = !string.Equals(columnOldValue, dr["ColumnValue"].ToString(), StringComparison.InvariantCultureIgnoreCase);
}
columnOldValue = dr["ColumnValue"].ToString();

if (relavantRow)
{
dtVersions.Rows.InsertAt(dr, 0);
}
}
catch
{
}
}
}

return dtVersions;
}

/// <summary>
/// Show all versions of a document library
/// </summary>
/// <param name="dtVersions"></param>
/// <param name="web"></param>
/// <param name="listName"></param>
/// <param name="columnName"></param>
/// <param name="showOnlyChanges">Show only rows which have changes</param>
/// <returns></returns>
public static DataTable GetAllLibraryVersions (DataTable dtVersions, SPWeb web, string listName, string columnName, bool showOnlyChanges)
{
SPList spList = web.Lists[listName];
SPListItemCollection listItemColl = spList.Items;

foreach (SPListItem doc in listItemColl)
{
string columnOldValue = "NULL";
bool relavantRow = true;
string updatedColumnName = columnName;

if (columnName.Equals("Title"))
{
updatedColumnName = "vti_title";
}

SPFileVersionCollection versionColl = doc.File.Versions;
Dictionary<int, string> myDict = new Dictionary<int, string>();

for (int i = 0; i < versionColl.Count; i++)
{
myDict.Add(i,versionColl[i].VersionLabel);
}

var sortedDict = (from entry in myDict orderby entry.Value ascending select entry).ToDictionary(pair => pair.Key, pair => pair.Value);

foreach(var k in sortedDict)
{
try
{
DataRow dr = dtVersions.NewRow();
dr["Source"] = doc.File.ParentFolder;
dr["Item"] = doc.File.Name;
dr["Version"] = versionColl[k.Key].VersionLabel;
dr["Modified By"] = versionColl[k.Key].Properties["vti_modifiedby"];
dr["Modified"] = GetDateDisplay(web, versionColl[k.Key].Properties["vti_timelastmodified"]);

dr["ColumnOldValue"] = columnOldValue;

if (null != versionColl[k.Key].Properties[updatedColumnName])
{
dr["ColumnValue"] = versionColl[k.Key].Properties[updatedColumnName].ToString();
}
else
{
dr["ColumnValue"] = "NULL";
}

if (showOnlyChanges)
{
relavantRow = !string.Equals(columnOldValue, dr["ColumnValue"].ToString(), StringComparison.InvariantCultureIgnoreCase);
}

columnOldValue = dr["ColumnValue"].ToString();

if (null != versionColl[k.Key].Properties["vti_sourcecontrolcheckincomment"])
{
dr["Comments"] = versionColl[k.Key].Properties["vti_sourcecontrolcheckincomment"];
}

if (relavantRow)
{
dtVersions.Rows.InsertAt(dr, 0);
}
}
catch
{
}
}

DataRow drLatestVersion = dtVersions.NewRow();
drLatestVersion["Source"] = doc.File.ParentFolder;
drLatestVersion["Item"] = doc.File.Name;
drLatestVersion["Modified By"] = doc.File.ModifiedBy;
drLatestVersion["Modified"] = DateTime.Parse(doc["Modified"].ToString()).GetDateTimeFormats()[43];

if (null != doc["Version"])
{
drLatestVersion["Version"] = doc["Version"];
}

if (null != doc["_CheckinComment"])
{
drLatestVersion["Comments"] = doc["_CheckinComment"].ToString().Split('#')[1];
}

// Old Value from stored variable
drLatestVersion["ColumnOldValue"] = columnOldValue;

// Checking for new value
if (null != doc[columnName])
{
drLatestVersion["ColumnValue"] = doc[columnName].ToString();
}
else
{
drLatestVersion["ColumnValue"] = "NULL";
}

if (showOnlyChanges )
{
relavantRow = !string.Equals(columnOldValue, drLatestVersion["ColumnValue"].ToString(), StringComparison.InvariantCultureIgnoreCase);
}

columnOldValue = drLatestVersion["ColumnValue"].ToString();

if (relavantRow)
{
dtVersions.Rows.InsertAt(drLatestVersion, 0);
}
}

return dtVersions;
}

public static string GetDateDisplay (SPWeb web, object p)
{
return SPUtility.FormatDate(web, DateTime.Parse(p.ToString()), SPDateFormat.DateTime).ToString();
}
}
}

Friday, September 30, 2011

Deleting all items from lists

Scenario:
Often during data migration we need to do clean up list data. I had something similar but there were multiple lists and each list with 5000-10000 records.

Solution:
Quick console application did the trick of cleaning all the lists.
>> Create a new console application and add reference to Microsoft.SharePoint.dll
>> Use the below code.

Code: [ Applies To : WSS3.0 / Sharepoint 2010 Foundation ]

using System;
using Microsoft.SharePoint;
using System.Collections.Generic;
using System.Text;

namespace SKN.CleanSPLists
{
class Program
{
static void Main (string[] args)
{
string webUrl = "http://ws2003";
bool deleteFromRecycleBin = true;
List<string> listNames = new List<string>();
listNames.Add("List Title 1");
listNames.Add("List Title 2");
listNames.Add("List Title 3");
listNames.Add("List Title 4");

using (SPSite site = new SPSite(webUrl))
{
using (SPWeb web = site.OpenWeb())
{
foreach (var listName in listNames)
{
SPList list = web.Lists[listName];

Console.WriteLine("Purging list: " + list.Title);
Console.WriteLine("Base Type: " + list.BaseType.ToString());

StringBuilder sbDelete = BuildBatchDeleteCommand(list);
web.ProcessBatchData(sbDelete.ToString());

Console.WriteLine("Done cleaning list : Presss a key to continue with next list.");
Console.WriteLine("");
Console.ReadKey();
}


if (deleteFromRecycleBin)
{
Console.WriteLine("Cleaning Recycle bin");
web.RecycleBin.DeleteAll();
site.RecycleBin.DeleteAll();
Console.WriteLine("Done cleaning Recycle bin");
Console.ReadKey();
}
}
}
}


/// <summary>
/// Builds a batch string with a list of all the items that are to be deleted.
/// </summary>
/// <param name="spList"></param>
/// <returns></returns>
private static StringBuilder BuildBatchDeleteCommand (SPList spList)
{
StringBuilder sbDelete = new StringBuilder();
sbDelete.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Batch>");
string command = "<Method><SetList Scope=\"Request\">" + spList.ID +
"</SetList><SetVar Name=\"ID\">{0}</SetVar><SetVar Name=\"Cmd\">Delete</SetVar></Method>";

foreach (SPListItem item in spList.Items)
{
sbDelete.Append(string.Format(command, item.ID.ToString()));
}
sbDelete.Append("</Batch>");
return sbDelete;
}
}
}
Article: Batch command , SP List Delete

Tuesday, March 8, 2011

SharePoint Picture library thumbnail url

Scenario:
While working with picture library we often need Thumbnails for display purpose.
Also depending upon you are accessing it in XSLT or C# code, you need the proper Url to the SharePoint generated thumbnail url.

Solution:
Small snippet here has it

Code:


<a href="{@EncodedAbsUrl}"><img border="0" src="{@EncodedAbsThumbnailUrl}"/></a>

SPListItem["EncodedAbsUrl"]
or
SPListItem["EncodedAbsThumbnailUrl"]


SPListItem[SPBuildInFieldId.EncodedAbsUrl]
or
SPListItem[SPBuildInFieldId.EncodedAbsThumbnailUrl]

Monday, February 21, 2011

SharePoint : Limitations

Scenario:
After working on SharePoint for some time now. I thought of documenting few of the limitations I came to know.

Design:
1. Error : Most of the error messages are mis-leading. I agree this has improved in SP2010 as we have correlation token's to trace the error much faster.

2. Packaging : WSP are great but when it comes to deploying something in Inetpub folder, its limited.

File System:
1. Project Structure : SharePoint 12/14 hive feature folder doesn't support sub-folders. So developers need to add some prefix to identify all the features from one project in 2007. Same is done automatically by VS2010 in case of SP2010 projects.

2.Field Control and User Control based templates : Even though it is possible to have a sub-folder in CONTROLTEMPLATE to logically group multiple user controls which are custom developed under a sub-folder. This is not possible for the User Controls which are used by Field Controls. SharePoint will not be able to read these Field Control / Editor templates. Applicable to both in SP2007/2010.

3. XML files merging : While SharePoint does a great job of merging various site definition XML file ( any file with prefix onet** ) , this is not possible with other XML files like AlertTemplates.xml / DocIcon.xml.

UI Related limitation:
1. Views : View are great but again with a limitations. You can create many many views but the View Drop will be able to list out only 50 :)

2. Pages Library : Doesn't support sub-folders in SP2007. In SP2010 it does, surely a relief.

3. List in general : Doesn't support sub-folders in SP2007 and SP2010. Document libraries does.

4. Incoming Email : Great feature, you send an email with an attachment and if you have setting to retain the original email also for the document library. You will see 2 new documents created. Once some few emails with attachment arrives in the document library there is not way to identify which attachment belongs to which email. LOL :)

5. Calendar List : Recurring events are great but try editing one single instance of it and that it. Weird things will start happening. Manage permission menu is gone from UI altogether for this item. Actually its a bug.

Coding :
1. SPQuery class : There is no easy way to figure out the exact number of records returned by a particular query. In case you need to display that 1-10 of x results type display, no luck.


There is not the exhaustive list , but I will keep updating as I see more.

Monday, July 19, 2010

SharePoint Document Library and physical folders

Scenario:
This is 5am and my friend asked me "Is it possible to create directory in share point where user can upload some document new files and they get synced with some physical folder for further processing by other LOB systems."

Solution:
Even though there can be many solutions to thsi kind of situation. I am listing a few here.

1. I will recommend not to create a physical folder and adjust the foreign process to read directly from SP Document Library ( 20 lines of code ). In case this is not possible for any reason, try other options

2. Create a new Visual Webpart/User Control to provide a UI for uploading a document and directly to the physical folder. This is kind of pure ASP.Net approach. Disadvantage of this approach will be that there is no copy retained in SharePoint.

3. Incase you want to retain a copy in Sharepoint also

3a. Modify the above Webpart/User Control to create copies in physical folder and sharepoint document library

3b. Provide a document library for user to upload documents and Create a Window Service with Timer to poll this document library for any changes and sync physical folder accordingly.

4. We can write event handler/workflow on the designated document library . Thanks to Gaurav suggesting this. ( It was 5 am and I was sleepy :) )

Any other thoughts ? Welcome :)

Saturday, July 10, 2010

Quickly find Site Template ID

Scenario:
Sometime we want to quickly find out the right web template ID for a site/web.

Solution:
Even though there are soooo many ways to find this out.
1.Powershell
2. Quick Console Application

Here's another quick no-code solution to this. Try it

Steps:
1. Go to http://sharepoint.microsoft.com
2. Right click > View Source
3. Search for "SiteTemplate" keyword ( without space ) and you have you answer

sitetemplateID

Thursday, January 7, 2010

The document could not be created

Scenario:
Got the following message while creating a new document.

err

Solution:
Install Office 2003 or Office 2007.

Wednesday, January 6, 2010

Exception of type Microsoft.Office.Server.UserProfiles.UserProfileException

Scenario:

Failed to create sample data.
An exception of type Microsoft.Office.Server.UserProfiles.UserProfileException was thrown. Additional exception information: Unrecognized attribute 'allowInsecureTransport'. Note that attribute names are case-sensitive. (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\WebClients\Profile\client.config line 56)


ds

Solution:
Install following hotfixes and re-boot the server

Download available here:
KB971831 - Windows Server 2008 Service Pack 2, Windows Vista Service Pack 1 or Windows Vista Service Pack 2

KB976462 - Windows Server 2008 R2 and Windows 7

Friday, April 10, 2009

WCF turn on IncludeExceptionDetailInFaults

Error: The server was unable to process the request due to an internal error.
For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the
configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.System.Exception {System.ServiceModel.FaultException}

Reason/Solution:
When any kind of error occur calling a WCF endpoint from client, client will receive a generic message ( as given above ) for security reason.

If you want to see the full details of the error, you need to change the app.config file for the WCF Host to include full exception details while sending it to clients.

Host App.Config:

<configuration>
<system.serviceModel>
<services>
<!-- Step 1. Add a behaviorConfiguration attribute -->
<service
name="Microsoft.WCF.Documentation.SampleService"
behaviorConfiguration="metadataAndDebug">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/SampleService" />
</baseAddresses>
</host>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<!-- Step 2. Add a new behavior below.-->
<behavior name="metadataAndDebug">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
<!-- Step 3. Add a <serviceDebug> element -->
<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Article:MSDN


This setting is only recommended for DEV purpose.

WCF : Already a listener on the IP endpoint

Scenario:
While testing my WCF service using netTCP binding, I got the following error.

Error:Unhandled Exception: System.ServiceModel.AddressAlreadyInUseException: There is already a listener on IP endpoint 0.0.0.0:9000. Make sure that you are not trying to use this endpoint multiple times in your application and that there are no other applications listening on this endpoint. ---> System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted

Reason:
NetTcp Port Sharing is a Windows Communication Foundation (WCF) feature that is similar to IIS and allows multiple network applications to share a single port. The NetTcp Port Sharing Service accepts connections using the net.tcp protocol and forwards messages based on their destination address.But NetTcp Port Sharing Service is not enabled by default.

Solution:
1. You can also use TCPView to check what process that is holding the port open.
2. Check using following command
netstat -a | find "portno"
3. Try restarting the service or server
4. Try configuring the service on different port number
5. You can try enabling port sharing ( require NetTcp Port Sharing Service running)

Code:


<system.serviceModel>
<bindings>
<netTcpBinding name="customBinding"
portSharingEnabled="true" />
<services>
<service name="MyService">
<endpoint address="net.tcp://localhost/MyService"
binding="netTcpBinding"
contract="IMyService"
bindingConfiguration="customBinding" />
</service>
</services>
</system.serviceModel>
Article:
TCP View

Thursday, April 9, 2009

WCF Errors

Scenario:
Past week I was working on a new WCF service and encountered following errors

Error 1:
The maximum array length quota (16384) has been exceeded while reading XML data. This quota may be increased by changing the MaxArrayLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.'. Please see InnerException for more details.

Error 2:
The maximum nametable character count quota (16384) has been exceeded while reading XML data. The nametable is a data structure used to store strings encountered during XML processing - long XML documents with non-repeating element names, attribute names and attribute values may trigger this quota. This quota may be increased by changing the MaxNameTableCharCount property on the XmlDictionaryReaderQuotas object used when creating the XML reader

Error 3:
The formatter threw an exception while trying to deserialize the message: Error in deserializing body of request message for operation 'XYZ'. The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader

Solution:
All the above errors are related to the way Server and Client side binding configuration are set. Make sure you have same values on both side.

Error 1 : MaxArrayLength default value is 16384 , try increasing it to a bigger value.

Error 2 : MaxNameTableCharCount default value is 16384 , try increasing it to a bigger value.

Error 3 : MaxStringContentLength default value is 8192, try increasing it to a bigger value.

Saturday, April 4, 2009

Visual Studio name too long error

Scenario:
When you create your solution/project inside Visual Studio it gives you error that name is too long and it cannot create that solution/project. So some of you might be thinking that looks like VS has some limitation on characters for a project/solution.

Solution:
Well that’s not the case. Problem is that if you create solution deep inside the path (default path of VS is document & settings -> visual studio projects etc.) then this error arises and if you change the path to some small path like c:\working or c:\VSProjects and keep your solution name as its, it will work.

Tuesday, February 3, 2009

Debugging Timer Job

Scenario:
I have already written some articles about writing and managing the Timer Job.One of my student asked me how to debug the timer job.

Solution:
Its preety simple. Follow the following step to debug the Timer Job.
1. Open the Visual Studio and the Timer Job code base
2. Set the break point in the code
3. Attach the debugger to OWSTimer.exe
4. Wait for the next cycle of the timer job.

Make sure that you dont set Timer Job interval more than 5 min for development purpose, otherwise you need to wait for longer.

You can also execute the Timer Job forcefully by writing a small console application.
or
using STSADM command line

Code:

stsadm -o execadmsvcjobs
Other Consideration:
When you change the code base for the Timer Job, deploy the new binary in GAC and RESET the OWSTimer.exe service.

Yes you are right I said OWSTimer and not IIS Reset , because timer job run inside the OWStimer process only and till you restart it, it will always run it from previously cached copy.

:-)

Sunday, August 24, 2008

Creating child site while provisioning Root Site

Scenario:
As a part of site provisioning process you want to create some child sites also.

Solution:
Specify a provisioning provider while registering your Site Defintion as shown below.

Snippet:
Sample WebTemp* file :

<Template Name="ClientApplication" ID="10090">
<Configuration ID="0" Title="Client Application" Hidden="FALSE"
ImageUrl="/_layouts/1033/images/clientapplication.gif"
Description="This site will create a top level site and will create some sub level sites."
ProvisionAssembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
ProvisionClass="Microsoft.SharePoint.Publishing.PortalProvisioningProvider"
ProvisionData="xml\\ClientSiteHierrarchy.xml"
RootWebOnly="TRUE" DisplayCategory="Client Sites" >
</Configuration>
</Template>
Above example uses a PortalProvisioningPortal which supports ProvisionData attribute which is basically a XML file path relative to layout folder.

Sample ClientSiteHierrarchy.xml file :
<?xml version="1.0" encoding="utf-8" ?>
<portal xmlns="PortalTemplate.xsd">
<web name="Home"
siteDefinition="STS#0"
displayName="Root Site"
description="This is root site" >
<webs>
<web name="First Child Site"
siteDefinition="STS#1"
displayName="First Child Site"
description="This is First Child Site" />
<web name="Second Child Site"
siteDefinition="STS#1"
displayName="Second Child Site"
description="This is Second Child Site" />
</webs>
</web>
</portal>
Notes:
Above example has dependency upon Publishing assembly which is not a part of WSS. But you are not restricted by this assembly, you can write your own ProvisioningProvider by implementing Microsoft.SharePoint.SPWebProvisioningProvider

Saturday, August 23, 2008

Document library explorer view problem

Scenario:
When you navigate a document library and click on Action > Open In Explorer View , nothing happens

Possible Reasons:
1. 'WebClient' service not running on the client computer.
2. Your Site is not listed as Trusted Site.

Resolution:
1. Make sure WebClient service is running.
2. Add the site to the list of Trusted Sites.

Steps:
1.a. Open 'Administrative Tools'
1.b. Open 'Services' and look for the 'WebClient' service.
1.c. If this one is stopped or disables, enable it and start it.

2.a. Open Internet Explorer
2.b. Go to Tools > Internet Options > Security.
2.c. Click on Trusted Sites and Add option
2.d. Add the site to the list of Trusted Sites.

Debugging sharepoint error

Scenario:
You was working with SharePoint and got Error : Unknown Error or Cannot complete this action

Reason:
SharePoint has encountered some processing error but haven't displayed the complete Error details because of various setting in Web.Config ( relates to Debugging and Trace etc ).

Resolution:
0. Check the logs in 12 HIVE
1. Make the necessary changes as given below to the Web.Config.
2. Make sure Logging is enabled in Central Administration > Operations > Logging
3. Check the logs in 12 HIVE

Code:


<configuration>
<SharePoint>

<SafeMode CallStack="true" AllowPageLevelTrace ="true">
** change both to true

</SharePoint>
<system.web>
<customErrors mode="RemoteOnly" />
** change to RemoteOnly (better than Off)

<compilation debug="true" />
** change to true

<trust level="Full" originUrl="" />
** may need to change this to Full

</system.web>
</configuration>
Article
Custom Errors

Saturday, August 16, 2008

Redirecting to Access deined page

Scenario:
You want to redirect user to access denied page when your code attempts to access an object to which the user does not have access.

Solution:
SPUtility class provides method HandleAccessDenied, which redirects user to standard access denied page.

Code Snippet:

try
{
//your code goes here
}
catch(Exception ex)
{
SPUtility.HandleAccessDenied(ex);
}

Thursday, August 7, 2008

Deleting all the Items from a list or library

Scenario:
You want to delete all the items from a list or library

Code:

StringBuilder sbDelete = new StringBuilder();

sbDelete.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Batch>");

sbDelete.Append("<Batch>");

string command = "<Method><SetList Scope=\"Request\">" + spList.ID + "</SetList>";
command +="<SetVar Name=\"ID\">{0}</SetVar><SetVar Name=\"Cmd\">Delete</SetVar></Method>";

foreach (SPListItem item in spList.Items)
{
sbDelete.Append(string.Format(command, item.ID.ToString()));
}

sbDelete.Append("</Batch>");

spSite.RootWeb.ProcessBatchData(sbDelete.ToString());

Wednesday, August 6, 2008

Moving a Site collection

Scenario:
You have a site collections running at http://severname:port/ on farm 1
and now want to move it to http://servername/sites/site on farm 2.

Required Permissions & Assumption:
Site collection Admin or Farm Admin account , Both contentDBs belong to same farm.

Command:

stsadm.exe -o mergecontentdbs
-url
-sourcedatabasename
-destinationdatabasename
[-operation <1-3>
1 - Analyze (default)
2 - Full Database Merge
3 - Read from file]
[-filename ]

stsadm -o enumcontentdbs -url
stsadm -o enumsites -url -databasename


Example Usage:
Best way to use this command is to generate the file
by using the stsadm -o enumsites command. Open the file and remove the lines within the site collections you do not want to move. Save the file and use it as shown below.

stsadm.exe -o mergecontentdbs -url http://server_name
-sourcedatabasename WSS_Content_SOURCE_DB
-destinationdatabasename WSS_Content_DEST_DB -operation 3 -filename listofsites.txt


Related Articles:
http://www.toddklindt.com/blog/Lists/Posts/Post.aspx?ID=53