Friday, January 25, 2008

MOSS 2007 Tips and Trick January 2008

Here are some MOSS 2007 tips I want to share from my previous experience.
Problem : How to insert / update a list item without write permission

You can use this code

SPSecurity.RunWithElevatedPrevileges(delegate(){
//place your code here
});

Your code above will be executed using admin rights. So you can insert / update a list item even though current login doesn't have permission to insert / update.

Note:
Remind that you cannot call method Update of SPListItem class inside the code above. It will throw error like this : "Operation is not valid due to the current state of the object".

I have googled about this problem and found a way to solve it, thanks to this great post.
The point is :You must not call the SPListItem.Update inside the RunWithElevatedPrivileges block. Instead you should only instantiate the SPSite or SPWeb there and call Update afterwards.

Here is the sample code :


SPSite site = new SPSite("http://moss.denallix.com");
SPWeb elevatedRootWeb = null;
SPWeb web = site.OpenWeb();
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite elevatedSite = new SPSite(web.Site.ID))
{
elevatedRootWeb = elevatedSite.RootWeb;
}
});
SPList myList = elevatedRootWeb.Lists["MyList"];
try
{
elevatedRootWeb.AllowUnsafeUpdates = true;
SPListItem myNewItem = myList.Items.Add();
myNewItem["Column1"] = "Column1Value";
myNewItem["Column2"] = "Column2Value";
myNewItem["Column3"] = "Column3Value";
myNewItem.Update();
}
catch (Exception ex)
{
EventLog.WriteEntry("Error", ex.Message.ToString(), EventLogEntryType.Error);
}


MOSS 2007 Tips : Dynamic Webpart Installer Class

Usually when we deploy a web part to MOSS , we have to develop 2 times. One for the installer class , one for the user control (ASCX) itself. A friend of mine has made a dynamic installer class so that we just have to set the ASCX path every time we want to make a web part. Here is the code.



using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

namespace DynamicUserControlWebPart
{
public class DynamicUserControlWebPart : WebPart
{
private string _usercontrolvirtualpath;
private string ErrorMessage;
Control _control = null;

[WebBrowsable(true)]
[Personalizable(true)]
[WebDescription("Dynamic User Control WebPart")]
[WebDisplayName("Dynamic User Control WebPart")]
public string UserControlVirtualPath
{
get { return _usercontrolvirtualpath; }
set { _usercontrolvirtualpath = value; }
}

protected override void CreateChildControls()
{
this.Controls.Clear();
try
{
_control = this.Page.LoadControl(_usercontrolvirtualpath);
this.Controls.Add(_control);
}
catch (System.Exception ex)
{
ErrorMessage = ex.Message;
}
}

protected override void RenderChildren(HtmlTextWriter writer)
{
if (_control != null)
{
_control.RenderControl(writer);
}
else
{
writer.Write(ErrorMessage);
}
}
}
}


- Deploy this Web Part.
- Place your *.ASCX and *.ASCX.CS files in the moss folder (ex: C:\Inetpub\wwwroot\wss\VirtualDirectories\81\MyUserControl ).
- After adding this webpart to a page , just click Edit - Modify Shared Web Part.
- And then set the ASCX path to the property in the right column , Miscellaneous category. (ex : ~/MyUserControl/myUC.ascx )
- See the result.

Monday, January 14, 2008

Microsoft Infopath 2007 Tips And Trick January 14, 2008

In my last project, I use Microsoft Infopath 2007 intensively. In the beginning, I have difficulties in navigating Microsoft Infopath 2007 data source because all data is stored in XML. Here are the codes I often use when dealing with Infopath.

Most of my codes use XPathNavigator class, so don't forget to add this reference in the using section.I assume you place this code in Infopath code( example : in Form Load event)

using System.Xml;
using System.Xml.XPath;

Common problem #1 : Get Microsoft Infopath 2007 Data Source XML value
Suppose you have a data source like this :To get the value of name, you can use this code.

XPathNavigator root = MainDataSource.CreateNavigator();
XPathNavigator nameNode = root.SelectSingleNode("/my:myFields/my:Name",NamespaceManager);

string name = nameNode.Value;

note : the parameter in SelectSingleNode method is a XPath query. You can get this by right-clicking the data source you want, click "Copy XPath"

Common problem #2 : Set A Microsoft Infopath 2007 Data Source XML Value
Suppose you want to set the name to a value "newvalue". You can use this code.

XPathNavigator root = MainDataSource.CreateNavigator();
XPathNavigator nameNode = root.SelectSingleNode("/my:myFields/my:Name",NamespaceManager);

nameNode.SetValue("newvalue");
Common problem #3 : Loop through a repeating table in Microsoft Infopath 2007
Suppose you have a data source like thisThen , to get the value of field1, field2, and field3 iteratively, use this code.

XPathNavigator domNav = MainDataSource.CreateNavigator();
XPathNodeIterator rows = domNav.Select("/my:myFields/my:table/my:row", NamespaceManager);

while (rows.MoveNext())
{
string field1 = rows.Current.SelectSingleNode("my:field1", NamespaceManager).Value;
string field2 = rows.Current.SelectSingleNode("my:field2", NamespaceManager).Value;
string field3 = rows.Current.SelectSingleNode("my:field3", NamespaceManager).Value;
}
Common problem #4 : Add a row to Microsoft Infopath 2007 repeating table

