Creating an external content type

External content types are defined as reusable objects with metadata descriptions of connectivity information to external systems and data definitions. They could also contain the behaviors you want to apply to the external data. They are similar to the content types that we have dealt so far. The difference is that we will be managing the external data in external content types. The external data can be from relational databases like SQL server or Oracle or data coming from some web service.

For our recipe, we will use a SQL server table and create a content type based on the table data. We will use the HumanResources.Department table in the AdventureWorks database. We will create a GetDepartments method that will retrieve the list of all departments and a GetDepartment method that retrieves the single department object.

We will use LINQ to SQL to access relational data as objects. You do not have to use LINQ to SQL for data access in external content types. In this example, we are using it for the sake of simplicity of the code. If you want to learn more about LINQ to SQL, refer to MSDN at: http://msdn.microsoft.com/en-us/library/bb425822.aspx.

Getting ready

For this recipe, you need to have access to the AdventureWorks database. You can download it from: http://msftdbprodsamples.codeplex.com/.

How to do it...

  1. Create an empty SharePoint project with the farm level deployment option.
  2. Add a new item to this project and select Business Data Connectivity Model and name the item as DepartmentsModel as shown here:
    How to do it...
  3. Visual Studio adds the necessary files and brings up the BDC designer with a default entity called Entity1. Delete this default entity. Also delete the files Entity1.cs and Entity1Service.cs associated with this entity.
  4. From the ToolBox, add a new entity to the designer surface and rename this as Department in the properties window of the entity. Add a new identifier to this entity and call it DepartmentID and change the Type Name to System.Int16. Visual Studio will add a new service file called DepartmentService.cs in your solution explorer.
  5. To the project, now add a new item and select Data | LINQ to SQL Classes and name it Department as shown in the following screenshot:
    How to do it...
  6. From the server explorer, add a new data connection to your AdventureWorks database. Now from your LINQ to SQL designer window, navigate through the Server Explorer to the tables node from the data connection you just added. Expand the tables node and drag the Departments table and it to the designer. Visual Studio will generate the necessary LINQ DataContext classes for the external table. You can refer to this DataContext class in the Department.designer.cs file. Close this designer surface. We will not be making any changes to this class file.
  7. Now back in the DepartmentsModel, select the Department Entity created previously, and Create a Finder Method from the BDC Method Details window and name it GetDepartmentList. Also Create a Finder Specific method and name it GetDepartment. The final screenshot should look like the following:
    How to do it...
  8. Select the DepartmentList Type Descriptor in the BDC Method Details window and from the drop-down select Edit menu option to bring up the BDC explorer window. In here, change the Type Name property to Current Project | Department. Make sure that the Is Enumerable checkbox is selected.
  9. Underneath the DepartmentList, select Department and change the Type Name property to Current Project | Department. In this case, the Is Enumerable checkbox is not selected. Underneath this department, add a Type Descriptor and name it DepartmentID. The type name should be System.Int16. In the same manner, add three more Type Descriptors named Name, GroupName, and ModifiedDate. The Type Name for the Name and the GroupName is System.String and for ModifiedDate it is System.DateTime. The final screen should be as shown in the following screenshot:
    How to do it...
  10. Open the DepartmentService.cs file and add code to retrieve the departments from the database to the GetDepartmentList method and add code to retrieve the single object to the GetDepartment method. Your code should be as follows. Make sure to change the database connection string to your environment:
    public static IEnumerable<Department> GetDepartmentList()
    {
    DepartmentDataContext dx = new DepartmentData Context("Data Source=intsql;Initial Catalog=Adventure Works;Integrated Security=True");
    return dx.Departments;
    }
    public static Department GetDepartment(short id)
    {
    DepartmentDataContext dx = new DepartmentData Context("Data Source=intsql;Initial Catalog=AdventureWorks; Integrated Security=True");
    return dx.Departments.Single(d => d.DepartmentID == id);
    }
    
  11. Press F5 to build and run the project. This should bring up the site that was provided during the project creation wizard. In here, from the site actions menu, create an external list called Departments and add the content type we just created as shown here:
    How to do it...
  12. This should list all the departments from the Departments table in the AdventureWorks database as shown in the next screenshot:
