Nov 5, 2010

Disable Active Directory group membership indexing in MOSS search

We have a corporate user profile search page in Sharepoint that allows free-word searching over various user attributes such as Title, Department, Extension, etc.

But incorrect extra profiles were showing up in searches by Department and Title. I traced the problem to the "Memberships" Crawled Property and the "People:Quicklinks" Managed Property. These properties index a user's Active Directory group membership and caused the extras profiles to appear.

Sep 2, 2010

GridView problems with Editing and Updating

Symptoms:
  • RowUpdated handler does not fire
  • UpdateMethod in DataSource does not fire
  • GridViewUpdateEventArgs empty in the RowUpdating handler
All of these are caused by a problem in the binding of the DataSource object to the GridView.

Solution:
  1. Check that your DataSourceControl has been added to the page controls. (ej. Panel1.Controls.Add(objectdatasource);
  2. Bind your Datasource to the GridView with: Gridview.DataSourceId = datasource.Id;
  3. Do NOT bind your DataSource to the GridView using: Gridview.Datasource = datasource;

Jul 29, 2010

No two choices should have the same ID at Microsoft.SharePoint.ApplicationPages.ChoiceComparerWithDefaultGroup.Compare

You probably get this error when you try to add an existing site column to a site content type.

The reason is that two site columns have the same internal name.

1. Check if the same error occurs at the root site when adding an existing site column to a site content type.

2. Once you've determined at which level the site column conflict is occurring, crack open your handy-dandy Sharepoint Manager 2007 (http://spm.codeplex.com).

3. Navigate to the fields (site columns) defined for that site and you'll probably see an additional field that doesn't show via the normal site columns page (_layouts/mngfield.aspx). This field is your problem field because its internal name matches the internal name of an inherited field.

4. Check that this field is not used in any site content types or lists. You may have to remove it from them first.

5. Delete the field with Sharepoint Manager 2007.

Cheers!

Jul 7, 2010

Custom list forms and data views

If you create a custom form for displaying or editing a list item, you won't be able to view the author or editor fields except in the Sharepoint:CreatedModifiedInfo control.

This is because the SPDataSource created uses the ListItem mode which hides certain fields. If you change the mode to List, you'll get all the fields.

Keep in mind you'll have to add a parameter ItemId to your selectcommand for the SPDatasource and correct the view CAML accordingly.

Sharepoint filter logic order

As you've discovered, the filter logic for Sharepoint 2007 list views has no grouping operator unless you convert the list view into a Data View Web Part.

That said, you can possibly use the evaluation order of the filter rules to achieve your grouping.

The order is: (((filter1 and/or filter2) and/or filter3) and/or filter4) and so on.

May 14, 2010

Attachments in sharepoint custom list forms

Attachments usually work fine for a custom New Item form created from Sharepoint Designer, but if you create a custom Edit Item form, you'll get the javascript error "This form was customized not working with attachment." when you click the attachments button.

Here's the Microsoft fix: http://support.microsoft.com/kb/953271

Basically the attachment button launches a javascript function UploadAttachment() that hides a span with id "part" which is usually the body of the form and shows just the attachment div. If you look at your custom New form you can see how it works.

Apr 16, 2010

How to get SPSite and SPWeb references

MSDN has a good article on how to quickly get references to an SPSite and SPWeb.

http://msdn.microsoft.com/en-us/library/ms468609.aspx

To summarize, use the SPContext class. And don't use dispose() or using blocks with the SPSite or SPWeb obtained via the SPContext class because you will break other code further on in the page!!!

Feb 25, 2010

Quick Excel table join

Situation: two excel worksheets with a common id column to join on.

Use LOOKUP and VLOOKUP to do this in a simpler manner. BUSCAR y BUSCARV en castellano.

1. Copy your id column to a new worksheet
2. For each column of interest paste the formula =INDEX(SourceSheet!$A$1:$T$500;MATCH($A$3;SourceSheet!$S$1:$S$500;0);SourceColumnOfInterestNumber)

Function parameters:
INDEX(dataRange;rowNumber; columnNumber)
MATCH(targetValue;dataRange;matchType(0 for exact match))

In Spanish language version Excel:
INDICE = INDEX
COINCIDIR = MATCH

Feb 22, 2010

Sharepoint: Access denied while uploading multiple files

Problem: you receive an error message saying "Access denied" while uploading multiple files or images to a sharepoint library, even though you have all the necessary permissions.

Solution: your filename contains characters that aren't allowed by Sharepoint.


Microsoft lays it out for you here: http://support.microsoft.com/default.aspx?scid=kb;en-us;905231

Feb 10, 2010

Blank items in DropDownList controls

After playing with JQuery to dynamically insert a blank option in my DropDownList but not finding a way to maintain the logic through a postback, I came across this wonderful post from Tomas Ekeli:

http://personalinertia.blogspot.com/2007/08/dropdownlist-with-blank-item-on-top.html

Works perfectly! Thrown in a RequiredFieldValidator with an InitialValue property and you're set.

Feb 3, 2010

How to export a key with Microsoft Enterprise Library

If you ever need to move an encryption key for Enterprise Library from one server to another, here's how to do it. No, you can't just copy the key file.

ON THE ORIGINAL SERVER

1. Open the Enterprise Library Configuration tool from the Start menu > Microsoft Patterns and Practices > Enterprise Library 4.0


2. Open your application configuration from File > Open Application and find your exe.config file that contains your Enterprise Library configuration.



3. Select your Symmetric Provider entry and choose Export Key from the Action menu.


4. Choose a location to save your exported key file and a password to protect it.



ON THE NEW SERVER


5. Copy the exe.config file and the export key file to your new server.
6. Run the Enterprise Configuration tool and open the exe.config file
7. Create a new Symmetric Algorithm Provider in the Symmetric Provider section


8. Choose the same encryption algorithm used on the original server


9. Choose the option to "Import a password protected key file"


10. Locate your exported key file and enter the password you protected it with


11. Choose a location to save your new permanent encryption key


12. Choose machine mode if you want all accounts to be able to use this key.


13. Rename or delete the old Symmetric Provider



14. Rename the new Symmetric Provider with the name of the old Symmetric Provider


15. Save your new Enterprise Library configuration.

Jan 29, 2010

Workflow problem with OnWorkflowItemUpdated

If you have an OnWorkflowItemUpdated activity, it can cause conflicts with other tasks and activities in your Sharepoint workflow.

Solution here: http://blogs.msdn.com/yvan_duhamel/archive/2009/11/25/workflow-locks-because-of-onworkflowitemchanged-event-handler.aspx

To workaround:
  1. Create a new SequenceActivity
  2. Create an InitializeWorkflow activity inside the SequenceActivity with a new correlation token scoped to the SequencyActivity
  3. Move the OnWorkflowItemUpdated activity after the InitializeWorkflow activity and set its correlation token to the same as the InitializeWorkflow activity.

Jan 25, 2010

Default values for association Infopath forms in Sharepoint workflows

At first, I thought you could set default values for an association form directly from the Infopath tool, simply assigning default values to the fields. That works, but the association form state gets lost after the user submits the form.

The correct way is creating an AssociationData element in the workflow.xml file of the workflow and the format is identical to the string passed into your workflow in the workflowProperties.AssociationData variable (minus some backslashes and carriage returns that might be present in the string).

In the example, my root data group in Infopath is called WorkflowParameters and inside I have two text fields, HorasRetraso and EmailBody (ignore the bilingual craziness). And we create a similar structure in the workflow.xml file.

Here's an example:

Infopath data design:




workflow.xml
file

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Workflow
Name="Workflows.ViajesCuestionario"
Description="My SharePoint Workflow"
Id="6dcb00c0-29af-448b-a5cd-333781c6071c"
CodeBesideClass="Workflows.ViajesCuestionario.Workflow1"
CodeBesideAssembly="Workflows.ViajesCuestionario, Version=1.0.0.0, Culture=neutral, PublicKeyToken=17d9b5dddc2775a2"
AssociationUrl="_layouts/CstWrkflIP.aspx">

<Categories/>
<AssociationData>
<my:WorkflowParameters xml:lang="es-ES" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2009-09-30T09:09:24" xmlns:xd="http://schemas.microsoft.com/office/infopath/2003">
<my:HorasRetraso>48</my:HorasRetraso>
<my:EmailBody>&lt;html&gt;&lt;body&gt;A link in the email body &lt;a href=&quot;http://www.google.com&quot;&gt;Link Text&lt;/a&gt;&lt;/body&gt;&lt;/html&gt;</my:EmailBody>
</my:WorkflowParameters>
</AssociationData>
<MetaData>
<Association_FormURN>urn:schemas-microsoft-com:office:infopath:WorkflowViajesCuestionarioAssociation:-myXSD-2009-09-30T09-09-24</Association_FormURN>
<StatusPageUrl>_layouts/WrkStat.aspx</StatusPageUrl>
</MetaData>
</Workflow>
</Elements>



Problems with infopath forms and workflows

Many times you'll get errors (This form cannot be opened. It is not workflow enabled. Or: The form was closed.) while using Infopath forms for association, initiation or modification in a Visual Studio workflow.

Here's a troubleshooting checklist:
  1. The form is web-enabled.
  2. The security level is "domain".
  3. You have published the form to your Visual Studio project folder, not simply copied or saved as. And you have left blank the file path for alternate access to the form in the Publishing wizard.
  4. The form URN is in the correct tag in the workflow.xml file.
  5. The workflow attribute "AssociationUrl" is set to "_layouts/CstWrkflIP.aspx" in the workflow.xml file.
  6. The form has an ElementFile entry in the feature.xml file.
  7. If you're using a WSP to deploy your workflow, be sure the form is included in the manifest.xml file.
If you're still having trouble, use these tools to find your problem:
  1. Check out Central Administration > Application Management > Manage Form Templates to see the status of the form.
  2. Run the command "stsadm -o verifyformtemplate -filename formname.xsn" to check for generic form problems.
  3. Review the Sharepoint logs in the 12 hive.

Jan 20, 2010

No-code cascading lists in Sharepoint

Here's how to do cascading lists in Sharepoint without resorting to custom webparts:

References:
Steps:

  1. Create the master list.
  2. Create the slave list using a lookup column to link elements to the master list
  3. In your page, create an SPDataSource to the master list
  4. Create a DropdownList linked to the first SPDataSource
  5. Create a second SPDataSource with a ControlParameter linked to the first dropdownlist and the required changes to the view query to accept this parameter.
  6. Create a dropdownlist connected to the second SPDataSource.
Example:


<SharePoint:SPDataSource runat="server" DataSourceMode="List"
UseInternalName="true"
selectcommand="<View></View>" id="categoriaspdatasource">
<SelectParameters>
<asp:Parameter Name="ListID" DefaultValue="3C001A55-F90B-4829-80BA-5374B939524E"/>
</SelectParameters>
</SharePoint:SPDataSource>
<asp:DropDownList runat="server" id="CategoriaDropDownList"
DataSourceID="categoriaspdatasource"
DataTextField="Label_ES"
DataValueField="Title" autopostback="true">
</asp:DropDownList>

<SharePoint:SPDataSource runat="server" DataSourceMode="List"
UseInternalName="true"
selectcommand="<View><Query><Where><Eq><FieldRef Name='Categoria'/><Value Type='Text'>{Categoria}</Value></Eq></Where></Query></View>"
id="subcategoriaspdatasource">
<SelectParameters>
<asp:Parameter Name="ListID" DefaultValue="FBB80C2B-EC23-426C-ACBE-9A595E20EE0C"/>
<asp:ControlParameter Name="Categoria" ControlID="CategoriaDropDownList" PropertyName="SelectedValue" />
</SelectParameters>
</SharePoint:SPDataSource>
<asp:DropDownList runat="server" id="SubcategoriaDropDownList"
DataSourceID="subcategoriaspdatasource"
DataTextField="Label_ES"
DataValueField="Title" EnableViewState="false">
</asp:DropDownList>

Jan 13, 2010

Output Excel xml file from web page

The original post for this technique is here:http://articles.techrepublic.com.com/5100-10878_11-6163451.html


Here are two ways to output to Excel from a webpage:
1. Output a DataGrid or HTML table, which Excel can reinterpret.
2. Output Excel XML format

In both cases, the MIME type must be set to "application/vnd.ms-excel".

For outputting the XML format, you can simply piece together three strings:
1. Header string containing document and worksheet properties
2. Body string containing data rows and columns
3. Footer string containing closing tags

More sophisticated is using an XSLT to transform your custom XML into an Excel XML.

A code sample for the XSLT tranform method:

protected void Button1_Click(object sender, EventArgs e)
{
// read data and build custom xml
String customXML = @"<?xml version='1.0' ?>
<root>
<row>
<column>Column 1 Row 1</column>
<column>Column 2 Row 1</column>
<column>Column 3 Row 1</column>
</row>
<row>
<column>Column 1 Row 2</column>
<column>Column 2 Row 2</column>
<column>Column 3 Row 2</column>
</row>
<row>
<column>Column 1 Row 3</column>
<column>Column 2 Row 3</column>
<column>Column 3 Row 3</column>
</row>
<row>
<column>Column 1 Row 4</column>
<column>Column 2 Row 4</column>
<column>Column 3 Row 4</column>
</row>
</root>"; // This should be built dynamically


Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", "Attachment;Filename=web.xml");
Response.Charset = "";
this.EnableViewState = false;

// Create input xmlreader from string
XmlTextReader xmlRead = new XmlTextReader(new System.IO.StringReader(customXML));

// Create stringbuilder output
System.Text.StringBuilder builder = new System.Text.StringBuilder();

// create xslt object
XslCompiledTransform xslDoc = new XslCompiledTransform();

// load xslt from string
xslDoc.Load(new System.Xml.XmlTextReader(new System.IO.StringReader(Resources.Resource1.XSLString)));

// run xslt transform on xml
xslDoc.Transform(xmlRead, XmlTextWriter.Create(builder));

// output transformed xml to Response
Response.Write(builder.ToString());
Response.End();
}




The XSLT transform (could be saved as a resource string):

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
<!-- : /: Edmond Woychowsky: July 25, 2005: The purpose of this template is to create an Excel/XML spreadsheet from a
simple xml document.
-->
<xsl:template match="/">
<xsl:processing-instruction name="mso-application">progid='Excel.Sheet'</xsl:processing-instruction>
<Workbook>
<xsl:call-template name="DocumentProperties"/>
<xsl:call-template name="OfficeDocumentSettings"/>
<xsl:call-template name="ExcelWorkbook"/>
<xsl:call-template name="Styles"/>
<xsl:apply-templates select="/*" mode="worksheet"/>
</Workbook>
</xsl:template>
<!-- : * worksheet: This template builds the spreadsheets individual worksheets, commonly know as
tabs.
-->
<xsl:template match="*" mode="worksheet">
<xsl:variable name="position" select="position()"/>
<Worksheet ss:Name="{concat('Sheet', $position)}">
<Table ss:ExpandedColumnCount="{count(./*[1]/*)}" ss:ExpandedRowCount="{count(./*) + 2}" x:FullColumns="1" x:FullRows="1">
<xsl:apply-templates select="*" mode="row"/>
</Table>
<xsl:call-template name="WorksheetOptions"/>
</Worksheet>
</xsl:template>
<!-- : * row: This template builds the worksheet's rows.
-->
<xsl:template match="*" mode="row">
<Row>
<xsl:apply-templates select="*" mode="cell"/>
</Row>
</xsl:template>
<!-- : * cells: This template builds the row's cells.
-->
<xsl:template match="*" mode="cell">
<xsl:variable name="type">
<xsl:choose>
<xsl:when test="number(.) = .">Number</xsl:when>
<xsl:otherwise>String</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<Cell>
<Data ss:Type="{$type}">
<xsl:value-of select="."/>
</Data>
</Cell>
</xsl:template>
<!-- : * column: This template describes a worksheet's individual columns.
-->
<xsl:template match="*" mode="column">
<xsl:variable name="name" select="name(.)"/>
<xsl:variable name="length">
<xsl:call-template name="length">
<xsl:with-param name="nodeset" select="//parent::*/parent::*/*/*[name(.) = $name]"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="width">
<xsl:choose>
<xsl:when test="($length * 5.75) &lt; 56.25">56.25</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$length * 5.75"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="style">
<xsl:choose>
<xsl:when test="parent::*/parent::*/*/*[name(.) = $name] = number(parent::*/parent::*/*[1]/*[name(.) = $name])">
<xsl:choose>
<xsl:when test="string-length(parent::*/parent::*/*/*[name(.) = $name][contains(.,'.')]) = 0">s23</xsl:when>
<xsl:otherwise>s24</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>s22</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<Column ss:StyleID="{$style}" ss:AutoFitWidth="0" ss:Width="{$width}"/>
</xsl:template>
<!-- : DocumentProperties: This template describes the document to Excel.
-->
<xsl:template name="DocumentProperties">
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
<Author>ewoychowsky</Author>
<Company>EAW</Company>
<Version>10.4219</Version>
</DocumentProperties>
</xsl:template>
<!-- : OfficeDocumentSettings: This template describes the Office document to Excel.
-->
<xsl:template name="OfficeDocumentSettings">
<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
<DownloadComponents/>
<LocationOfComponents HRef="file:///\\phlfsnt01\DOWNLOAD\OfficeXPSrc\"/>
</OfficeDocumentSettings>
</xsl:template>
<!-- : ExcelWorkbook: This template describes the characteristics of the wookbook to Excel.
-->
<xsl:template name="ExcelWorkbook">
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>9210</WindowHeight>
<WindowWidth>15195</WindowWidth>
<WindowTopX>0</WindowTopX>
<WindowTopY>60</WindowTopY>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
</xsl:template>
<!-- : Styles: This template describes the display styles to Excel.
-->
<xsl:template name="Styles">
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
</Styles>
</xsl:template>
<!-- : WorksheetOptions: This template describes the worksheet options to Excel.
-->
<xsl:template name="WorksheetOptions">
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<Print>
<ValidPrinterInfo/>
<HorizontalResolution>1200</HorizontalResolution>
<VerticalResolution>1200</VerticalResolution>
</Print>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</xsl:template>
<!-- : length: Determine either the length of the node name or the longest node(s), which ever is longer.
-->
<xsl:template name="length">
<xsl:param name="nodeset"/>
<xsl:variable name="longest">
<xsl:call-template name="longest">
<xsl:with-param name="nodeset" select="$nodeset"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="string-length(name($nodeset[1])) &gt; string-length($longest)">
<xsl:value-of select="string-length(name($nodeset[1]))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="string-length($longest)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- : longest: This recursive template transverses a nodeset to find the nodes with the longest
string-length. Please note that the result of this template may itself be a nodeset.
-->
<xsl:template name="longest">
<xsl:param name="nodeset"/>
<xsl:param name="length" select="0"/>
<xsl:choose>
<xsl:when test="count($nodeset[string-length(.) &gt; $length]) &gt; 0">
<xsl:call-template name="longest">
<xsl:with-param name="nodeset" select="$nodeset[string-length(.) &gt; $length]"/>
<xsl:with-param name="length" select="string-length($nodeset[string-length(.) &gt; $length][1])"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$nodeset"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>