Sunday, June 8, 2014

Event Receiver in SharePoint 2013

Here I have performed the following operations.
  1. Document Adding
  2. Document Updating
  3. Document Deleting
Step 1
Open Visual Studio 2013 and create an Empty SharePoint Project.

create Empty SharePoint Project

Step 2
Enter site URL and select Deploy as a farm solution and click Finish.

Enter site URL

Step 3
Open Solution Explorer and add a new item.

add new item

Step 4
Select event receiver and enter the title of the event receiver. Click the Add button.

event receiver

Step 5
Select List Item Events in type of event receiver and select the Document Library option from the event source. Then select an events as in the following and click Finish.

select an events

Step 6
The following screen will appear. Here I'm trying to update a SharePoint list based on file changes happening to a separate SharePoint Document Library.

Basically, the list will act like a document log. So we need to create the library and a list.

Here, I have created the EmployeeDocuments library to add and maintain documents and also created an EmployeeDocumentLog list to log the changes happening to the library.

changes happening to the library

An EmployeeDocuments Document Library has the following columns:
  1. Name
  2. Modified
  3. ModifiedBy
An EmployeeDocumentLog List has the following columns:
  1. Title
  2. DocumentAction
Step 7
Go to the Event receiver cs file and paste the following code.

Add Document

Here note that the ItemAdded method is used instead of the ItemAdding method.
  1. public override void ItemAdded(SPItemEventProperties properties) {  
  2.     //base.ItemAdding(properties);  
  3.     using(SPWeb web = properties.OpenWeb()) {  
  4.         try {  
  5.             SPList list = web.Lists["EmployeeDocumentLog"];  
  6.             SPListItem newItem = list.Items.Add();  
  7.             newItem["Title"] = properties.ListItem.Name;  
  8.             newItem["DocumentAction"] = "Document Added";  
  9.             newItem.Update();  
  10.         } catch (Exception ex) {  
  11.             throw ex;  
  12.         }  
  13.     }  
  14. }  
Update Document
  1. public override void ItemUpdating(SPItemEventProperties properties) {  
  2.     //base.ItemUpdating(properties);  
  3.     using(SPWeb web = properties.OpenWeb()) {  
  4.         try {  
  5.             SPList list = web.Lists["EmployeeDocumentLog"];  
  6.             SPListItem newItem = list.Items.Add();  
  7.             newItem["Title"] = properties.ListItem.Name;  
  8.             newItem["DocumentAction"] = "Document Updated";  
  9.             newItem.Update();  
  10.         } catch (Exception ex) {  
  11.             throw ex;  
  12.         }  
  13.     }  
  14. }  
Delete Document:
  1. public override void ItemDeleting(SPItemEventProperties properties)  
  2. {  
  3.     //base.ItemDeleting(properties);  
  4.     using (SPWeb web = properties.OpenWeb())  
  5.     {  
  6.         try  
  7.         {  
  8.             SPList list = web.Lists["EmployeeDocumentLog"];  
  9.             SPListItem newItem = list.Items.Add();  
  10.             newItem["Title"] = properties.ListItem.Name;  
  11.             newItem["DocumentAction"] = "Document Deleted";  
  12.             newItem.Update();  
  13.         }  
  14.         catch (Exception ex)  
  15.         {  
  16.             throw ex;  
  17.         }  
  18.     }  
  19. }  
Step 8
Here targeting to add the event receiver only to the “EmployeeDocuments” library, the Elements.xml file requires the following change.

Elements
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <Elements xmlns="http://schemas.microsoft.com/sharepoint/">  
  3.   <!--<Receivers ListTemplateId="101">-->  
  4.   <Receivers ListUrl="EmployeeDocuments">  
  5.       <Receiver>  
  6.         <Name>EmployeeDocumentsLogItemAdding</Name>  
  7.         <Type>ItemAdded</Type>  
  8.         <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>  
  9.         <Class>DocumentEventReceiver.EmployeeDocumentsLog.EmployeeDocumentsLog</Class>  
  10.         <SequenceNumber>10000</SequenceNumber>  
  11.       </Receiver>  
  12.       <Receiver>  
  13.         <Name>EmployeeDocumentsLogItemUpdating</Name>  
  14.         <Type>ItemUpdating</Type>  
  15.         <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>  
  16.         <Class>DocumentEventReceiver.EmployeeDocumentsLog.EmployeeDocumentsLog</Class>  
  17.         <SequenceNumber>10000</SequenceNumber>  
  18.       </Receiver>  
  19.       <Receiver>  
  20.         <Name>EmployeeDocumentsLogItemDeleting</Name>  
  21.         <Type>ItemDeleting</Type>  
  22.         <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>  
  23.         <Class>DocumentEventReceiver.EmployeeDocumentsLog.EmployeeDocumentsLog</Class>  
  24.         <SequenceNumber>10000</SequenceNumber>  
  25.       </Receiver>  
  26.   </Receivers>  
  27. </Elements>  