How to do it...

How it works...

Visual Studio refers to external content types as an entity because BDC schema refers to this as entities. BDC Designer is built on top of ADO.Net Entity Designer and hence that reference. If you are familiar with ADO.Net Entity Designer, this will work the same way. In here, we can create entities and associate them with some relationship.

For our external content type to work, we need to create at least two methods of type Finder and SpecificFinder method. In our example, we created GetDepartmentList and GetDepartment that corresponds to these types. This is important because SharePoint calls these methods to render the list and display the selected item when the item is selected. There are other types of methods that can be used in external content types. Refer to MSDN at: http://msdn.microsoft.com/en-us/library/ee557363(office.14).aspx for more information on different method types that can be developed in the external content types.

The finder method, GetDepartmentList does not take any input parameters, but has one return parameter. This is defined in the Method Details window. In here, we provided information about the type of our parameter and direction of the parameter. The direction can be "In", "Out", "InOut", and "Return". The "In" direction is used on the parameters that are used to pass in the values to the methods. The "Out" direction, as the name refers to, is the output parameter and "InOut" is similar to "ref" parameter in C#. We also provided the type of our parameter. For this, we used the Department object that was created through LINQ to SQL. We set the type of the parameter through type descriptors. Type descriptors are metadata information that is used during the runtime to determine the type of the parameter passed or returned. There are other properties in type descriptors that tell SharePoint how to use this parameter. For example, the Creator Field property in a type descriptor tells that it is used in the form for user input. the collection property tells that the parameter is a collection. Not all of the type descriptors make sense for each of the parameters that pass in the method. It comes in handy, depending upon the type we want to retrieve or pass.

Each of the methods that we defined also has a method instance. This is because, in BCS, when we define a method, it is defined as an abstract piece of code. An instance is created during run time and executed.

There's more...

If you receive Access denied by Business Data Connectivity error as shown here, follow these steps:

There's more...
  1. Open Central Administration | Application Management | Manage Service applications and select Business Data Connectivity Service. You should see the list of all external content types deployed.
  2. From the drop-down menu select your content type and select Set Permissions as shown in the following screenshot:
    There's more...
  3. Add users and set appropriate permissions for the user executing the ECT.

Create, update, and delete methods

For our preceding example, to add other CRUD methods like create, update, and delete methods, follow these steps:

  1. From the BDC Method Details Window, create Creator Method for creating the department. Name this method CreateDepartment. For updating, the method type should be Updater Method and for delete Deleter Method. Also name the updater method as UpdateDepartment and the deleter method as DeleteDepartment.
  2. Visual Studio automatically wires up the necessary parameters and its type descriptors and adds method signatures in the DepartmentService.cs. Add the code in the DepartmentService.cs for create, update, and delete. Your code should look as follows:
    public static Department CreateDepartment(Department newDepartment)
    {
    DepartmentDataContext dx = new DepartmentDataContext("Data Source=intsql;Initial Catalog=AdventureWorks;Integrated Security=True");
    newDepartment.ModifiedDate = DateTime.Today;
    dx.Departments.InsertOnSubmit(newDepartment);
    dx.SubmitChanges();
    return dx.Departments.Single(d => d.DepartmentID == newDepartment.DepartmentID);
    }
    public static void UpdateDepartment(Department department)
    {
    DepartmentDataContext dx = new DepartmentDataContext("Data Source=intsql;Initial Catalog=AdventureWorks;Integrated Security=True");
    Department dept = dx.Departments.Single(d => d.DepartmentID == department.DepartmentID);
    dept.GroupName = department.GroupName;
    dept.Name = department.Name;
    dept.ModifiedDate = DateTime.Today;
    dx.SubmitChanges();
    }
    public static void DeleteDepartment(short departmentID)
    {
    DepartmentDataContext dx = new DepartmentDataContext("Data Source=intsql;Initial Catalog=AdventureWorks;Integrated Security=True");
    external content typeCRUD methodsdx.Departments.DeleteOnSubmit(dx.Departments.Single(d => d.DepartmentID == departmentID));
    dx.SubmitChanges();
    }
    

Connection strings

