RSS

Tag Archives: Programming Algorithms

Creating A Custom Content Type for SharePoint 2010 – Through Code

You can easily create your own content types through the user interface of SharePoint, This post shows you a couple of options to create your own content types using code for SharePoint 2010.

Option #1:

Custom Content Types (via a Content Type project)

The easiest way to create a custom content type is to use Visual Studio 2010 to create a special project type of type Content Type. Click on the installed project templates to display the templates in the SharePoint 2010 section, and select the template named Content Type. Let’s give the project the name MovieData and click the OK button.

The SharePoint Customization Wizard opens, which will display a series of steps you need to provide information for, so Visual Studio can configure your project properly. On the first screen, enter the URL of the SharePoint site you want this content type to be deployed to. You should also select the Deploy as a farm solution radio button. Press the Next button to continue.

The next screen requires that you choose which content type to inherit the content type from. We want to inherit from the Document content type, so select Document from the dropdown list, and press the Finish button. Visual Studio will now create the project, and we are ready to finish coding our custom content type.

You will notice that for the Content Type project template, Visual Studio creates an elements.xml file as part of the project. This is the only file we will need to modify to complete our custom content type. Open the elements.xml file, and under the ContentType node.

You can optionally set the Description attribute value to whatever you like, and if you wish to have the content type be displayed in a specific content type group, you can modify the Group attribute value. Note that the ID attribute value represents the GUID value of the content type we inherited from (the Document content type).

The next step is to create the Genre column that will be part of our content type. To do this, add a Field element inside the Elements node, right before the ContentType node. Set the Name and DisplayName attribute values to ‘Genre’, and make the column a choice column by setting the Type attribute to ‘Choice’. You also need to give the field a unique ID value (a GUID), which you can use the GUIDGEN tool to do this for you.
Since the column we are adding is a choice column, we now need to add entries that will be displayed when the user is selecting an entry. Add a CHOICES node inside the Field element, and then add one or more CHOICE nodes inside the CHOICES node.

Once you have this column defined, you must add a field reference so the column can be displayed as part of the content type. Add a FieldRef element inside of the FieldRefs node, as shown below:

Make sure you use the same GUID that you created when you created the Field element, and give the Name and DisplayName attributes a value of ‘Genre’. Save the elements.xml file when you are finished.
The project is now ready to be compiled and deployed to our SharePoint site. Right mouse click the project in Solution Explorer, and select Deploy. Visual Studio will compile the project, deploy the content type (as a Feature), and automatically activate it at the site level.


At this point, our custom content type is ready to use, but first we need to enable it in the document library that we want to use it in. I have created a normal document library in my SharePoint site. Navigate to the Document Library Settings page, and click on Advanced Settings. Enable management of content types, and click OK. This allows us to add our content type for this document library, so we can classify documents with this content type.

When you return to the Document Library Settings page, you will notice that under the Content Types section, there is the Add from existing site content types link. Click on this link to add the custom content type to this library.

That’s it! We are now ready to upload (or create) a document to our library, and our content type will be used when uploading/creating the document. You will notice that a dialog is displayed when I upload a document, allowing selection of a Genre metadata field when uploading the document.

Option # 2:

Custom Content Types (via a blank SharePoint project)

Another easy way to create a custom content type is to do it with SharePoint object model code.

The code will be deployed as a feature also, but the content type will be created when the feature is activated.

This has the advantage that if you need to do anything custom to your content type before it gets created, you can handle that with code.
As usual, launch Visual Studio 2010 and create a new project. Click on the installed project templates to display the templates in the SharePoint 2010 section, and select the template named Empty SharePoint Project. Give the project a name and click the OK button.

You will notice that Visual Studio only asks you to specify whether the project should be deployed in a farm or sandbox solution (select the farm solution). Visual Studio doesn’t ask you for any additional information when creating the project, as it did in Option 1. An empty SharePoint project assumes you will handle all the configurations yourself.

The next step is to create a feature, as this is how we will deploy our custom content type. Right mouse click the Features node in Solution Explorer, and click on Add Feature. This will create a feature in the project and open the designer page for the Feature1.feature file. We want to add code to the events that fire when the feature is activated/deactivated, so in order to do that we need to add an event receiver to the feature. Right mouse click the Feature1.feature file in Solution Explorer, and click on Add Event Receiver:

Visual Studio creates a Feature1.EventReceiver.cs file, which contains the event handlers for the FeatureActivated, FeatureDeactivating, FeatureInstalled, FeatureUninstalling, and FeatureUpgrading events. We are only going to add code to the FeatureActivated and FeatureDeactivating events. Uncomment the FeatureActivated event, and add the following code to it:

//get a reference to the SharePoint site

SPWeb thisWeb = (SPWeb)properties.Feature.Parent;

//set the AllowUnsafeUpdates property, so we can modify the site through code.

thisWeb.AllowUnsafeUpdates = true;

//reference the Document content type defined, & create custom content type, inheriting from it.

SPContentTypeCollection contentTypes = thisWeb.ContentTypes;
SPContentType parent = thisWeb.ContentTypes[“Document”];
SPContentTypeId parentID = parent.Id;

//create a site column by instantiating a variable of type SPFieldChoice class

SPContentType MyCustomCT = new SPContentType(contentTypes[parentID], contentTypes, “MyCustomCT”);
contentTypes.Add(MyCustomCT);
string MyField = thisWeb.Fields.Add(“FieldType”, SPFieldType.Choice, false);
SPFieldChoice fieldType = (SPFieldChoice)thisWeb.Fields.GetFieldByInternalName(MyField);
fieldType.Choices.Add(“Test1”);
fieldType.Choices.Add(“Test2”);

//call the Update() method which will create the site column on the SharePoint site.
fieldType.Update();

//now link your site column to your CT  using SPFieldLink class
SPFieldLink fieldLink = new SPFieldLink(fieldType);
MyCustomCT.FieldLinks.Add(fieldLink);
MyCustomCT.Update();

//you need to set your new custom content type as the default content type for the your document library.

SPList MyList = thisWeb.Lists[“ListName”];

MyList.ContentTypesEnabled = true;
MyList.Update();
MyList.ContentTypes.Add(MyCustomCT);
MyList.Update();

//This is done by creating a generic list variable of type SPContentType, and adding the content types to it

SPContentTypeCollection listCTs = MyList.ContentTypes;

System.Collections.Generic.IList newOrder = new System.Collections.Generic.List();
newOrder.Add(listCTs[“MyCustomCT”]);
newOrder.Add(listCTs[“Document”]);
MyList.RootFolder.UniqueContentTypeOrder = newOrder;
MyList.RootFolder.Update();

This code will execute when the feature is activated, and is responsible for all the steps of creating our custom content type.

 
 

Tags: , , , , , , , , , , , , , , , ,

Generate CAML from Linq-to-SharePoint

Generate CAML from Linq-to-SharePoint

