Friday, November 21, 2008

Programmatically determine the display mode or edit mode of a website

You have a WCMS website and want to programmatically determine if the whole website is in display mode or edit mode. The namespace

using Microsoft.SharePoint.WebControls;

offers the SPControlMode enumeration with the members:
  • Display
  • Edit
  • Invalid
  • New

You can check the current mode by using the SPContext.Current object:
if (SPContext.Current.FormContext.FormMode == SPControlMode.Edit)
{
}

If you want implement a custom WebControl you can use Microsoft.SharePoint.WebControls.SPControlMode.Display to determine if your custom WebControl is in display or edit mode.

Custom Alert Template

To customize alerts template:
  1. Create a working copy of AlertTemplates.xml. File Alerttemplates.xml is located at: Local_Drive\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\Template\XML directory.
    Note Do not modify Alerttemplates.xml itself. Make changes to a working copy.
  2. Edit the working copy that you just created.
    Use the stsadm command to read the changed templates into the database. STSADM -o updatealerttemplates -url -filename .
  3. Restart IIS.
    Note It may be necessary to restart SharePoint Timer Services.

To assign a custom alert template to a specific list:

Create a new custom template with a unique Name attribute in your working copy of AlertTemplates.xml (You can copy paste the entire section with Name SPAlertTemplateType.GenericList, change the name and modify the sections you want to). Modify the template as necessary. After restarting IIS, write object model code to set the list alert template.
SPAlertTemplateCollection ats = new SPAlertTemplateCollection((SPWebService)(WebApplication.Parent)); //give appropriate values for WebApplication
list.AlertTemplate = ats["name from above"];
list.Update();

More information about Alerts Customization here

Friday, November 7, 2008

Embedding JavaScript in SharePoint Pages

The best method to embed custom javascript in SharePoint pages is to create a .js file and then include it in the SharePoint Page. If you would like to include javascript functions in the onload event of a sharepoint page, use the _spBodyOnLoadFunctionNames array. Include the push method in your script with the title of your function. The function should not include parameters...

<script>
function runOnLoad(){

}
_spBodyOnLoadFunctionNames.push("runOnLoad");
</script>

You found _spBodyOnLoadFunctionNames in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\1033\INIT.JS

Thursday, November 6, 2008

Installing SQL Reporting Services and MOSS 2007 on the Same port ( default : 80)

If you have both MOSS 2007 ( Microsoft Office SharePoint Server) and Reporting Services ( not in SharePoint integrated mode) installed on the same IIS virtual server, then you have to make the below updates in web.config for them to work:
  1. In the Root web.config to comment out the below. Otherwise the reportserver will give sessionState partitionResolver Issue
    <!-- <sessionstate mode="SQLServer" timeout="60" allowcustomsqldatabase="true" partitionresolvertype="Microsoft.Office.Server.Administration.SqlSessionStateResolver, Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />-->
  2. In both Reportserver and ReportManager vdir web.config, the following should be added under appSettings. Otherwise you will get ReportViewer error messages
    <remove key="ReportViewerMessages">
    or
    you disable inheritance from Root Web.Config. You can use inheritInChildApplications attribute in a configuration file to specify that the settings defined in the
    location element for the root of a Web site should not be inherited by child applications:

    This is because , by default MOSS uses /reports url for it’s report center and it’s the same virtual dir url for native SQL Reporting Services report manager as well.

Tuesday, November 4, 2008

How to deploy a custom field with custom properties from a feature

When MOSS 2007 was still in beta and features and custom fields were new areas to discover we created the classic regular expression field type too, just to play with and learn the new technology.
Our implementation SPFieldRegEx was inherited from the Text type and had three custom properties defined in the field type definition XML:


<PropertySchema>
<Fields>
<Field Name="RegEx" DisplayName="Regular Expression" MaxLength="255" DisplaySize="15" Type="Text">
</Field>
<Field Name="MaxLen" DisplayName="Maximum length" MaxLength="3" DisplaySize="3" Type="Integer">
<Default>255</Default>
</Field>
<Field Name="ErrMsg" DisplayName="Validation message" MaxLength="255" DisplaySize="30" Type="Text">
<Default>The value does not match the regular expression</Default>
</Field>
</Fields>
</PropertySchema>

The RegEx property stores the regular expression pattern, the MaxLen controls the maximal length of the field content and finally, the ErrMsg holds the validation message to be displayed when the input text does not match with the regular expression.

There is nothing interesting in that up to this point, but if you would like to deploy this custom field using a feature setting custom values to the properties you might encounter some difficulty.

Since I haven’t found that documented neither in the WSS SDK nor on developer blogs in the past years, I decided to share my experience.If you create your feature definition for the field as you do normally with the built in field types, the result is the following XML:

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Field ID="{54634385-A8AC-4898-BF24-E533EB23444F}" Name="RegExField" DisplayName="RegExField" StaticName="RegExField" Group="Grepton Fields" Type="SPFieldRegEx" Sealed="FALSE" AllowDeletion="TRUE" SourceID="http://schemas.microsoft.com/sharepoint/v3/fields" Description="This is the RegEx field" RegEx="[0-9]" MaxLen="20" ErrMsg="Error!"/>
</Elements>

