Making metadata fields of document library available in Search & Search results

Sometimes there may be a requirement, where we have exposed some metadata fields in a document library and we need those fields to be available when we use SharePoint search, and also in search results.

To achieve this, we need to carry out the following steps:

  1. Create content type with metadata fields (This step has already been covered in my previous post – http://ankitkrsaxena.blogspot.com/2011/12/create-custom-content-type-with-custom.html
  2. Create managed properties for the metadata fields (for content type fields)
  3. Run full crawl on the server so that the properties become available for mapping.
  4. Map crawled properties to the Managed properties.

The code snippets for implementing the above are mentioned below:

//Get the default shared service provider                         
ServerContext sc = ServerContext.GetContext(SPContext.Current.Site);
PropertyInfo srpProp = sc.GetType().GetProperty(
    “SharedResourceProvider”, BindingFlags.NonPublic | BindingFlags.Instance);
object srp = srpProp.GetValue(sc, null);
PropertyInfo srpNameProp = srp.GetType().GetProperty(
    “Name”, BindingFlags.Public | BindingFlags.Instance);
string sspName = (string)srpNameProp.GetValue(srp, null);
//Get search Schema
ServerContext serverContext = ServerContext.GetContext(sspName);
SearchContext searchContext = SearchContext.GetContext(serverContext);
Schema schema = new Schema(searchContext);                   

Once we have the ssp and search schema details, we read the content type fields and create managed properties for the metadata.

//Getting the content type object
SPContentType siteCT = web.ContentTypes[“CustomDocLibCT”];
//Getting the content type’s fields
CTFields = siteCT.Fields;
//Loop on the content type fields to find the internal names of the columns
FindInternalNamesOfMetadata();                          
//Putting values in an array
InternalNamesArray = InternalNames.Split(‘;’);
//Looping on the array
for (int i = 0; i < InternalNamesArray.Length; i++)
{
    string managedPropertyName = InternalNamesArray[i];
    string PropertyPublished = string.Format(“ows_{0}”,InternalNamesArray[i]);
    if(!schema.AllManagedProperties.Contains(“MyCustom”+managedPropertyName))
    {
        ManagedProperty newManagedProperty = schema.AllManagedProperties.Create(“MyCustom” + managedPropertyName, ManagedDataType.Text);
        //Get crawled property to map in the Managed Property            
        CrawledProperty cprop = null;
        foreach(CrawledProperty prop in schema.QueryCrawledProperties   (PropertyPublished, 1000, Guid.NewGuid(), string.Empty, true))
        {
            if (prop.Name == PropertyPublished)
            {
               cprop = prop;
               break;
            }
        }
        if (cprop != null)
        {
             // Map the crawled prop to the Managed Prop                  
             MappingCollection mappings = new MappingCollection();
             mappings.Add(new Mapping(cprop.Propset, cprop.Name, cprop.VariantType, newManagedProperty.PID));
             newManagedProperty.SetMappings(mappings);
             
             // Set Some other properties                  
             newManagedProperty.FullTextQueriable = true;
             newManagedProperty.EnabledForScoping = true;
             newManagedProperty.Update();
        }                                   
    }                                                          
}
//Create new managed property – All Metadata & Assign all metadata field crawled properties to it
createAllMetadataProperty(schema, InternalNamesArray);
InternalNamesArray = null;
InternalNames = string.Empty;

 The method createAllMetadataProperty is used to create a property that will search for all the metadata values collectively.

private void createAllMetadataProperty(Schema schema, string[] IntNamesArray)
{
    if (schema.AllManagedProperties.Contains(“MyCustomAllMetadata”))
    {
        schema.AllManagedProperties[“MyCustomAllMetadata “].DeleteAllMappings();
        schema.AllManagedProperties[“MyCustomAllMetadata “].Delete();
    }
    string PropertyPublishedNew = string.Empty;
    MappingCollection mappings = new MappingCollection();
    //create managed property
    ManagedProperty newManagedProperty = schema.AllManagedProperties.Create(“MyCustomAllMetadata “, ManagedDataType.Text);
   
    // Get the (crawled) property you want to map in the ManagedProperty            
    for (int i = 0; i < IntNamesArray.Length; i++)
    {
        PropertyPublishedNew = string.Format(“ows_{0}”, IntNamesArray[i]);
        foreach (CrawledProperty cprop in schema.QueryCrawledProperties(PropertyPublishedNew, 1000, Guid.NewGuid(), string.Empty, true))
        {
            // Map the crawled properties to the Managed Prop    
            mappings.Add(new Mapping(cprop.Propset, cprop.Name, cprop.VariantType,newManagedProperty.PID));
        }
    }
    newManagedProperty.SetMappings(mappings);
    // Set Some other properties                  
    newManagedProperty.FullTextQueriable = true;
    newManagedProperty.EnabledForScoping = true;
    newManagedProperty.Update();
    IntNamesArray = null;
}

Create Custom content type with Custom fields supporting creation of multiple types of documents (.doc, .xls, .ppt) in MOSS

At times, we may have a requirement where in we need to create different type of documents (Word – .doc/.docx , Excel – .xls/.xlsx, Powerpoint – .ppt/.pptx) in a single document library.
So we need to follow the below mentioned steps:
1. Create the required custom fields.
<Field ID={2B333B0C-05E6-4576-A49E-8713CD6F3FA6} Name=Field1      DisplayName=Field1 Type=User Required=FALSE Indexed=TRUE  ShowInNewForm=TRUE ShowInEditForm=TRUE ShowInDisplayForm=TRUE
Group=Other Columns >
    <Formula>=Author</Formula>
    <FieldRefs>
      <FieldRef Name=Author/>
    </FieldRefs>
</Field>
<Field ID={B8DEEF8E-54AA-4ad9-9AC7-115AC936228E} Name=Field2
 DisplayName=“Field2” Type=Choice Required=FALSE Indexed=TRUE   ShowInNewForm=TRUE  ShowInEditForm=TRUE ShowInDisplayForm=TRUE
Group=Other Columns >
    <CHOICES>
      <CHOICE>void</CHOICE>
    </CHOICES>
</Field>
and so on……
2. Create custom content types with the required custom fields.
<!–Generic content type inherited from document content type containing all the fields–>

<ContentType  ID=0x01010D Name=CustomDocLibWrkspcCT Group=Document Content Types Description=Create a document for the document library Version=0>

  <FieldRefs>
    <FieldRef ID={2B333B0C-05E6-4576-A49E-8713CD6F3FA6}  Name=OwnerRequired=FALSE ShowInNewForm=TRUE ShowInEditForm=TRUEShowInDisplayForm=TRUE/>
    <FieldRef ID={B8DEEF8E-54AA-4ad9-9AC7-115AC936228E} Name=Entity Required=FALSE   ShowInNewForm=TRUE ShowInEditForm=TRUE ShowInDisplayForm=TRUE/>
  </FieldRefs>
  <XmlDocuments>
     <XmlDocument NamespaceURI=http://schemas.microsoft.com/sharepoint/v3/contenttype/forms>
        <FormTemplates xmlns=http://schemas.microsoft.com/sharepoint/v3/contenttype/forms>
          <Display>DocumentLibraryForm</Display>
          <Edit>DocumentLibraryForm</Edit>
          <New>DocumentLibraryForm</New>
        </FormTemplates>
      </XmlDocument>
    </XmlDocuments>
</ContentType>
<ContentType  ID=0x01010D0089A4ED8153C04980A6CC1DB53EFA85A9
       Name=Word Document Group=Document Content Types
       Description=Create a word document for the document library
       Version=0>
    <FieldRefs></FieldRefs>
  </ContentType>

<!–Content type for Excel document–>
<ContentType DocumentTemplate=122  ID=0x01010D00A09D2732961C4ffe822B33F30117D24F Name=Excel Document Group=Document Content Types Description=Create an excel document for the document library Version=0>
    <DocumentTemplate TargetName=/_cts/Excel Document/MyTemplate.XLSX />
    <FieldRefs></FieldRefs>   
</ContentType>
<!–Provision the document template in system content types virtual folder-->
<Module Name=XLSTemplates Url=_cts/Excel Document RootWebOnly=TRUE Path=XLSTemplates >
    <File Url=MyTemplate.XLSX Type=Ghostable />
</Module>

<!–Content type for PowerPoint document–>
<ContentType DocumentTemplate=123 ID=0x01010D0036A1687A93B8415fAE51C38676BACD9F Name=PowerPoint Document Group=Document Content Types Description=Create a powerpoint document for the document library Version=0 >
<DocumentTemplate TargetName=/_cts/PowerPoint Document/MyPptTemplate.PPTX />
    <FieldRefs></FieldRefs>  
</ContentType>
<!–Provision the document template in system content types virtual folder–>
<Module Name=PPTTemplates Url=_cts/PowerPoint Document RootWebOnly=TRUE Path=PPTTemplates >
    <File Url=MyPptTemplate.PPTX Type=Ghostable />
</Module>
Note: The templates for these files are uploaded at the location http://minus.com/mtomNJw23
3. Attach these content types to the document library.

In the schema.xml file of the custom document library, within the tag, attach the content types created above

<ContentTypes>                 
      <ContentTypeRef ID=0x01010D0089A4ED8153C04980A6CC1DB53EFA85A9>
        <Folder TargetName=Forms/Document/>
      </ContentTypeRef>
      <ContentTypeRef  ID=0x01010D00A09D2732961C4ffe822B33F30117D24F>
        <Folder TargetName=_cts/Excel Document/>
      </ContentTypeRef>
      <ContentTypeRef ID=0x01010D0036A1687A93B8415fAE51C38676BACD9F>
        <Folder TargetName=_cts/PowerPoint Document/>
      </ContentTypeRef>
      <ContentTypeRef ID=0x0120 />

</ContentTypes>