Thursday, July 31, 2008

Publish Form Template as Content Type

In this post, I will show you how to publish a form template as a site content type. The advantages of publishing form template as content type as opposed to publish directly to form library are:
  • Site content types can be used by every library in the site collection
  • You can add multiple content types to one library.


1. Once you finished designing the form template. Click Publish Form Template from the Design Tasks task pane.
2. Choose to publish the form to a SharePoint server with or without InfoPath Forms Services, and click Next.
3. Enter the location of the SharePoint site.
4. Select Site Content Type and click Next.

5. Select Create a new content type and click Next.

6. Enter a name and description for the new content type.
7. Specify a document library to where you want to save the form template and click Next.

8. You can add, remove, or modify a site column. Click Next.

9. Click Publish and click Close.
10. Open InfoPath, customize a sample of Expense Report, save it as content type as shown above.
11. Go to Site Actions > Site Settings > Modify All Site Settings > Site content types > You can see the two content types you have just created.

12. Click Site Actions > View All Site Content > Create > Form Library > Specify a name for the form library > Create
13. Select Settings > Form Library Settings > Advanced settings > select Yes to allow management of content types > Click OK.

14. Click Add from existing site content types > Select the two content types > click Add.

15. Delete the default 'Form' content type.
16. When you click New, you will notice that there are now two content types you can choose from.

Tuesday, July 29, 2008

Publish Form Template

In this post, I will show you how to publish a form template to a form library.


1. Once you finished designing the form template. Click Publish Form Template from the Design Tasks task pane.
2. Choose to publish the form to a SharePoint server with or without InfoPath Forms Services, and click Next.

3. Enter the location of the SharePoint site.

4. We are going to create a document library and click Next.

5. Enter a name and description for the new document library.

6. You can determine which form data elements will be visible as columns in the document library.

7. Click Publish. Go to the site collection and locate the new library just created. Click New.

8. Fill out the form and Save the form back to the library.

Monday, July 28, 2008


Microsoft Office InfoPath 2007

  • Collect data in an efficient way.
  • Built using XML
  • Contains its own set of controls such as
    • repeating tables
    • repeating sections
    • choice groups.
    • You can create your own custom controls.
  • Controls that are not supported in browser-enabled form templates such as:
    • repeating recursive section
    • choice group
    • horizontal repeating table
  • You can publish the form template to the following locations:
  • Trust Levels
    • Security level determines which features are available to the InfoPath form.
    • Full trust context, or
    • Domain security context, or
    • Restricted security level context
      • Browser-enabled form cannot be published as a site content type in this context
  • Site content type
    • Can be used in more than one form library.
    • It is possible to use more than one form template per form library

Data Connection Files

  • One form template can have
    • one main data connection (primary connection) and
    • one or more secondary data connections.
  • One data connection file can be used by multiple form template
  • A data connection can submit to or receive data from an external data source
    such as
    • a web service,
    • SharePoint list, or
    • SQL Server database.
  • A data connection file is an XML file with an .xml or .udc(x) extension, where udc(x) stands Universal Data Connection.
  • Udc 1.0 files use the extension .odc, which stands for Office Data Connection. Udc 1.0 files cannot be used by InfoPath 2007.
  • Three ways to create data connection files:
    • via InfoPath
    • Excel
    • Create the UDC file manually via Notepad or UDC File Authoring Tool
      • Allows you to add authentication information to a data connection file.

Access Sharepoint List

  • You can access data that is stored in a SharePoint list within InfoPath form.
  • Data stored in a SharePoint list can be accessed via
    • SharePoint library
    • List data connection
      • Allows you to specify authentication information within the data connection itself.
    • SharePoint Lists web service
      • If use FBA, you cannot use the list directly. You need to use Lists web service.

Program InfoPath

  • You can update an InfoPath form programmatically and save it back to a SharePoint form library.
  • Steps
    • Read the InfoPath form into an XML document
    • Update the value in the XML document
    • Save the XML document as a InfoPath form to the form library.


Pro SharePoint 2007 Development Techniques

Friday, July 25, 2008

Text File Logger in VB.NET

I use Log4Net and Trace at work. But sometimes I use a simple logger to log any error in an quick solution. The best feature about this logger is that:

  • It is simple to use & understand
  • The log file is generated based on date and it shows the timestamp of the logging message.

Imports System.IO

Imports System.Reflection

Public Class Logger

Public Shared Sub log(ByVal message As String)

Dim strAssemblyPath As String = IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)

Dim logPath As String = Path.Combine(strAssemblyPath, "Log")