If you have a repeating table like thiswith this data sourceYou can add a row to this repeating table by using this code.

string myNamespace = NamespaceManager.LookupNamespace("my");
using (XmlWriter writer = MainDataSource.CreateNavigator().SelectSingleNode(
"/my:myFields/my:group1", NamespaceManager).AppendChild())
{
writer.WriteStartElement("group2", myNamespace);
writer.WriteElementString("field1", myNamespace, "Cell 1");
writer.WriteElementString("field2", myNamespace, "Cell 2");
writer.WriteElementString("field3", myNamespace, "Cell 3");
writer.WriteEndElement();
writer.Close();
}
Article #3 was taken from this great site . Article #4 was taken from the another great site.

Note that NamespaceManager is a property which exists only in Infopath code. To use these code in another place, such as K2 Blackpearl, you have to define the NamespaceManager by yourself. You can use this method.

public XmlNamespaceManager InitNamespaceManager(XmlDocument xmlDOMDoc)
{
XmlNamespaceManager xnmMan;
xnmMan = new XmlNamespaceManager(xmlDOMDoc.NameTable);
foreach (XmlAttribute nsAttr in xmlDOMDoc.DocumentElement.Attributes)
{
if (nsAttr.Prefix=="xmlns")
xnmMan.AddNamespace(nsAttr.LocalName,nsAttr.Value);
}
return xnmMan;
}
and use this code to create your NamespaceManager ( I assume you use K2 Blackpearl and Microsoft Infopath 2007)

XmlDocument doc = new XmlDocument();
string xmlString = K2.ProcessInstance.XmlFields["MyInfopathForm"].Value;
doc.LoadXml(xmlString);
XmlNamespaceManager NamespaceManager = InitNamespaceManager(doc);

I took this code from this great blog.
All credits should go to the original poster.

Hope this article helps:)

Friday, January 11, 2008

K2 Tips And Trick January 2008

In last few months, I encountered some common problem in K2 blackpearl development. I want to share what I've got:) I assume you are using Virtual PC given by K2 (DENALLIX)

Common problem #1: Get Active Directory's Full Name from Login Name
case : Suppose you want to get Codi's full name from active directory (login name : denallix\codi). You can use this code.

public string GetFullName(string userID)
{
DirectoryEntry entry = new DirectoryEntry("LDAP://DENALLIX.COM");
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.Filter = "(SAMAccountName=" + userID + ")";
searcher.PropertiesToLoad.Add("displayname");

SearchResult result = searcher.FindOne();

return result.Properties["displayname"][0].ToString();
}

Sample code : string myFullName = GetFullName("codi"); //returns Codi

Common problem #2: Get Active Directory's Email from Login Name
case : Suppose you want to get Codi's email from active directory (login name : denallix\codi).

public string GetEmail(string userID)
{
DirectoryEntry entry = new DirectoryEntry("LDAP://DENALLIX.COM");
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.Filter = "(SAMAccountName=" + userID + ")";
searcher.PropertiesToLoad.Add("mail");

SearchResult result = searcher.FindOne();

return result.Properties["mail"][0].ToString();
}
Sample code : string myFullName = GetEmail("codi"); //returns codi@denallix.com

Common problem #3: Insert a List Item to a Sharepoint List
case : Suppose you want to insert a list item to a Sharepoint List named "MyList". You can use this code.

public void InsertMyList(string Column1Value, string Column2Value, string Column3Value)
{
SPSite site = new SPSite("http://moss.denallix.com");
SPWeb web = site.OpenWeb();
web.AllowUnsafeUpdates = true;
SPList myList = web.Lists["MyList"];
SPListItem myNewItem = myList.Items.Add();
myNewItem["Column1Title"] = Column1Value;
myNewItem["Column2Title"] = Column2Value;
myNewItem["Column3Title"] = Column3Value;
myNewItem.Update();
}
Sample code : InsertMyList("Column1Value","Column2Value","Column3Value");

Common problem #4: Get a List Item From a Sharepoint List with a condition (using CAML query)
case : Suppose you want to get Column2 Value from a list item where the Column1 Value is "Column1Value" . You can use this code.

public string GetColumn2ValueFromMyList(string Column1Value)
{
SPSite site = new SPSite("http://moss.denallix.com");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["MyList"];
SPQuery query = new SPQuery();
query.Query = "<Where><Eq><FieldRef Name='Column1Title' /><Value Type='Text'>" + Column1Value + "</Value></Eq></Where>";
SPListItemCollection listItem = list.GetItems(query);
if (listItem.Count > 0)
{
return listItem[0]["Column2Title"].ToString();
}
else
{
return string.Empty;
}
}
sample code : string myColumn2Value = GetColumn2ValueFromMyList("Column1Value");
Some bonus from this week's tips and trick.
My friend had found a way to validate email format in Microsoft Infopath 2007 browser-enabled form. You can add a data validation matching this pattern:
.+@\p{L}+\.\p{L}+\.*.*

This pattern can handle agus123@yahoo.com , agus.santoso@yahoo.co.id , or agus_santoso@yahoo.co.id. I haven't tested it for all email format. Just inform me if you have better pattern. I will add it to this post. Thank you :)