My way to deploy Sharepoint Solution

May 16th, 2007 by unclaimed blog

VS.NET extension for Sharepoint 2007 is a great tool to create webparts, features and site definitions. But I found it's not very not that easy to package the solution and deploy to production servers. I need to create manifest.xml and a ddf file and have to use makecab.exe tool. I don't why MS doesn't auotmatically genereate in the solution.

And my simple way to deploy the solution is

  • Find the setup.bat and solution folder under binDebug (usually it's generated after you build and deploy the solution in VS.NET)
  • Copy your release version dlls to solution folder 
  • Open setup.bat and change "TargetUrl" to your production server.
  • Copy these file and folder to production
  • Run "setup /i"

and it works great.

I've also find a Sharepont Solution Installer tool in here:

http://blog.mondosoft.com/ontolica/archive/2007/03/14/Generic-SharePoint-2007-Solution-Installer.aspx

it sounds a nice tool but I didn't try it yet. 

 

My way to deploy Sharepoint Solution

May 16th, 2007 by unclaimed blog

VS.NET extension for Sharepoint 2007 is a great tool to create webparts, features and site definitions. But I found it's not very not that easy to package the solution and deploy to production servers. I need to create manifest.xml and a ddf file and have to use makecab.exe tool. I don't why MS doesn't auotmatically genereate in the solution.

And my simple way to deploy the solution is

  • Find the setup.bat and solution folder under binDebug (usually it's generated after you build and deploy the solution in VS.NET)
  • Copy your release version dlls to solution folder 
  • Open setup.bat and change "TargetUrl" to your production server.
  • Copy these file and folder to production
  • Run "setup /i"

and it works great.

I've also find a Sharepont Solution Installer tool in here:

http://blog.mondosoft.com/ontolica/archive/2007/03/14/Generic-SharePoint-2007-Solution-Installer.aspx

it sounds a nice tool but I didn't try it yet. 

 

Update WSS 3.0 User Profile Programmatically

December 5th, 2006 by unclaimed blog

In WSS 3.0, there is a special list `User Information List' for user's profile information. When a user is added to the Sharepoint site, a list item is automatically created in this list. To update the user's information in `User Information List', for instance, to update the user's photo, I am using following code and it works fine:

 

 

Microsoft.SharePoint.SPList list = web.Lists["User Information List"];

Microsoft.SharePoint.SPUser u = web.SiteUsers["domain\user1"];

Microsoft.SharePoint.SPListItem it = list.Items.GetItemById(u.ID);

 

it["Picture"] =”http://sharepointApp/sites/wss/photos/abc.jpg”;

it.Update();

 

Also, you are able to add a custom field to user profile like this:

 

Microsoft.SharePoint.SPList list = web.Lists["User Information List"];
if (!list.Fields.ContainsField("Favorites"))
{
         list.Fields.Add("Favorites", SPFieldType.Text, false);
         list.Update();
}

 

Update WSS 3.0 User Profile Programmatically

December 5th, 2006 by unclaimed blog

In WSS 3.0, there is a special list `User Information List' for user's profile information. When a user is added to the Sharepoint site, a list item is automatically created in this list. To update the user's information in `User Information List', for instance, to update the user's photo, I am using following code and it works fine:

 

 

Microsoft.SharePoint.SPList list = web.Lists["User Information List"];

Microsoft.SharePoint.SPUser u = web.SiteUsers["domain\user1"];

Microsoft.SharePoint.SPListItem it = list.Items.GetItemById(u.ID);

 

it["Picture"] =”http://sharepointApp/sites/wss/photos/abc.jpg”;

it.Update();

 

Also, you are able to add a custom field to user profile like this:

 

Microsoft.SharePoint.SPList list = web.Lists["User Information List"];
if (!list.Fields.ContainsField("Favorites"))
{
         list.Fields.Add("Favorites", SPFieldType.Text, false);
         list.Update();
}

 

VMWare Server released and it's free, too

July 14th, 2006 by unclaimed blog

VMWare Server was released after serveral months beta. You can free register and download it from here. It looks have more features than MS Virtual Server R2, which is also free. And from many comparison articles in Internet, it should have better performance than Virtual Server.

VMWare Server released and it's free, too

July 14th, 2006 by unclaimed blog

VMWare Server was released after serveral months beta. You can free register and download it from here. It looks have more features than MS Virtual Server R2, which is also free. And from many comparison articles in Internet, it should have better performance than Virtual Server.

Topic Assistant is not in MOSS 2007

July 13th, 2006 by unclaimed blog

I noticed the Topic Assistant is not in MOSS 2007 any more. In SPS 2003, you can set up a training set in an area, and the Topic Assistant will automatically categorize and assocaite the portal content to the area. Although I know there are not too many people really use this feature but it seems to be a helpful tool when you want to organize massive content to the company's taxonomies.

Don't know why MS remove it instead of providing an improved equivalent tool.

 

Topic Assistant is not in MOSS 2007

July 13th, 2006 by unclaimed blog

I noticed the Topic Assistant is not in MOSS 2007 any more. In SPS 2003, you can set up a training set in an area, and the Topic Assistant will automatically categorize and assocaite the portal content to the area. Although I know there are not too many people really use this feature but it seems to be a helpful tool when you want to organize massive content to the company's taxonomies.

Don't know why MS remove it instead of providing an improved equivalent tool.

 

Create custom field type in WSS V3

July 10th, 2006 by unclaimed blog

WSS v3 supports creating custom field type with OM, and you have total control on its internal data storage, editing and display. I have tested it today by creating a custom phone number field with 3 sub-fields: country code, area code and phone number.

1. Create a ascx control and its code behind for editing

In order to make the custom field type editable in form view, we need to custom rendering user control for this new field type. At first, we need to create an ascx file with a Sharepoint RenderingTemplate control on it. See the code below.

<%@ Control Language="C#" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<SharePoint:RenderingTemplate ID="PhoneNumberFieldRendering" runat="server">
    <Template>
        +<asp:TextBox ID="txtCountryCode" runat="server" MaxLength="3" Size="3"></asp:TextBox>(<asp:TextBox ID="txtAreaCode" runat="server" MaxLength="3" Size="3"></asp:TextBox>)<asp:TextBox ID="txtNumber" runat="server" MaxLength="8" Size="8"></asp:TextBox>
    </Template>
</SharePoint:RenderingTemplate>

Then we need to implement its code behind class. The class must derives BaseFieldControl and overrides the property Value to set the three fields of a phone number into three segments in SPFieldMultiColumnValue object.

    public class PhoneNumberFieldControl : Microsoft.SharePoint.WebControls.BaseFieldControl
    {
        protected System.Web.UI.WebControls.TextBox txtCountryCode;
        protected System.Web.UI.WebControls.TextBox txtAreaCode;
        protected System.Web.UI.WebControls.TextBox txtNumberCode;

        protected override string DefaultTemplateName
        {
            get
            {
                return "PhoneNumberFieldControl";
            }
        }

        public override object Value
        {
            get
            {
                EnsureChildControls();
                Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = new Microsoft.SharePoint.SPFieldMultiColumnValue(3);
                phoneNumberValue[0] = txtCountryCode.Text.Trim();
                phoneNumberValue[1] = txtAreaCode.Text.Trim();
                phoneNumberValue[2] = txtNumberCode.Text.Trim();
                return phoneNumberValue;
            }
            set
            {
                EnsureChildControls();
                Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = value as Microsoft.SharePoint.SPFieldMultiColumnValue;
                txtCountryCode.Text = phoneNumberValue[0];
                txtAreaCode.Text = phoneNumberValue[1];
                txtNumberCode.Text = phoneNumberValue[2];
            }
        }

        public override void Focus()
        {
            EnsureChildControls();
            txtCountryCode.Focus();
        }

        protected override void CreateChildControls()
        {
            if (Field == null) return;

            base.CreateChildControls();

            if (ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.Display)
                return;

            txtCountryCode = (System.Web.UI.WebControls.TextBox)FindControl("txtCountryCode");
            if (txtCountryCode == null) throw new NullReferenceException("txtCountryCode is null. Corrupted PhoneNumberFieldControl.ascx file.");
            txtCountryCode.TabIndex = TabIndex;
            txtCountryCode.CssClass = CssClass;
            txtCountryCode.ToolTip = Field.Title + " Country Code";

            txtAreaCode = (System.Web.UI.WebControls.TextBox)FindControl("txtAreaCode");
            if (txtAreaCode == null) throw new NullReferenceException("txtAreaCode is null. Corrupted PhoneNumberFieldControl.ascx file.");
            txtAreaCode.TabIndex = TabIndex;
            txtAreaCode.CssClass = CssClass;
            txtAreaCode.ToolTip = Field.Title + " Area Code";

            txtNumberCode = (System.Web.UI.WebControls.TextBox)FindControl("txtNumberCode");
            if (txtNumberCode == null) throw new NullReferenceException("txtNumberCode is null. Corrupted PhoneNumberFieldControl.ascx file.");
            txtNumberCode.TabIndex = TabIndex;
            txtNumberCode.CssClass = CssClass;
            txtNumberCode.ToolTip = Field.Title + " Phone Number";
            if (ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.New)
            {
                txtCountryCode.Text = Field.GetCustomProperty("DefaultCountryCode").ToString();
                txtAreaCode.Text = Field.GetCustomProperty("DefaultAreaCode").ToString();
                txtNumberCode.Text = Field.GetCustomProperty("DefaultNumber").ToString();
            }
        }
    }

2. Create a custom field type class

The custom field type must inherit the base class SPField. In my test, I wrote following class derives SPFieldMultiColumn which is a subclass of SPField but supports multiple sub-columns. GetValidatedString overridden method checks the input object value and return its string value if it's correct. GetFieldValue method is to create a SPFieldMultiColumnValue object by the input string. FieldRenderingControl property returns the user control we created in step 1.

public class PhoneNumberField : Microsoft.SharePoint.SPFieldMultiColumn
    {
        public PhoneNumberField(Microsoft.SharePoint.SPFieldCollection fields, string fieldName)
            : base(fields, fieldName)
        {
        }

        public PhoneNumberField(Microsoft.SharePoint.SPFieldCollection fields, string typeName, string displayName)
            : base(fields, typeName, displayName)
        {
        }

        public override string GetValidatedString(object value)
        {
            Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = value as Microsoft.SharePoint.SPFieldMultiColumnValue;
            if (phoneNumberValue == null)
                return String.Empty;
            if(String.IsNullOrEmpty(phoneNumberValue[0]) || String.IsNullOrEmpty(phoneNumberValue[1]) || String.IsNullOrEmpty(phoneNumberValue[2]))
                throw new Microsoft.SharePoint.SPFieldValidationException(Microsoft.SharePoint.SPResource.GetString(Microsoft.SharePoint.Strings.MissingRequiredField));

            return value.ToString();
        }

        public override object GetFieldValue(string value)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = new Microsoft.SharePoint.SPFieldMultiColumnValue(value);
            return phoneNumberValue;
        }

        public override Microsoft.SharePoint.WebControls.BaseFieldControl FieldRenderingControl
        {
            get
            {
                Microsoft.SharePoint.WebControls.BaseFieldControl phoneNumberFieldControl = new PhoneNumberFieldControl();
                return base.FieldRenderingControl;
            }
        }
    }

3. Create custom Field Type Definition

The custom type must include a custom field type definition. It's an XML file with file name fldtypes_*.xml. I named my phone number field definition file as fldtypes_phonenumber.xml. The detail schema is in http://msdn2.microsoft.com/en-us/library/ms415141.aspx

<?xml version="1.0" encoding="utf-8"?>
<FieldTypes>
  <FieldType>
    <Field Name="TypeName">PhoneNumber</Field>
    <Field Name="ParentType">MultiColumn</Field>
    <Field Name="TypeDisplayName">Phone Number</Field>
    <Field Name="TypeShortDescription">Phone Number</Field>
    <Field Name="UserCreatable">TRUE</Field>
    <Field Name="ShowInListCreate">TRUE</Field>
    <Field Name="ShowInSurveyCreate">TRUE</Field>
    <Field Name="ShowInDocumentLibraryCreate">TRUE</Field>
    <Field Name="ShowInColumnTemplateCreate">TRUE</Field>
    <Field Name="FieldTypeClass">WSSFieldDemo.PhoneNumberField,WSSFieldDemo,Version=1.0.0.0,Culture=neutral,PublicKeyToken=5cca1e4ab4efce28</Field>
    <PropertySchema>
      <Fields>
        <Field Name="DefaultCountryCode" DisplayName="Default Country Code" MaxLength="3" DisplaySize="3" Type="Text">
          <Default>1</Default>
        </Field>
        <Field Name="DefaultAreaCode" DisplayName="Default Area Code" MaxLength="3" DisplaySize="3" Type="Text">
          <Default>416</Default>
        </Field>
        <Field Name="DefaultNumber" DisplayName="Default Phone Number" MaxLength="8" DisplaySize="8" Type="Text">
          <Default>5325554</Default>
        </Field>
      </Fields>
    </PropertySchema>
    <RenderPattern Name="DisplayPattern">
      <Switch>
        <Expr>
          <Column />
        </Expr>
        <Case Value="" />
        <Default>
          <HTML><![CDATA[+]]></HTML>
          <Column SubColumnNumber="0" HTMLEncode="TRUE" />
          <HTML><![CDATA[(]]></HTML>
          <Column SubColumnNumber="1" HTMLEncode="TRUE" />
          <HTML><![CDATA[)]]></HTML>
          <Column SubColumnNumber="2" HTMLEncode="TRUE" />
        </Default>
      </Switch>
    </RenderPattern>
  </FieldType>
</FieldTypes>

4. Deployment

The final step is to deploy the assembly, user control and the field definition xml. It includes following steps:

1. Build the solution and sign the assembly
2. Put the assembly into GAC
3. Copy the user control to program files…web server extensions12 emplatecontroltemplates
4. Copy fldtypes_phonenumber.xml to program files…web server extensions12 emplatexml
5. iisreset.

Create custom field type in WSS V3

July 10th, 2006 by unclaimed blog

WSS v3 supports creating custom field type with OM, and you have total control on its internal data storage, editing and display. I have tested it today by creating a custom phone number field with 3 sub-fields: country code, area code and phone number.

1. Create a ascx control and its code behind for editing

In order to make the custom field type editable in form view, we need to custom rendering user control for this new field type. At first, we need to create an ascx file with a Sharepoint RenderingTemplate control on it. See the code below.

<%@ Control Language="C#" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<SharePoint:RenderingTemplate ID="PhoneNumberFieldRendering" runat="server">
    <Template>
        +<asp:TextBox ID="txtCountryCode" runat="server" MaxLength="3" Size="3"></asp:TextBox>(<asp:TextBox ID="txtAreaCode" runat="server" MaxLength="3" Size="3"></asp:TextBox>)<asp:TextBox ID="txtNumber" runat="server" MaxLength="8" Size="8"></asp:TextBox>
    </Template>
</SharePoint:RenderingTemplate>

Then we need to implement its code behind class. The class must derives BaseFieldControl and overrides the property Value to set the three fields of a phone number into three segments in SPFieldMultiColumnValue object.

    public class PhoneNumberFieldControl : Microsoft.SharePoint.WebControls.BaseFieldControl
    {
        protected System.Web.UI.WebControls.TextBox txtCountryCode;
        protected System.Web.UI.WebControls.TextBox txtAreaCode;
        protected System.Web.UI.WebControls.TextBox txtNumberCode;

        protected override string DefaultTemplateName
        {
            get
            {
                return "PhoneNumberFieldControl";
            }
        }

        public override object Value
        {
            get
            {
                EnsureChildControls();
                Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = new Microsoft.SharePoint.SPFieldMultiColumnValue(3);
                phoneNumberValue[0] = txtCountryCode.Text.Trim();
                phoneNumberValue[1] = txtAreaCode.Text.Trim();
                phoneNumberValue[2] = txtNumberCode.Text.Trim();
                return phoneNumberValue;
            }
            set
            {
                EnsureChildControls();
                Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = value as Microsoft.SharePoint.SPFieldMultiColumnValue;
                txtCountryCode.Text = phoneNumberValue[0];
                txtAreaCode.Text = phoneNumberValue[1];
                txtNumberCode.Text = phoneNumberValue[2];
            }
        }

        public override void Focus()
        {
            EnsureChildControls();
            txtCountryCode.Focus();
        }

        protected override void CreateChildControls()
        {
            if (Field == null) return;

            base.CreateChildControls();

            if (ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.Display)
                return;

            txtCountryCode = (System.Web.UI.WebControls.TextBox)FindControl("txtCountryCode");
            if (txtCountryCode == null) throw new NullReferenceException("txtCountryCode is null. Corrupted PhoneNumberFieldControl.ascx file.");
            txtCountryCode.TabIndex = TabIndex;
            txtCountryCode.CssClass = CssClass;
            txtCountryCode.ToolTip = Field.Title + " Country Code";

            txtAreaCode = (System.Web.UI.WebControls.TextBox)FindControl("txtAreaCode");
            if (txtAreaCode == null) throw new NullReferenceException("txtAreaCode is null. Corrupted PhoneNumberFieldControl.ascx file.");
            txtAreaCode.TabIndex = TabIndex;
            txtAreaCode.CssClass = CssClass;
            txtAreaCode.ToolTip = Field.Title + " Area Code";

            txtNumberCode = (System.Web.UI.WebControls.TextBox)FindControl("txtNumberCode");
            if (txtNumberCode == null) throw new NullReferenceException("txtNumberCode is null. Corrupted PhoneNumberFieldControl.ascx file.");
            txtNumberCode.TabIndex = TabIndex;
            txtNumberCode.CssClass = CssClass;
            txtNumberCode.ToolTip = Field.Title + " Phone Number";
            if (ControlMode == Microsoft.SharePoint.WebControls.SPControlMode.New)
            {
                txtCountryCode.Text = Field.GetCustomProperty("DefaultCountryCode").ToString();
                txtAreaCode.Text = Field.GetCustomProperty("DefaultAreaCode").ToString();
                txtNumberCode.Text = Field.GetCustomProperty("DefaultNumber").ToString();
            }
        }
    }

2. Create a custom field type class

The custom field type must inherit the base class SPField. In my test, I wrote following class derives SPFieldMultiColumn which is a subclass of SPField but supports multiple sub-columns. GetValidatedString overridden method checks the input object value and return its string value if it's correct. GetFieldValue method is to create a SPFieldMultiColumnValue object by the input string. FieldRenderingControl property returns the user control we created in step 1.

public class PhoneNumberField : Microsoft.SharePoint.SPFieldMultiColumn
    {
        public PhoneNumberField(Microsoft.SharePoint.SPFieldCollection fields, string fieldName)
            : base(fields, fieldName)
        {
        }

        public PhoneNumberField(Microsoft.SharePoint.SPFieldCollection fields, string typeName, string displayName)
            : base(fields, typeName, displayName)
        {
        }

        public override string GetValidatedString(object value)
        {
            Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = value as Microsoft.SharePoint.SPFieldMultiColumnValue;
            if (phoneNumberValue == null)
                return String.Empty;
            if(String.IsNullOrEmpty(phoneNumberValue[0]) || String.IsNullOrEmpty(phoneNumberValue[1]) || String.IsNullOrEmpty(phoneNumberValue[2]))
                throw new Microsoft.SharePoint.SPFieldValidationException(Microsoft.SharePoint.SPResource.GetString(Microsoft.SharePoint.Strings.MissingRequiredField));

            return value.ToString();
        }

        public override object GetFieldValue(string value)
        {
            if (String.IsNullOrEmpty(value))
                return null;
            Microsoft.SharePoint.SPFieldMultiColumnValue phoneNumberValue = new Microsoft.SharePoint.SPFieldMultiColumnValue(value);
            return phoneNumberValue;
        }

        public override Microsoft.SharePoint.WebControls.BaseFieldControl FieldRenderingControl
        {
            get
            {
                Microsoft.SharePoint.WebControls.BaseFieldControl phoneNumberFieldControl = new PhoneNumberFieldControl();
                return base.FieldRenderingControl;
            }
        }
    }

3. Create custom Field Type Definition

The custom type must include a custom field type definition. It's an XML file with file name fldtypes_*.xml. I named my phone number field definition file as fldtypes_phonenumber.xml. The detail schema is in http://msdn2.microsoft.com/en-us/library/ms415141.aspx

<?xml version="1.0" encoding="utf-8"?>
<FieldTypes>
  <FieldType>
    <Field Name="TypeName">PhoneNumber</Field>
    <Field Name="ParentType">MultiColumn</Field>
    <Field Name="TypeDisplayName">Phone Number</Field>
    <Field Name="TypeShortDescription">Phone Number</Field>
    <Field Name="UserCreatable">TRUE</Field>
    <Field Name="ShowInListCreate">TRUE</Field>
    <Field Name="ShowInSurveyCreate">TRUE</Field>
    <Field Name="ShowInDocumentLibraryCreate">TRUE</Field>
    <Field Name="ShowInColumnTemplateCreate">TRUE</Field>
    <Field Name="FieldTypeClass">WSSFieldDemo.PhoneNumberField,WSSFieldDemo,Version=1.0.0.0,Culture=neutral,PublicKeyToken=5cca1e4ab4efce28</Field>
    <PropertySchema>
      <Fields>
        <Field Name="DefaultCountryCode" DisplayName="Default Country Code" MaxLength="3" DisplaySize="3" Type="Text">
          <Default>1</Default>
        </Field>
        <Field Name="DefaultAreaCode" DisplayName="Default Area Code" MaxLength="3" DisplaySize="3" Type="Text">
          <Default>416</Default>
        </Field>
        <Field Name="DefaultNumber" DisplayName="Default Phone Number" MaxLength="8" DisplaySize="8" Type="Text">
          <Default>5325554</Default>
        </Field>
      </Fields>
    </PropertySchema>
    <RenderPattern Name="DisplayPattern">
      <Switch>
        <Expr>
          <Column />
        </Expr>
        <Case Value="" />
        <Default>
          <HTML><![CDATA[+]]></HTML>
          <Column SubColumnNumber="0" HTMLEncode="TRUE" />
          <HTML><![CDATA[(]]></HTML>
          <Column SubColumnNumber="1" HTMLEncode="TRUE" />
          <HTML><![CDATA[)]]></HTML>
          <Column SubColumnNumber="2" HTMLEncode="TRUE" />
        </Default>
      </Switch>
    </RenderPattern>
  </FieldType>
</FieldTypes>

4. Deployment

The final step is to deploy the assembly, user control and the field definition xml. It includes following steps:

1. Build the solution and sign the assembly
2. Put the assembly into GAC
3. Copy the user control to program files…web server extensions12 emplatecontroltemplates
4. Copy fldtypes_phonenumber.xml to program files…web server extensions12 emplatexml
5. iisreset.