If Not Directory.Exists(logPath) Then


End If

Dim logFilePath As String = Path.Combine(logPath, _

String.Format("Log_{0}_{1}_{2}.log", DateTime.Now.Year.ToString, DateTime.Now.Month.ToString, DateTime.Now.Day.ToString))

Using sw As New StreamWriter(logFilePath, True)

sw.Write("[" + DateTime.Now + "] ")



End Using

End Sub

End Class

It is a coincidence that I run a search on Google which return me a very similar logging mechanism provided by Chris. His log class also caters for writing entries to event log. If you want to write entries to the event log, you need to watch out for the max size of the event log. You can check out his blog here.

Monday, July 21, 2008

Read data from Excel in VB.NET

The following code will show you how to read data from Excel file and to be able to check whether a specific column name exists in the excel file.

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="ExcelImport._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">

<html xmlns="" >

<head runat="server">

<title>Untitled Page</title>



<form id="form1" runat="server">


Column A: <asp:Label ID="lblColumnA" runat="server"></asp:Label><br />

Column B: <asp:Label ID="lblColumnB" runat="server"></asp:Label><br />

Column C: <asp:Label ID="lblColumnC" runat="server"></asp:Label><br />





Imports System.Data.OleDb

Partial Public Class _Default

Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Dim drExcel As OleDbDataReader = GetData()


While drExcel.Read()

lblColumnA.Text = drExcel("columnA").ToString()

lblColumnB.Text = drExcel("columnB").ToString()

'If IsColumnExist(drExcel, "columnv") Then

' lblColumnC.Text = drExcel("columnv").ToString()

'End If

If IsColumnExist("columnv") Then

lblColumnC.Text = drExcel("columnv").ToString()

End If

End While

Catch ex As Exception

Throw ex


If drExcel IsNot Nothing Then


End If

End Try

End Sub

'This function is not ideal

Private Function IsColumnExist(ByVal drExcel As OleDbDataReader, ByVal columnName As String) As Boolean


If drExcel(columnName) IsNot Nothing Then

End If

Catch ex As Exception

Return False

End Try

Return True

End Function

Private Function GetData() As OleDbDataReader

Dim cnAdo As New OleDbConnection()

Dim cmCommand As New OleDbCommand()


cnAdo.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties='Excel 8.0;HDR=YES';Data Source=C:\\Book1.xls;"


cmCommand.Connection = cnAdo

cmCommand.CommandText = "SELECT * FROM [Sheet1$]"

cmCommand.CommandType = CommandType.Text

Return cmCommand.ExecuteReader(CommandBehavior.CloseConnection)

Catch ex As Exception

If cnAdo.State = ConnectionState.Open Then


End If

Throw ex

End Try

End Function

Private Function IsColumnExist(ByVal columnName As String) As Boolean

Dim dt As DataTable

Dim restrictions As String() = {Nothing, Nothing, "Sheet1$", Nothing}

Dim connectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties='Excel 8.0;HDR=YES';Data Source=C:\\Book1.xls;"

Using connection As New OleDbConnection(connectionString)


dt = connection.GetSchema("Columns", restrictions)

End Using

For Each row As DataRow In dt.Rows

If row("COLUMN_NAME") IsNot DBNull.Value AndAlso row("COLUMN_NAME").ToString.Equals(columnName) Then

Return True

End If


Return False

End Function

End Class

This is the excel file that I used in this demo:

To figure out the column name (COLUMN_NAME) of the datatable, you will need to use the DataSet Visualizer, just double click the magnifier icon.

Reading Excel Worksheet and Column Schema Information Using ADO.NET 2.0 and GetSchema

Sunday, July 20, 2008

Shared Services

Shared Services Provider provides the following services:
  • Audiences
  • BDC
  • Excel Services
  • My Sites
  • Published Links
  • Personalization Links
  • Search
  • User Profiles


  • A SSP can host only a single Search Provider
  • Best practice is to implement a single SSP and a single search provider, multiple search providers complicates the SSP design.

User Profiles

  • Benefits: search people with skills about a subject
  • User profile information can be collected from:
    • LDAP: limited content information
    • Direct input from user:
      • Edit profile in personal feature page if do not have a My Site
      • Or My Site User details page
  • Properties of users can be used to
    • define audiences for targeting content
    • Or create custom search scopes

Publishing Links

  • It is for relevance.
  • Publishing links to Office applications such as Word, Excel or PowerPoint allows you to populate the "Save As" locations based on the who a user is, such as the AD group to which the user belong.
  • When you save a word doc, you can specify the sharepoint site folder. If you specify my site to be their default, they will pull information from the SSP every 24 hours.

