Tuesday, June 26, 2012

Elegant way of setting and getting values from SPListItem

As we already know setting and getting values from SPListItem usually involves checking if the field is available, if exist then checking if the value is not null and then only we can make sure that we can read a value from the SPListItem. the following code snippet explains how we usually do that;

1 using (SPSite spSite = new SPSite("http://sp2k10"))
2 {
3 using (SPWeb spWeb = spSite.OpenWeb())
4 {
5 try
6 {
7 SPList spList = spWeb.Lists.TryGetList("ListName");
8 SPListItem spListItem = spList.GetItemById(1);
9 //see if the field exists and the value is not null
10 string fieldName = "fieldName";
11 if (spListItem.Fields.ContainsField(fieldName) && spListItem[fieldName]!=null)
12 {
13 object fieldVal = spListItem[fieldName];
14 }
15 }
16 catch (Exception exception)
17 { }
18 }
19 }



as you can see we have to know the type of the column for us to type cast the returned value. it would be really easy for the programmer if there is a way to call a typed method and get the value back. to achieve this I have decided to write 2 extension methods to get and set SPListItem values.



first we will look at the setting of SPListItem value using extention method.









1 public static bool TrySetValue<T>(this SPListItem listItem, string fieldInternalName, T value)
2 {
3 try
4 {
5 if (!String.IsNullOrEmpty(fieldInternalName) &&
6 listItem != null &&
7 listItem.Fields.ContainsField(fieldInternalName))
8 {
9 listItem[fieldInternalName] = value;
10 }
11 return true;
12 }
13 catch (Exception exception)
14 {
15 return false;
16 }
17 }


as you can see there is no magic here and the value is assigned at line 9.



Now, let’s look at the set method. I have used generics in order to prevent calling method using type casting.



1 public static T TryGetValue<T>(this SPListItem listItem, string fieldInternalName)
2 {
3 if (!String.IsNullOrEmpty(fieldInternalName) &&
4 listItem != null &&
5 listItem.Fields.ContainsField(fieldInternalName))
6 {
7 object untypedValue = listItem[fieldInternalName];
8 if (untypedValue != null)
9 {
10 var value = (T)untypedValue;
11 return value;
12 }
13 }
14 return default(T);
15 }


Let’s look at the usage of these 2 methods.



1 SPListItem spListItem = spList.GetItemById(1);
2 //read values
3 string title = spListItem.TryGetValue<string>("Title");
4 DateTime modDate = spListItem.TryGetValue<DateTime>("dateTimeField");
5
6 //set value
7 spListItem.TrySetValue("dateTimeField", DateTime.Now);
8 spListItem.TrySetValue("Title", "test value");
9 spListItem.Update();


Hope this blog post would help you to streamline the SPListItem set and get value process.

Tuesday, November 16, 2010

Enabling sound card in your Windows Server 2008 R2 Hyper-V machine

When I started SharePoint 2010 development projects recently, the first thing I did was start building a Windows Server 2008 R2 virtual machine. at first I could not get my sounds enabled and few different blogs have suggested that sound can be enabled when you RDP to your VM. unfortunately, the Windows Server 2008 R2 virtual machine sound card is not enabled by default even you RDP to it. so, I have decided to somehow enable it and gone through few blogs and collected pieces here and there. here are the steps how you can enable sound card in your Windows server 2008 R2.

1. Type ‘remote’ at start search text box

image

2. Click ‘Remote Desktop Session Host Configuration’ link

3. Open the properties page of the default remote desktop connection by right clicking on the  connection name (or double-clicking) under ‘Connections’ section. usually the connection name is RDP-Tcp

image

4. In the properties page select ‘Client settings’ tab and notice ‘Audio and video playback’ option is disabled

 image

5. De-select ‘Audio and video playback’ option and click Apply. then click OK to close the page.

6. Log-off and log back in to the virtual machine using RDP to get the changes applied to the system.

Now you should see the sound is enabled in your system.

image

I hope this would help you especially on playing video tutorials on your Hyper-V machine.

Thank You

Tuesday, May 11, 2010

Fixing Session error with custom SharePoint master pages