Step 9
Build and deploy the solution.

deploy

Step 10
The document has been added.

Go to the EmployeeDocuments Document Library and add a new document.

add new document

document library

Go to “EmployeeDocumentLog” list. The log will show by the following.

log  

Step 11
The document has been updated.

Go to the EmployeeDocuments library and update the document.

EmployeeDocuments library

Here I have changed the File Name. 

changed the File Name

Go to the “EmployeeDocumentLog” list. The log will show as in the following:

EmployeeDocumentLog list

Step 12
The document has been deleted.

Go to EmployeeDocuments library and delete the document.

EmployeeDocuments  

Go to the “EmployeeDocumentLog” list. The deleted document log will show as in the following:

EmployeeDocumentLog

SharePoint 2013 custom BCS Connector


SharePoint 2013 provides out of the box BCS connectors for Database, WCF, .Net and OData sources. If you need to connect to other form of data like a XML file or a file system then a custom BCS Connector has to be developed.

This blog post will explain the steps involved in creating a Custom BCS connector for SharePoint 2013 that connects to a XML file source. The steps involved  are
Developing Custom Connector Assembly
Creating the BCS model
Deploying the assembly and model
Creating external lists using custom connector

Developing Custom Connector Assembly
The customer connector assembly should have a class that implements the ISystemUtility interface from in Microsoft.BusinessData assembly. ISystemUtility interface provides functionality to execute operations against the external system. ExecuteStatic  method is the most important method within the interface where  we will be implementing CRUD actions for the custom connector.

The first parameter in ExecuStatic method is of type ImethodInstance and has a property called MethodInstanceType which indicates the type of method that is being called against the external content.  Finder MethodInstanceType  corresponds to retrieving  all items and SpecificFinder corresponds to retrieving a particular item.

The third parameter is an object array that has items that can be used with MethodInstanceType. The last item in the array is reserved for the return parameter.

Below is the execute static method for XML connector

public void ExecuteStatic(IMethodInstance mi,
            ILobSystemInstance si,
            object[] args,
            IExecutionContext context)
        {
               
           switch (mi.MethodInstanceType)
            {
                    //Single product view
               case MethodInstanceType.SpecificFinder:
                    int id = (int)args[0];
                    args[1] = GetProduct(id);
                    break;
                    //Product Listing
                case MethodInstanceType.Finder:
                    args[args.Length - 1] = GetProducts();
                     break;    
            }

        }
GetProducts method has the logic for retrieving all products from the XML file and GetProduct method has the logic for retrieving a particular product within the XML file. Sign the custom connector assembly with a strong name and generate the dll.

Creating the BCS model
The BCS model file can be created using a XML editor or using Visual Studio. The BCS model XML file has the below elements

LOB System
LOB System Instance
Entities

The Lob System element has the SystemUtilityTypeName property where we specify the fully qualified name of our custom connector assembly. Below is an example snippet of LOB System element
      <Properties>
        <Property Type="System.String" Name="SystemUtilityTypeName">
XMLFileConnectorG.Connector, XMLFileConnectorG, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3c36ccc14bfdf0d2
</Property>
      </Properties>

LObSystemInstance elements is where we can specify properties that can be used in custom connector assembly code. For example we can add a property to take the path of external XML source data file
<LobSystemInstances>
        <LobSystemInstance Name="ItemsData">
          <Properties>
            <Property Name="xmlfilepath" Type="System.String">c:\testfolder\products.xml</Property>
         </Properties>
        </LobSystemInstance>
      </LobSystemInstances>