Personalization Links

  • Personalization Links allows you to target content to My Site top link bars.
  • You can target information on top link bars to specific users based on the AD group.
  • You can also expose Publishing site navigation to your My Sites.


  • For increasing relevance.
  • Audiences allow you to target information to users based on their:
    • AD Groups
    • Sharepoint Groups
    • User Profile information
  • You can change the audience settings of your web part to show/hide information based on the user group who are viewing your web part.
  • Users cannot easily choose their audience on the fly.

My Sites

  • Advantages
    • Provide personal workspace for users
    • Collecting user information
    • Integration with Outlook through Meeting Workspaces


Microsoft® Office SharePoint® Server 2007 Best Practices

Sunday, July 13, 2008

Handling Sharepoint List Events

In May I have blogged about the Search Crawler Custom Workflow. What it basically does is that assume there is a newsletter list which contains a URL field, when a new URL is added to the newsletter list, the workflow will kick start and it will crawls the URL and put it into content source for search later.

In this post, I will talk about how you can handle the newsletter list event to delete the content source when an associated URL is deleted. You can handle the List level event as well as List Item level event. There are Synchronous Events and Asynchronous Events, please take a look at my
blog for more list event details.


1. Create a C# class library and create the ItemEventReceivers which handles the ItemDeleting event for the newsletter list. Note that the "external newsletter" in the code below is the URL field name of the newsletter list.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.SharePoint;

using Microsoft.Office.Server.Search.Administration;

Namespace ATSListReceiver


class ItemEventReceivers : SPItemEventReceiver


public override void ItemDeleting(SPItemEventProperties properties)



//Disable events to prevent an endless loop of event handling!


//******************Step 1: Get the site search context*****************************

//string strURL = @"";

SearchContext context;

using (SPSite site = new SPSite(strURL))


context = SearchContext.GetContext(site);


//******************Step 2: Get the Newletter url newsletter list*****************************

String url = properties.ListItem["external newsletter"].ToString();

url = url.Substring(0, url.IndexOf(','));

//******************Step 3: Delete the content source *****************************

Content sspContent = new Content(context);

ContentSourceCollection sspContentSources = sspContent.ContentSources;

if (sspContentSources.Exists(url))


ContentSource cs = sspContentSources[url];







2. Give this project a strong name and deploy this assembly to the GAC.

3. Create a console application to add the handler to the newsletter list.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Microsoft.SharePoint;

Namespace ATSAddHandler


Class Program


static void Main(string[] args)




public static void Add_EventHandler_To_Newsletter()




string assemblyName = "ATSListReceiver, Version=, Culture=neutral, PublicKeyToken=dfb38e12474cae53";

string className = "ATSListReceiver.ItemEventReceivers";

SPSite rootSite = new SPSite("");

SPWeb web = rootSite.AllWebs[""];

web.AllowUnsafeUpdates = true;

SPList newsletter = web.Lists["ATSNewsletter"];

newsletter.EventReceivers.Add(SPEventReceiverType.ItemDeleting, assemblyName, className);








4. For the purpose of this demo, I used console application, you can also do this in you STSDEV solution and implements this as a List Receiver.


Sharepoint 2007: List Events Practical Example: Creating a rigged survey!!

Saturday, July 12, 2008

Using User Control in Sharepoint Web Parts

Web parts are more complicated to implement than user controls. So often people will desire to use user control in web parts. In this case, I will create a user control which contains a repeater to show some information within a custom news list in a MOSS site.


1. Create a user control called News.ascx. Make sure you specify this user control to inherit from the solution assembly. By the way, if you do not have a solution set up yet, I recommend you try out
STSDEV, this is what I am using in this example.


<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="News.ascx.cs" Inherits="ATSDeploymentSolution.News,ATSDeploymentSolution, Version=, Culture=neutral, PublicKeyToken=ca6621b7467269f9" %>

<asp:Repeater ID="repNews" runat="server">





<div><%# Eval("ID") %>: <%# Eval("Title") %></div>








// <auto-generated>

// This code was generated by a tool.

// Runtime Version:2.0.50727.1433


// Changes to this file may cause incorrect behavior and will be lost if

// the code is regenerated.

// </auto-generated>


Namespace ATSDeploymentSolution


/// <summary>

/// SimpleList class.

/// </summary>

/// <remarks>

/// Auto-generated class.

/// </remarks>