In our example, we have hard coded the connection string. There are several ways you can access the connection string data without hard coding it like getting the connection string from web.config or from a custom SharePoint list that is used to store the configuration information. The other approach is to use the BCS LobSystemInstance object. For our example:

  1. Navigate from BCS Explorer window Model | DepartmentsModel | DepartmentsModel | LobSystemInstances | DepartmentsModel.
  2. From the properties windows, add a custom property in the custom property collection and add your connection string as shown:
    Connection strings
  3. Add a reference to Microsoft.BusinessData.dll found in Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14ISAPI.
  4. This connection string now can be accessed from the code by making DepartmentService implement the IContextProperty interface. The following is the code for getting the DB connection string.
    public string GetDBCon()
    {
    Microsoft.BusinessData.MetadataModel.Collections.INamedPropertyDictionary dic = this.LobSystemInstance.GetProperties();
    if (dic.ContainsKey("DBCon"))
    return dic["DBCon"].ToString();
    else
    return "";
    }
    public Microsoft.BusinessData.Runtime.IExecutionContext ExecutionContext
    public Microsoft.BusinessData.Runtime.IExecutionContext ExecutionContext
    {
    get;
    set;
    }
    public Microsoft.BusinessData.MetadataModel.ILobSystemInstance LobSystemInstance
    {
    get;
    set;
    }
    public Microsoft.BusinessData.MetadataModel.IMethodInstance MethodInstance
    {
    get;
    set;
    }
    

The other method is to use the secure store service to store the connection string. Although it is used to store the user credentials for logging into the external system, it can be used to store the connection string. Information on configuring the secure store service can be found on MSDN at http://technet.microsoft.com/en-us/library/ee806866.aspx.

For our example, create a new secure store application called AdventureWorks with one field of type Generic. Call that field Connection String as shown here:

Connection strings

Follow the next steps to get credentials from the secure store programmatically.

  1. Add a new class to the project and call it SecureStoreUtilities.cs.
  2. Add a reference to Microsoft.BusinessData.dll from the ISAPI folder.
  3. Add a reference to Microsoft.Office.SecureStoreService.dll from WindowsassemblyGAC_MSILMicrosoft.Office.SecureStoreService14.0.0.0__71e9bce111e9429c.
  4. Add the following code to SecureStoreUtilities.cs to retrieve and decrypt the string:
    public static Dictionary<string, string> GetSSCreds(string applicationID)
    {
    var credKVP = new Dictionary<string, string>(); //Key Value pair
    using (SPSite site = new SPSite("http://intsp1/"))
    {
    // Console.WriteLine(site.RootWeb.CurrentUser.Name);
    SPServiceContext serviceContext = SPServiceContext.GetContext(site);
    var secureStoreProvider = new SecureStoreProvider { Context = serviceContext };
    using (var creds = secureStoreProvider. GetCredentials(applicationID))
    {
    var taFields = secureStoreProvider.GetTarget ApplicationFields(applicationID);
    for (var i = 0; i < taFields.Count; i++)
    {
    var field = taFields[i];
    var credential = creds[i];
    var decryptedCredential = DecryptCredential(credential.Credential);
    external content typeconnection stringscredKVP.Add(field.Name, decryptedCredential);
    }
    }
    }
    return credKVP;
    }
    public static string DecryptCredential(this SecureString encryptedString)
    {
    var ssBSTR = Marshal.SecureStringToBSTR (encryptedString);
    try
    {
    return Marshal.PtrToStringBSTR(ssBSTR);
    }
    finally
    {
    Marshal.FreeBSTR(ssBSTR);
    }
    }
    
  5. Create a following utility method in your DepartmentService.cs called GetDBConnectionString and pass the return value from this method to the DepartmentDataContext constructor:
    public static string GetDBConnectionString()
    {
    string sDbCon = "";
    Dictionary<string, string> ssList = SecureStoreUtilities.GetSSCreds("AdventureWorks");
    foreach (KeyValuePair<string, string> kvp in ssList)
    {
    if (kvp.Key == "Connection String")
    {
    sDbCon = kvp.Value;
    break;
    }
    }
    return sDbCon;
    }
    

You can use this approach to dynamically construct a LOB connection string by storing the credentials in the secure store.

See also

  • Creating a list definition recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.239.195