Though you can use old CAML builder with SharePoint 2010, since the CAML builder is not updated yet, you will not get the CAML new features when you will use CAML builder. Worried? Please don’t. There’s an way out. Let me explain

  1. Download CKS Visual Studio Extension: There’s an useful and handy Visual Studio Extension for SharePoint developers known as Community Kit for SharePoint (CKS): Development tool edition. You can download the extension for SharePoint Server or for SharePoint Foundation.
  2. Generate Entity classes from SharePoint site:Once you have installed the Community Kit for SharePoint, you can generate entity classes from Server Explorer. First open a SharePoint project in Visual Studio and then connect to the SharePoint server from Server Explorer ==> SharePoint Connections. Then right click on your web and click “Generate entity classes” as shown below. This will generate the entity classes in the current selected project of Visual Studio.LINQ - VS 2010
    Generate entity class from SharePoint site/web
  3. Write Linq using Linq-to-SharePoint against generated entity classes:Once you have generated the entity classes as described on step2, you can use Linq to SharePoint to write your logic that you want to achieve through CAML. Once you write the Linq, you can run the code and log the CAML generated from the Linq. For example I have two lists Orders and Product. I want to join two lists to get order title and product name. The Linq will look like as shown below:
    using (var dataContext = new MySiteDataContext(siteUrl))
    {
        TextWriter textWriter = new StreamWriter(@"c:\caml.txt",false);
        dataContext.Log = textWriter;
        var result = from o in dataContext.Orders
                        join p in dataContext.Product on o.Product.Id equals p.Id
                        select new {OrderName = o.Title, p.ProductName};
        foreach (var v in result)
        {
            System.Console.WriteLine("{0}----{1}",v.OrderName,v.ProductName);
        }
    }
    Code snippet 1: Linq query using Linq to SharePoint

    As shown in the code snippet above, I have used the data context generated at step 2 and I have run a Linq query against two lists of the data context. The most import thing to notice in above code snippet is marked with yellow. I have instantiated a text writer (initialize with file stream) and then I had set it as the Log property of the datacontext. This will ensure that any CAML generated from the Linq query will be written in the writer. Once the query gets executed the CAML is dumped in the file (in my case C:\Caml.txt).

    So for generating any complex CAML query you can first write its equivalent Linq query and then get the CAML from log.

  4. Get the CAML from the Linq query: After running the Linq to SharePoint query, you have got the CAML query in the log file as shown in step 3. However, you need to work a bit to make the CAML usable in SPQuery. The CAML generated from code snippet 1 is shown below:
    <View>
      <Query>
        <Where>
          <And>
            <BeginsWith>
              <FieldRef Name="ContentTypeId" />
              <Value Type="ContentTypeId">0x0100</Value>
            </BeginsWith>
            <BeginsWith>
              <FieldRef Name="ProductContentTypeId" />
              <Value Type="Lookup">0x0100</Value>
            </BeginsWith>
          </And>
        </Where>
        <OrderBy Override="TRUE" />
      </Query>
      <ViewFields>
        <FieldRef Name="Title" />
        <FieldRef Name="ProductProductName" />
      </ViewFields>
      <ProjectedFields>
        <Field Name="ProductProductName" Type="Lookup" List="Product" ShowField="ProductName" />
        <Field Name="ProductContentTypeId" Type="Lookup" List="Product" ShowField="ContentTypeId" />
      </ProjectedFields>
      <Joins>
        <Join Type="INNER" ListAlias="Product">
          <Eq>
            <FieldRef Name="Product" RefType="ID" />
            <FieldRef List="Product" Name="ID" />
          </Eq>
        </Join>
      </Joins>
      <RowLimit Paged="TRUE">2147483647</RowLimit>
    </View>

    Code snippet 2: CAML generated from Linq query of Code Snippet 1

    In the above code snippet, the lines marked with yellow can be modified if you want. Specially the content type in where part is put in the CAML to ensure only list items are selected. FYI, Content type 0x0100 means list item type.

  5. Use CAML query in SPQuery:Now you have got the CAML and you want to use the CAML in SPQuery. The following code snippet shows how I’ve used the CAML(from code snippet 2) in SPQuery:
    SPQuery query = new SPQuery();
    query.Query = @"<Where>
                        <And>
                        <BeginsWith>
                            <FieldRef Name='ContentTypeId' />
                            <Value Type='ContentTypeId'>0x0100</Value>
                        </BeginsWith>
                        <BeginsWith>
                            <FieldRef Name='ProductContentTypeId' />
                            <Value Type='Lookup'>0x0100</Value>
                        </BeginsWith>
                        </And>
                    </Where>
                    <OrderBy Override='TRUE' />";
    
    query.ViewFields = @"<FieldRef Name='Title' />
                        <FieldRef Name='ProductProductName' />";
    query.ProjectedFields = @"<Field Name='ProductProductName' Type='Lookup'
                                     List='Product' ShowField='ProductName' />
                              <Field Name='ProductContentTypeId' Type='Lookup'
                                     List='Product' ShowField='ContentTypeId' />";
    query.Joins = @"<Join Type='INNER' ListAlias='Product'>
                    <Eq>
                        <FieldRef Name='Product' RefType='ID' />
                        <FieldRef List='Product' Name='ID' />
                    </Eq>
                    </Join>";
    
    query.RowLimit = 2147483647;
    
    var list = web.Lists["Orders"];
    var items = list.GetItems(query);
    foreach (SPListItem item in items)
    {
        System.Console.WriteLine("{0}--{1}", item["Title"], item["ProductProductName"]);
    }

    Code Snippet 3: Using generated CAML in SPQuery

Integrating the Test Code in your Visual Studio Soltuion

You may need to generate the CAML from time to time in your development life cycle. My personal preference is to keep a devtest project in the Visual Studio solution to do work like this CAML generation. I keep a dev-test project (used for RnD like task), mainly console app, in the solution. So you can keep the dev-test project in your solution and in that project you can write the Linq to SharePoint query and generate the CAML. Since the project will always be in your Visual Studio solution, if you need to get the CAML anytime you can just write the Linq query in the dev-test project and run the project to get the CAML.

 

Tags: , , , , , , , , , , , , , , , , , , ,