public partial class News {

protected global::System.Web.UI.WebControls.Repeater repNews;




using System;

using System.Data;

using System.Configuration;

using System.Collections;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

using Microsoft.SharePoint;

Namespace ATSDeploymentSolution


public partial class News : System.Web.UI.UserControl


protected void Page_Load(object sender, EventArgs e)


if (!IsPostBack)





private void Bind()


using (SPSite site = new SPSite("http://w2k3sharepoint:43490"))


using (SPWeb web = site.OpenWeb())


SPList list = web.Lists["ATSNews"];

repNews.DataSource = list.Items.GetDataTable();







2. Put this user control under the CONTROLTEMPLATES folder which is used to store all the user controls under the 12 hive. You can also notice from this image that I have created a feature called ATSDeploymentSolution which contains a bunch of web parts. ATSHomeNewsWebPart is the web part we will use to load the user control from.

3. Modify the manifest.xml to include this template file. The modified part is highlighed in red.

<?xml version="1.0" encoding="utf-8"?>

<!--Manifest created STSDEV utility at 22/05/2008 11:42:17 AM-->

<Solution SolutionId="4508B2DF-131A-4C52-A806-7C92AFD703A3" ResetWebServer="True" xmlns="">

<!--Feature Manifest files-->


<FeatureManifest Location="ATSDeploymentSolution\feature.xml" />

<FeatureManifest Location="ATSWorkflow\feature.xml" />

<FeatureManifest Location="ATSNewsletterListEvents\feature.xml" />


<!--TEMPLATE files-->


<TemplateFile Location="IMAGES\ATSDeploymentSolution\AfricanPith32.gif" />

<TemplateFile Location="IMAGES\ATSDeploymentSolution\Thumbs.db" />

<TemplateFile Location="ControlTemplates\SimpleList.ascx" />

<TemplateFile Location="ControlTemplates\News.ascx" />


<!--Assembly files-->


<Assembly Location="ATSDeploymentSolution.dll" DeploymentTarget="GlobalAssemblyCache">


<SafeControl Assembly="ATSDeploymentSolution, Version=, Culture=neutral, PublicKeyToken=ca6621b7467269f9" Namespace="ATSDeploymentSolution" TypeName="*" Safe="True" />





4. Specify the path of news.ascx in the SolutionPackage.ddf. The modified part is highlighed in red.

; Generated by STSDEV at 22/05/2008 11:42:17 AM


.Set CabinetNameTemplate=ATSDeploymentSolution.wsp

.set DiskDirectoryTemplate=CDROM

.Set CompressionType=MSZIP

.Set UniqueFiles=off

.Set Cabinet=on

.Set DiskDirectory1=DeploymentFiles

;*** Solution manifest


;*** Assembly files


;*** add files for ATSDeploymentSolution feature

.Set DestinationDir=ATSDeploymentSolution



;*** add files for ATSDeploymentSolution\WebParts feature

.Set DestinationDir=ATSDeploymentSolution\WebParts








;*** add files for ATSWorkflow feature

.Set DestinationDir=ATSWorkflow



;*** add files for ATSNewsletterListEvents feature

.Set DestinationDir=ATSNewsletterListEvents



;*** Begin TemplateFiles section ***


.Set DestinationDir=IMAGES\ATSDeploymentSolution



.Set DestinationDir="ControlTemplates"



5. Create the web part to load the user control we created.

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Text;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

Namespace ATSDeploymentSolution


public class ATSHomeNewsWebPart : WebPart


News _news = null;

protected override void CreateChildControls()



_news = (News)Page.LoadControl("~/_controltemplates/News.ascx");





6. Create the webpart xml file and put it under the WebParts folder of the ATSDeploymentSolution Feature.

<?xml version="1.0" encoding="utf-8"?>

<!--Created by STSDEV at 8/05/2008 10:56:56 AM-->


<webPart xmlns="">


<type name="ATSDeploymentSolution.ATSHomeNewsWebPart, ATSDeploymentSolution, Version=, Culture=neutral, PublicKeyToken=ca6621b7467269f9" />

<importErrorMessage>Error importing Web Part</importErrorMessage>




<property name="Title" type="string">ATSHomeNewsWebPart</property>

<property name="Description" type="string">A webpart for news on the home page.</property>

<property name="ChromeState" type="chromestate">Normal</property>

<property name="AllowZoneChange" type="bool">True</property>

<property name="AllowHide" type="bool">True</property>

<property name="ExportMode" type="exportmode">All</property>





7. Add ATSHomeNewsWebPart.webpart to the SolutionPackage.ddf file. This is highlighted in blue in the above code.

8. Add ATSHomeNewsWebPart.webpart to the Feature.xml of the ATSDeploymentSolution Feature. Highlighted in red.

<?xml version="1.0" encoding="utf-8"?>

<!--Created by STSDEV at 8/05/2008 11:12:24 AM-->



Title="ATS Web Parts Feature"

Description="This SharePoint solution was created by the Sam Fu."




ImageUrl="ATSTestSolution\AfricanPith32.gif" xmlns="">



Location="WebParts.xml" />


Location="WebParts\ATSCompanySearchWebPart.webpart" />


Location="WebParts\ATSGlobalSearchWebPart.webpart" />


Location="WebParts\ATSNewsSearchWebPart.webpart" />


Location="WebParts\ATSNewsletterSearchWebPart.webpart" />


Location="WebParts\ATSEventSearchWebPart.webpart" />


Location="WebParts\ATSHidePageWebPart.webpart" />


Location="WebParts\ATSHomeNewsWebPart.webpart" />



9. Add ATSHomeNewsWebPart.webpart to the WebParts.xml which is the ElementManifest of the ATSDeploymentSolution Feature. Highlighted in red.

<?xml version="1.0" encoding="utf-8"?>

<!--Created by STSDEV at 8/05/2008 10:56:56 AM-->

<Elements xmlns="">

<Module Name="ATSDeploymentSolution" List="113" Url="_catalogs/wp" Path="WebParts" RootWebOnly="True">

<File Url="ATSCompanySearchWebPart.webpart" Type="GhostableInLibrary">

<Property Name="Group" Value="ATSDeploymentSolution" />


<File Url="ATSGlobalSearchWebPart.webpart" Type="GhostableInLibrary">

<Property Name="Group" Value="ATSDeploymentSolution" />


<File Url="ATSNewsSearchWebPart.webpart" Type="GhostableInLibrary">

<Property Name="Group" Value="ATSDeploymentSolution" />


<File Url="ATSNewsletterSearchWebPart.webpart" Type="GhostableInLibrary">

<Property Name="Group" Value="ATSDeploymentSolution" />


<File Url="ATSEventSearchWebPart.webpart" Type="GhostableInLibrary">

<Property Name="Group" Value="ATSDeploymentSolution" />


<File Url="ATSHidePageWebPart.webpart" Type="GhostableInLibrary">

<Property Name="Group" Value="ATSDeploymentSolution" />


<File Url="ATSHomeNewsWebPart.webpart" Type="GhostableInLibrary">

<Property Name="Group" Value="ATSDeploymentSolution" />




10. Since I have deployed the solution before, I will choose DebugReploy from the Visual studio and build the solution. If you have deployed this web part before, you need to choose DebugUpgrade and build.

11. Add the web part to the page you want. This is the News List I had:

Here is the result:

Using user control in web parts