Entity element section is where the identifier, fields and methods of our external content type is defined. Below is the snippet for an entity by name item with Finder and Specific Finder methods
<Entity Name="Item" EstimatedInstanceCount="1000" Version="1.0.0.0" Namespace="XMLFileConnectorG">
          <Identifiers>
            <Identifier Name="Id" TypeName="System.Int32" />
          </Identifiers>
          <Methods>
            <Method Name="ItemFind">
              <Parameters>
                <Parameter Name="id" Direction="In">
                  <TypeDescriptor Name="id" TypeName="System.Int32" IdentifierName="Id" />
                </Parameter>
                <Parameter Name="Item" Direction="Return">
                  <TypeDescriptor Name="Item" TypeName="Microsoft.BusinessData.Runtime.DynamicType">
                    <TypeDescriptors>
                      <TypeDescriptor Name="Id" TypeName="System.Int32" IdentifierName="Id" />
                      <TypeDescriptor Name="Title" TypeName="System.String"/>
                     <TypeDescriptor Name="Category" TypeName="System.String"/>
                    </TypeDescriptors>
                  </TypeDescriptor>
                </Parameter>
              </Parameters>
              <MethodInstances>
                <MethodInstance Type="SpecificFinder"
                                Name="ItemSpecificFinder"
                                Default="true"
                                ReturnTypeDescriptorLevel="0"
                                ReturnParameterName="Item">
                </MethodInstance>
              </MethodInstances>
            </Method>
            <Method Name="ItemDataFinder">
              <Parameters>
                <Parameter Name="Items" Direction="Return">
                  <TypeDescriptor TypeName="Microsoft.BusinessData.Runtime.DynamicType[]" IsCollection="true"Name="Items">
                    <TypeDescriptors>
                      <TypeDescriptor Name="Item" TypeName="Microsoft.BusinessData.Runtime.DynamicType">
                        <TypeDescriptors>
                          <TypeDescriptor Name="Id" TypeName="System.String" IdentifierName="Id" />
                          <TypeDescriptor Name="Title" TypeName="System.String"/>
                          <TypeDescriptor Name="Category" TypeName="System.String"/>
                          </TypeDescriptors>
                      </TypeDescriptor>
                    </TypeDescriptors>
                  </TypeDescriptor>
                </Parameter>
              </Parameters>
              <MethodInstances>
                <MethodInstance Type="Finder"
                                Name="ItemFinder"
                                Default="true"
                                ReturnTypeDescriptorLevel="0"
                                ReturnParameterName="Items">
                </MethodInstance>
              </MethodInstances>
            </Method>
          </Methods>
        </Entity>

Deploying the assembly and model
The custom BCS connector assembly has to be installed to Global Assembly cache on the SharePoint 2013 server and the BCS Connector model has to be imported before we can create content type from our model.

The custom connector assembly can be installed on the SharePoint server by using gacutil utility or by just dragging and dropping the assembly file to C:\windows\assemby folder.

To import the BCS model to SharePoint 2013 copy the BCS model file has to be copied to a location in SharePoint 2013 server and below steps have to be performed
1.       Logon to SharePoint 2013 central administration site

2.       Select Manage service application under Application Management

3.       Click BCS service application

4.       Click the Edit tab and click Import on BDC models ribbon

5.       In the Import BDC model page select the BCS your model file

6.       In File Type, select model option.

7.       In Advanced Settings, check Localized names, Properties, and Permissions check boxes.

8.       Click Import button.

The BCS model will be imported and the page will display all available models as shown below

 

 Clicking the model will show the external content types available in it.


 Clicking on the external content type will show details about the content type


Creating external lists using custom connector
Once we have installed the assembly and imported the BCS model, we can create external lists from the external content type by performing the below steps

1.       Navigate to the SharePoint site where the external site has to be created

2.       Click on Settings Icon from top left and click View Site Content menu

3.       On the Site Contents page click Add and app icon

4.       On the Your Apps page search for external list and click on External List from the result

5.       On the Add External List pop up give a name for the external list and select the external content type that was imported.

6.       External list will be created and content from the XML file will be populated

Server Error in '/' Application when activating "Nintex Forms" web app feature.

Apparently "INSTALL-NFService" need to be run in SharePoint PowerShell to fix this problem.   When I installed Nintex Forms agai...