Recently one of my colleague asked me to look in to a weird problem he is facing with regards to SharePoint master page. in this SharePoint site he has a Pages library that publishes plain aspx pages that implements some of his Session related functionality in code behind. all went well until he changed the master page to a custom master page which was uploaded in to the master page gallery. suddenly we were getting the following error in the aspx page.
the funniest(or the weirdest) thing is that if the master page is changed back to any out of the box master page, the site works fine. after some investigation I realized that if the site master page is changed to a customized master page (or even to a custom master page that has been uploaded in to master page gallery through SharePoint UI) the aspx page breaks with the error. 
"Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the <configuration>\<system.web>\<httpModules> section in the application configuration."
Straight forward, Right? so, checked the web.config over and over again, but the setting is set to enable the session state. after some Googling I realized that every body is suggesting that the web.config should be corrected. but, it is corrected. so, what's next?
So, what is the difference between OOB master pages and the custom master pages that are uploaded through SharePoint UI or customized through SharePoint Designer? the simple difference is the way how they ended up in the gallery. OOB master pages are uploaded via feature activation and sit in the WFE's file system where as other reside in the site content data base. so, I decided to create a file upload feature. please check Heather Solomon's article on how to create a master page feature.
By activating the new master page feature, I got the new master page available in the master page gallery. then I set the new master page of the site. walla, it worked!!! No more Session errors in the custom aspx page.
Even though I got the problem solved for my colleague, I still don't understand what caused the problem. so, if anybody knows the cause of the problem I would appreciate comments on this thread.

Thursday, August 13, 2009

Changing ListViewWebPart Toolbar and Current View

Recently I came across a situation where I had to change the order of the fields of the current view and change the existing sort order of the current view of Tasks ListViewWebpart. and also my client wanted to change the view so that it shows only ‘Active’ tasks in the webpart. other requirement was to change the toolbar type from ‘Full Toolbar’ to ‘Summary Toolbar’. I know these changes are very easy to do in the UI by going in to edit mode of the ListViewWebPart and editing current view and then selecting the required toolbar type from the drop down box.

Unfortunately, the situation I am in is not so simple. we already have provisioned close to 100 sites and changing all the sites through UI would be a real pain. so, I thought the best way to do this is to write a custom stsadm command that iterates through the site collection which locates the required webpart and then change the toolbar type and edit the current view.

for simplicity, I will not show how to write the stsadm command, but, I will show you how to change the toolbar type and modify the current view of the webpart.

private void ChangeView(List<SPWeb> webs, string targetwp, string list)
{
foreach (SPWeb spWeb in webs)
{
using (spWeb)
{
try
{
using (SPLimitedWebPartManager wm = spWeb.GetLimitedWebPartManager("default.aspx", PersonalizationScope.Shared))
{
SPList spList = spWeb.Lists[list];
ListViewWebPart originalwp = (ListViewWebPart)SPUtil.GetWP(targetwp, wm);
//where query filters all the 'Active' tasks as well as sort on 'Modified'
String wherequery =
"<Where>" +
" <Neq>" +
" <FieldRef Name='Status' />"+
" <Value Type='Choice'>Completed</Value>" +
" </Neq>" +
"</Where>" +
"<OrderBy>" +
" <FieldRef Name='Modified' Ascending='FALSE' />" +
"</OrderBy>";

Guid guid = new Guid(originalwp.ViewGuid);
SPView webPartView = spList.Views[guid];
webPartView.ViewFields.DeleteAll();
webPartView.ViewFields.Add("Title");
webPartView.ViewFields.Add("Assigned To");
webPartView.ViewFields.Add("Due Date");
webPartView.ViewFields.Add("Status");
webPartView.Query = wherequery;
webPartView.RowLimit = 8;
webPartView.Update();
SetToolbarType(webPartView, "Freeform");
originalwp.ViewGuid = webPartView.ID.ToString("B").ToUpper();
wm.SaveChanges(originalwp);
spWeb.Update();
}
}
catch (Exception e)
{
Console.WriteLine(spWeb.Title + " was not processed.reason : " + e.Message);
}
}
}
}

Notice the the line where private method ‘SetToolbarType’ is being called where modifying the toolbar type is happening.

Due to a SharePoint API bug, you can not set the Toolbar type directly. there are plenty of resources out there on how to do this using reflection.

The following piece of code from Mark Stokes blog explains nicely how to change the Toolbar type with reflection.