  • As you can see from the above example, using user control in web parts works just fine.
  • All you have to do is in CreateChildControls, load the user control and add it to the control tree.
  • And In OnPreRender, you can set public properties of the user control just like any other control.
  • Pros of using user control in web parts
    • Re-use user controls from other application
    • Easier for development than web parts
  • Cons
    • You now have a dependency between the news.ascx file and the solution assembly. If news.ascx is used in lots of different web parts, you may have a versioning issue.
  • You can also use SmartPart for loading user control in MOSS. It allows you to choose which user control to load at run time in the browser. Of course, you could extend the above example to do the same thing as well.

Friday, July 11, 2008

Debugging .NET Framework Source Code

Since the releasing of Source Code for the .NET Framework Libraries, you are now able to debug the .NET Framework source code.


1. Open Visual Studio 2008 > Tools > Options > Debugging > General > uncheck "Enable Just My Code" > check "Enable Source Server Support"

2. Go to Tools > Options > Debugging > Symbols > add this symbol file location > specify the cache location > check the "Search the above locations only when symbols are loaded manually" option.

3. Fire up debugging > right click the code line you wanted to debug in the call stack > click Load Symbols > click F11 > now you can step into the .NET Framework source code and debug .


Configuring Visual Studio to Debug .NET Framework Source Code

Close All the tabs in Visual Studio 2008

PowerCommands 1.1 is a set of useful extensions for the Visual Studio 2008 adding additional functionality to various areas of the IDE.

PowerCommands allows you to:
  • Close All the tabs in Visual Studio 2008
  • Copy reference dll from one project to another
  • Open file's containing folder from Solution Explorer
  • A bunch of other useful functions...

PowerCommands for Visual Studio 2008

Thursday, July 10, 2008

.NET Generic






System.Collections.Generic Namespace