But if you try to install the feature, you get the following error:

Feature definition with Id 6fd6ca04-3ac3-490f-b22f-4461a2253001 failed validation, file 'feature_definition2.xml', line 5, character 299:
The 'RegEx' attribute is not allowed.

If you remove the RegEx attribute, the same error message appears with MaxLen, if you remove that too, the ErrMsg causes problem.

So what to do to make this attributes allowed?The schema of the features is defined in the wss.xsd. Now the most important part for us is the FieldDefinition complexType that is responsible – what a surprise! – for describing the format of the field definitions in the features. Besides other things it contains the list of the allowed attributes.

<xs:complexType name="FieldDefinition" mixed="true">
...
<xs:attribute name="Decimals" type="xs:int" />
<xs:attribute name="Description" type="xs:string" />
...
<xs:attribute name="DisplayName" type="xs:string" />
...
<xs:attribute name="FillInChoice" type="TRUEFALSE" />
...
<xs:attribute name="Hidden" type="TRUEFALSE" />
...
<xs:attribute name="Max" type="xs:float" />
<xs:attribute name="Min" type="xs:string" />
...
<xs:attribute name="Name" type="xs:string" use="required"/>
...
<xs:attribute name="ReadOnly" type="TRUEFALSE" />
...
<xs:attribute name="Required" type="TRUEFALSE" />
...
<xs:attribute name="Title" type="xs:string" />
<xs:attribute name="Type" type="xs:string" use="required" />
...
<xs:attribute name="ID" type="UniqueIdentifier" />
<xs:attribute name="Group" type="xs:string" />
<xs:attribute name="MaxLength" type="xs:int" />
<xs:attribute name="SourceID" type="xs:string" />
<xs:attribute name="StaticName" type="xs:string" />
...
<xs:anyAttribute namespace="##other" processContents="lax" />
</xs:complexType>

The fragment above contains only the most widely used attributes for example.

One quick and dirty solution would be to include our custom attributes in the XSD schema but this probably wouldn’t be a supported method. Fortunately in this case MS has left the back door open: if you check the last attribute in the schema, it is anyAttribute with namespace ##other, meaning that you can inject your own attributes in the XML files using your own namespace.

After a minor modification in the feature definition XML (highlighted below) the XML was passed the schema check and our custom field feature was installed successfully.


<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/" >
<Field ID="{54634385-A8AC-4898-BF24-E533EB23444F}" Name="RegExField" DisplayName="RegExField" StaticName="RegExField" Group="Grepton Fields" Type="SPFieldRegEx" Sealed="FALSE" AllowDeletion="TRUE" SourceID="http://schemas.microsoft.com/sharepoint/v3/fields" Description="This is the RegEx field" xmlns:RegEx="[0-9]" xmlns:MaxLen="20" xmlns:ErrMsg="Error!"/>
</Elements>

But I faced another problem. Although this XML passed schema Validation, It didn't update extended attributes. After investigations I found only way to do that create event receiver for activation.

public class LookupFeatureEvents : SPFeatureReceiver
{
private const string CONST_FIELD = "Field";
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
string str = string.Empty;
string lastXml = string.Empty;
SPElementDefinitionCollection elementDefinitionCollection = properties.Definition.GetElementDefinitions(new CultureInfo(1033));
foreach (SPElementDefinition elementDefinition in elementDefinitionCollection)
{
if (elementDefinition.ElementType == CONST_FIELD)
{
XmlNode node = elementDefinition.XmlDefinition;
List<string> arrNS = new List<string>();
for(int i=0; i<node.Attributes.Count; i++)
{
if (node.Attributes[i].Prefix!=string.Empty)
arrNS.Add(node.Attributes[i].Prefix);
}
SPSite parent = properties.Feature.Parent as SPSite;
if (parent != null)
{
SPWeb web = parent.RootWeb;
string webid = web.ID.ToString("D");
string fieldId = node.Attributes["ID"].Value;
SPField lookup = web.Fields[new Guid(fieldId)];
lastXml = node.OuterXml;
for (int i = 0; i < arrNS.Count; i++)
{
lastXml = lastXml.Replace(arrNS[i] + ":", "");
}
lastXml = lastXml.Replace("xmlns=\"http://schemas.microsoft.com/sharepoint//"","");
lookup.SchemaXml = lastXml; lookup.Update(true);
}
}
}
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
//throw new NotImplementedException();
}
public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
//throw new NotImplementedException();
}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
//throw new NotImplementedException();
}
}

Monday, November 3, 2008

An unhandled exception occurred in the user interface.Exception Information: OSearch (Administrator)

I was getting this error while trying to start the Office SharePoint Server Search service on a standalone dev machine that I was configuring. The machine was not a part of any domain so I would just enter the username for the search account without the domain name. To solve this error one needs to provide the MachineName\AccountName instead of AccountName for the search account to use