private static void SetToolbarType(SPView spView, String toolBarType)
{
spView.GetType().InvokeMember("EnsureFullBlownXmlDocument", BindingFlags.NonPublic BindingFlags.Instance BindingFlags.InvokeMethod, null, spView, null, System.Globalization.CultureInfo.CurrentCulture);

PropertyInfo nodeProp = spView.GetType().GetProperty("Node", BindingFlags.NonPublic BindingFlags.Instance);
XmlNode node = nodeProp.GetValue(spView, null) as XmlNode;
XmlNode toolbarNode = node.SelectSingleNode("Toolbar");

if (toolbarNode != null)
{
toolbarNode.Attributes["Type"].Value = toolBarType;

// If the toolbartype is Freeform (i.e. Summary Toolbar) then we need to manually
// add some CAML to get it to work.
if (String.Compare(toolBarType, "Freeform", true, System.Globalization.CultureInfo.InvariantCulture) == 0)
{
string newItemString = "";
XmlAttribute positionNode = toolbarNode.OwnerDocument.CreateAttribute("Position");
positionNode.Value = "After";
toolbarNode.Attributes.Append(positionNode);

switch (spView.ParentList.BaseTemplate)
{
case SPListTemplateType.Announcements:
newItemString = "announcement";
break;
case SPListTemplateType.Events:
newItemString = "event";
break;
case SPListTemplateType.Tasks:
newItemString = "task";
break;
case SPListTemplateType.DiscussionBoard:
newItemString = "discussion";
break;
case SPListTemplateType.Links:
newItemString = "link";
break;
case SPListTemplateType.GenericList:
newItemString = "item";
break;
case SPListTemplateType.DocumentLibrary:
newItemString = "document";
break;
default:
newItemString = "item";
break;
}

if (spView.ParentList.BaseType == SPBaseType.DocumentLibrary)
{
newItemString = "document";
}

// Add the CAML
toolbarNode.InnerXml = @"<IfHasRights><RightsChoices><RightsGroup PermAddListItems=""required"" /></RightsChoices><Then><HTML><![CDATA[ <table width=100% cellpadding=0 cellspacing=0 border=0 > <tr> <td colspan=""2"" class=""ms-partline""><IMG src=""/_layouts/images/blank.gif"" width=1 height=1 alt=""""></td> </tr> <tr> <td class=""ms-addnew"" style=""padding-bottom: 3px""> <img src=""/_layouts/images/rect.gif"" alt=""""><a class=""ms-addnew"" ID=""idAddNewItem"" href=""]]></HTML><URL Cmd=""New"" /><HTML><![CDATA["" ONCLICK=""javascript:NewItem(']]></HTML><URL Cmd=""New"" /><HTML><![CDATA[', true);javascript:return false;"" target=""_self"">]]></HTML><HTML>Add new " + newItemString + @"</HTML><HTML><![CDATA[</a> </td> </tr> <tr><td><IMG src=""/_layouts/images/blank.gif"" width=1 height=5 alt=""""></td></tr> </table>]]></HTML></Then></IfHasRights>";
}

spView.Update();

}
}


That concludes this article on how to change toolbar type and how to modify current view of a list view webpart.

Tuesday, June 23, 2009

Custom ‘stsadm’ command to change Top Navigation Tab URL

It has been a while since my last post and today I am going to show you how to code a custom ‘stsadm’ command to change the url of a given top navigation tab. the reason I had to write this command was that, my client is using backup/restore to promote the site collection to different environments. when this happens all the non-relative urls are carried over to new environment that are not relevant to the new environment. so, one option is to change the urls in the UI. but, unfortunately the site collection has more than 500 sub-sites under it and changing them manually is nearly impossible.

Now, let’s do some coding.

There will be 3 required parameters in the command.

Url of the targeted site, title of the top navigation tab that url needs to be changed and the last one is the new Url for the tab. and also we need to have few utility methods that iterates through the site collection/site and returns the list of SPWeb objects.

Now, I will define the usage string for the command as follows.
private string usageString = "[-siteurl < site url>] - site collection url or site url\n" +
"\t[-targettitle <url>] - title of the navigation item that needs to be replaced with new url\n" +
"\t[-newurl <url>] - new url \n";
As you already know when you write a custom stsadm command you have to implement ISPStsadmCommand with GetHelpMessage and Run methods.

public string GetHelpMessage(string command)
{
return usageString;
}

public int Run(string command, StringDictionary keyValues, out string output)
{
int rtnCode = 0;
string cmd = command.ToLowerInvariant();

switch (cmd)
{
case "spupdatenavigation":
rtnCode = this.Traverse(keyValues);
break;

default:
throw new InvalidOperationException();
}
output = "";
return rtnCode;
}
now, let’s get to the code where magic happens.

my strategy here is to navigate trough all the sites that were returned by previous methods and get the Global navigation Node Collection for each site. and , then for each node, recursively navigate to the targeted node, change and update the url.

Once, you have sign the project and compile the code, one more step is required to register the command in the system. to register the command in the system I create the a xml file ‘stsadmcommands.xxx.xml’ in 12\CONFIG and the file name should be in the format of ‘stsadmcommands.<custom name>.xml’. the file contains the following;

<?xml version="1.0" encoding="utf-8" ?>
<commands>
<command name="spupdatenavigation" class="XXX.Utils.Commands.SPUpdateNavigationCommand, XXX.Utils.Commands, Version=1.0.0.0, Culture=neutral, PublicKeyToken='public key token'"/>
</commands>
After copying the dll file to GAC recycle the AppPool and you are all set to go.
This is how you will use the command at the command line;

stsadm -o spupdatenavigation -siteurl http://server01:9090 -newurl http://server05:8888/recordscenter -targettitle "Records Center"

optionally, if you want to debug the code , you can provide additional key ‘-debug’ at the command.

The whole project can be found in this link.