Chapter 12. Building Server-Side BCS Solutions

In this chapter, you will learn to:

  • Use Microsoft Visual Studio to build Microsoft SharePoint solutions

  • Create Business Connectivity Services connectors

  • Import Business Data Connectivity models into Visual Studio

  • Build solutions using the Business Connectivity Services application programing interface

  • Build workflows with external data

  • Amend the SharePoint user interface to support your Business Connectivity Services solutions

  • Package and deploy solutions

In this chapter, you will learn how to build and use server-side solutions for working with your external data through Microsoft SharePoint Business Connectivity Services (BCS). As discussed in the previous chapter, and as the title of this chapter suggests, the solutions you will learn about execute the code on the server itself rather than on a user’s client. You will look at how Microsoft Visual Studio 2010 gives you the ability to build SharePoint solutions for BCS and also how to make use of the Business Data Connectivity Model project in Visual Studio to create and deploy a model.

Using Visual Studio 2010 to Create SharePoint Solutions

Microsoft has made some major investments in the SharePoint tools for Visual Studio 2010 Pro and above, which means creating solutions is now much easier than was possible in previous versions. The first major improvement is including a rich set of Visual Studio project templates to give developers a start for their solutions. Figure 12-1 shows the different project types available.

In addition to creating SharePoint projects in Visual Studio, you can create an empty SharePoint project and add various SharePoint project items to it or to other project types, as shown in Figure 12-2.

Many SharePoint 2010 project templates are available in Visual Studio 2010.
Figure 12-1. Many SharePoint 2010 project templates are available in Visual Studio 2010.
You can add SharePoint project items to an empty project or other project type.
Figure 12-2. You can add SharePoint project items to an empty project or other project type.

The next much appreciated improvement is the automatic packaging of solutions based off the Visual Studio SharePoint projects. Developers can now concentrate on writing the code for their solutions and adding the required artifacts to the Visual Studio project, and when they want to test or deploy the solution, Visual Studio will package the necessary files into a .wsp package. So after developers have fully tested and debugged their solutions, they can provide a .wsp package for their SharePoint administrators to deploy and test in the staging environment (see Figure 12-3). The developers can configure the feature and solution manifests using wizards, rather than editing the XML manually, as was previously required.

Developers can edit a feature using the new wizard.
Figure 12-3. Developers can edit a feature using the new wizard.

The final improvement we will examine is the improved ability to debug the solutions that developers are writing. Instead of manually packaging and attaching hooks to the necessary processes to see what the code is doing, developers can use the F5 deployment functionality, which will build the code and package and deploy the .wsp file to SharePoint.

Note

More Info If you are using Microsoft SharePoint Foundation, you need to take additional steps to add an event receiver. You can read more at http://archive.msdn.microsoft.com/BDCSPFoundation.

If required, once the solution is deployed using F5, developers can step through their code as it is being executed by SharePoint (see Figure 12-4). Once a solution has been debugged, Visual Studio can retract the .wsp file to clean up after itself. The steps executed when developers deploy the solution can again be configured to meet their requirements.

Configure the automated deployment and retraction steps in the View Deployment Configuration dialog box.
Figure 12-4. Configure the automated deployment and retraction steps in the View Deployment Configuration dialog box.

Visual Studio 2010 has made it easier to develop and work with SharePoint solutions. Next, you will take a look at the tools included to work with BCS. You may have noticed that there is a Business Data Connectivity Model project type available in Visual Studio. You will learn in the next section how to use this project type to create a BDC model, and why you would want to use this approach rather than simply using SharePoint Designer.

Creating BCS Connectors

Before diving into how to create a BCS connector in Visual Studio, let’s first take a step back to determine when you would and wouldn’t want to create one.

The first thing to note is that creating a BDC model in Visual Studio can be a lengthy process if you are unsure of how a BDC model is structured. You need to understand elements such as In and Return parameters, and the different method types and the code signatures required can lead to some confusion initially. Once you have written a handful of models, the process becomes easier, but understanding the principles first will help in the long run.

You shouldn’t need to create a BCS connector if all you want to do is perform simple CRUD functionality against a connection supported by SharePoint Designer. If you want to read and write data to a SQL table, for example, and you don’t need to transform or run any further business logic on the data, then it doesn’t make sense to write the code to do this when SharePoint Designer will generate the SQL scripts for you. SharePoint can connect with an external system through the SQL script in a model without the need to read and use a BCS connector DLL, which can help improve performance.

If, however, you want to create an external content type (ECT) based on multiple sources of data, and you want to transform the data before making it visible to SharePoint, add custom permission management, or even add in some custom business logic when a user updates or deletes a record, then a BCS connector is the way to add these custom requirements. A BCS connector also allows developers to get the context in which the ECT is being called, such as reading any properties from the BCS model and seeing the current user calling the ECT. Creating a BCS connector gives you a way to connect to a data source not supported by SharePoint Designer, such as Oracle or non-BCS-compatible web services. For the web services, you need to write a wrapper, and for any other data sources, you can connect in any way supported by the .NET Framework.

Stepping Through a BCS Connector Example

For this chapter’s example, you will use the Adventure Works Products SQL table and business logic to show the ProductId, Name, and list price for three different currencies—U.S. dollar ($), pound sterling (£), and yen (¥)—calculating the list price based on the latest exchange rate. The table shows the list price in U.S. dollars, so you will need to add custom type descriptors for the other two currencies dynamically—that is, the data will not come from the SQL table. You will create only read methods in this scenario, so the methods you create will be a Finder and a SpecificFinder.

First, open Visual Studio 2010 and create a new Business Data Connectivity Model project called ProductExchangeModel, as shown in Figure 12-5.

The next dialog box asks if you want to deploy as a sandboxed or a farm solution. Because the BCS connector DLL gets deployed to the global assembly cache (GAC), the farm solution is the only option available. The URL is the site that will be opened when the solution is deployed using F5. The F5 deployment is useful, as it allows you to configure a Web Part (for example, to use the ECT), and it will open to that page each time to let you test that you’re getting the results you expect. Click Finish to close the dialog box and load the project.

Create a Business Data Connectivity Model project in Visual Studio.
Figure 12-5. Create a Business Data Connectivity Model project in Visual Studio.

When the project first loads, you will see that an ECT is already created on the design surface. The default entity is similar to the “Hello World” application that a developer might write to show that the most basic functionality is working. If you were to press F5 now, you would have an ECT that shows “Hello World” for the Finder and SpecificFinder methods.

Understanding the User Interface with the “Hello World” Example

Now you’ll take some time to explore the user interface (UI) to understand the different components you use to configure the BDC model. You won’t make any changes to the default “Hello World” model you have at the moment, to make things easier to understand. The first item to look at is the visual representation of the ECT on the design surface, as shown in Figure 12-6.

The Entity1 ECT is shown on the design surface.
Figure 12-6. The Entity1 ECT is shown on the design surface.

The design surface with the ECT that you can see in Visual Studio is the BdcModel1.bdcm file. To view any BDC models in your solution, simply double-click the *.bdcm file to open it in this designer view.

Note

If you have ever seen a SharePoint 2007 application definition file (ADF), it is interesting to know that this .bdcm file type is essentially the same file (with some changes). If you were to open the file in XML view, you would see the structure of the model is almost identical to what used to be created in SharePoint 2007. Fortunately, you now have a nice UI in which to work with the model.

Taking a look at the Entity1 ECT, notice that it has an identifier defined called Identifier1 and it has two methods: ReadList and ReadItem. As you know by now, the identifier is the type descriptor that uniquely identifies a row of data in your external data and must be returned by each method. The names of the two methods give you a clue as to their method type: ReadList is the Finder method, and ReadItem is the SpecificFinder method. To confirm the method types, use the BDC Method Details tool pane at the bottom of the design surface (you may need to click its tab to display it). If you do not see the tool pane, go to the Visual Studio Menu toolbar at the top of the application and navigate to Views, click Other Windows, and then click BDC Method Details. The tool pane that displays looks similar to the one shown in Figure 12-7. Make sure the ECT is selected on the design surface.

View method details for the Entity1 ECT in the BDC Method Details tool pane.
Figure 12-7. View method details for the Entity1 ECT in the BDC Method Details tool pane.

In this view, you can see the two methods, ReadList and ReadItem, and for each method you can see the parameters, instances, and filter descriptors. For now, you are only interested in instances; you will look at the rest later. Click the ReadList line under Instances (not the one at the top; rather, the one six lines down from there). When you click this method instance, you can see its properties in the Properties tool pane, as shown in Figure 12-8. If the tool pane doesn’t appear, press F4 to display it or find it under the Views menu.

View the method instance type in the Properties tool pane.
Figure 12-8. View the method instance type in the Properties tool pane.

If you click the identifier on the ECT, you will see that its properties also display in the Properties tool pane. You can see both the identifier name and its data type, System.String. This is where you will configure various properties of the model later on.

So far, you have seen what the ECT looks like on the design surface and the information it offers. You have also viewed some of the properties of the model. The last thing to look at before writing your own ECT is the BDC Explorer tool pane. The BDC Explorer provides an overall view of the structure of the ECT and a means of working with the type descriptors of the model. When you work with a table as a data source, there is usually a simple mapping of one column to one type descriptor; however, as you will learn, you can add your own independent type descriptors to add more data to the ECT. You can access the BDC Explorer through its tab to the right of the Solution Explorer. If you do not see the BDC Explorer tab there, you can locate it through the Views menu. Figure 12-9 shows the BDC Explorer displaying the “Hello World” model.

The BDC Explorer shows the “Hello World” model.
Figure 12-9. The BDC Explorer shows the “Hello World” model.

You can click the various nodes in the BDC Explorer to easily access the properties of the BDC model.

You should now have a good sense of the BDC connector environment before diving into the code. There is a tight correlation between the code and the model, so it is important to understand where properties are configured.

Creating Your First External Content Type

Go ahead and delete the Entity1 ECT—it’s had its time in the spotlight. Now it’s time to create one with code. You should now have a blank design surface. Before you can move ahead, you’ll need to complete some housekeeping tasks. In the Solution Explorer, you’ll find two *.cs files to delete (see Figure 12-10). These are the C# code files that were used by the ECT that you just deleted.

Delete these redundant C# files.
Figure 12-10. Delete these redundant C# files.

After you delete the two .cs files, you should rename the model to something more appropriate than BdcModel1. Change to the BDC Explorer view and click the first node, BdcModel1. In the Properties pane, update the name to BdcConnectorProductModel, and also update the rest of the nodes to match Figure 12-11. These changes will help you identify the model and ECTs when using them inside of SharePoint.

The BDC Explorer shows the current model structure.
Figure 12-11. The BDC Explorer shows the current model structure.

Now it’s time to create an ECT. Right-click the design surface, click Add, and then click Entity. You can also drag an Entity toolbox item from the Toolbox.

Because this ECT will be used for product exchange rates, name it ProductExchangeRates. You can set the display name separately to make it easier for end users to read, but for the sake of the code, the name shouldn’t contain any spaces. To set the display name, click the ECT and change the Default Display Name in the Properties tool pane. If you look at the Solution Explorer, you should see that a file called ProductExchangeRatesService.cs has been automatically generated, as shown in Figure 12-12.

The ProductExchangeRatesService.cs file has been automatically generated.
Figure 12-12. The ProductExchangeRatesService.cs file has been automatically generated.

This service class is the class used as the data access layer to the external system. As methods and some changes are added to the BDC model, this file also gets updated. Visual Studio is writing the signature for the method for you to just enter the code logic to return the required data. If you look into the file now, you will see that it is just an empty C# class.

When you deleted the files from the Entity1 ECT earlier, you may recall that there were two files: a service class, like you have now, and another file. The second file is a class that defines the data you are getting from your external system. Essentially, you are building a strongly typed class that defines an ECT. To put this into simple terms, you need to think about the data you want to display in SharePoint. For this scenario, you want to return products with different exchange rates, so you will create a C# class that defines what a “product” in this context looks like.

In Solution Explorer, right-click the BdcModel1 folder, click Add, and click New Item. From the Code node, click Class, name it Product.cs, and click Add. Now you have an empty C# class to which you can add the necessary code to define what a product is. Because some of the data is coming from SQL Server, navigate to the SQL table using SQL Server Management Studio and have a look at the column types of the columns you are interested in. Figure 12-13 shows the view in SQL Server Management Studio.

View the column setup for the Product table.
Figure 12-13. View the column setup for the Product table.

The columns you are interested are ProductID, which is the primary key and has a type of Integer (int), Name (nvarchar(50)), and ListPrice (money). To add these properties to your C# code, you need to understand what their .NET equivalents are. A useful table available on MSDN presents the conversions: http://msdn.microsoft.com/en-us/library/ms131092.aspx. Some of the .NET types have Nullable<Type>, which is used when the standard .NET type expects to have a type. Usually it causes an error if, for example, a property of type Int (a number) is set to a null value (that is, no value). Using Nullable allows it to have no value. This is useful when you may not have all the values completed in your table—for example, say you have a database that contains people data, and one of the fields is Age, an optional field. If users have opted not to provide their age, then the value is null; it doesn’t exist. If you don’t use Nullable in this example, and SharePoint tries to set the Age property to null, it will throw an exception, whereas if you do use Nullable, SharePoint will allow the Age property to contain no value.

Converting the columns gives you the properties in Table 12-1, which you will add to the C# class.

Table 12-1. C# class properties

Property

SQL type

.NET type

ProductId

int

Int

Name

nvarchar(50)

String

ListPrice

money

Decimal

ListPriceSterling

*[a]

Decimal

ListPriceYen

*[b]

Decimal

[a] Not in SQL; these extra properties exist only in code.

[b] Not in SQL; these extra properties exist only in code.

The following code for the C# file shows that Product.cs was added:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProductExchangeModel.BdcModel1
{
    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        public decimal PriceInPoundSterling { get; set; }
        public decimal PriceInYen { get; set; }
    }
}

When you write the names of these properties, they do not need to match the names of the columns in the SQL table. You should remember that the data used to populate this object that you are calling a “product” could come from anywhere and could include as many or as few properties as needed. An external system could be just code or a hybrid such as this one, with a SQL table and code. Although these property names don’t have to match the source’s name, they do need to match the type descriptors in the BCS model. Naming the type descriptors is often where issues arise when building BCS models, and it is simply a case of a type descriptor not matching a property name perfectly (spelling, casing, and so on).

Now that you have defined what a Product ECT will look like in code, you can configure the BCS model to match by adding an identifier, a Finder method, and a SpecificFinder method. The identifier (the type descriptor that uniquely identifies a row) is the ProductId. You can add this identifier to the ECT by right-clicking it, clicking Add, and then clicking Identifier. By default, the identifier is called Identifier1 and its type is System.String, as shown in Figure 12-14.

The identifier properties can be viewed in the Properties tool pane.
Figure 12-14. The identifier properties can be viewed in the Properties tool pane.

This doesn’t match up with the identifier you want defined in the code: ProductId, with the type name System.Int32. Update the Properties pane to reflect your Product class, as shown in Figure 12-15. Don’t forget to check that the name matches the actual property’s name and ensure that the type is identical as well. Also set the Display Name to make it easier to understand what the column represents when it is used in SharePoint.

Updated properties for the identifier.
Figure 12-15. Updated properties for the identifier.

Next, you’ll add your first method to the model. Right-click the ECT again, and this time click Add, and then click Method. Call the new method GetAllProducts, as this will be the Finder method that gets all of the products.

You can edit the properties of the method to add a default display name, so your end users know what’s going to happen when they call this method. Entering Get All Products will suffice.

If you take a look at the BDC Method Details pane for the new method, you will see it is empty, as shown in Figure 12-16.

The newly created method before configuration.
Figure 12-16. The newly created method before configuration.

Now you’ll add some more properties to the method to describe its behavior. First, you’ll look at the parameters. When creating a basic Finder method, the only parameter required is a Return parameter. The majority of the time, a method has either an In and a Return parameter or just a Return parameter. An In parameter defines in the model that a value is going to be passed into your query. For example, if you have a filter, then you will be passed in the value to filter by. The SpecificFinder, as you will see later, gets passed in the identifier of the item to get from your external system. The Return parameter defines what data SharePoint can expect to be returned from your code, such as a Finder method returning a collection of items from your external system or a SpecificFinder returning just a single item from your external system.

Click the <Add a Parameter> text, and then click Create Parameter to create an In parameter (helpfully called “parameter” by default). You will want to change its name and also change the type to Return. Open the Properties tool pane and amend it to match Figure 12-17.

The parameter has been configured.
Figure 12-17. The parameter has been configured.

With a Return parameter defined, you now need to define what is being returned. The easiest way to do this is using a combination of the BDC Explorer and the Properties tool pane. If you take a look at the BDC Explorer pane now, you will see the parameter that you have just added (see Figure 12-18).

The BDC Explorer displays ReturnParameter.
Figure 12-18. The BDC Explorer displays ReturnParameter.

A type descriptor has been created for you, but you will need to do some work to make it fit with your requirements. As mentioned previously, type descriptors define the structure of the data that is going to be returned by your code, and this is where you define what that structure looks like. A Finder method typically returns a collection of objects (a Product), which have properties (Name, Cost, and so on). You will need to configure your type descriptors to reflect this detail, and its structure will look something like the following:

I am going to be returning a list of Products

This is a Product

This is a property of a Product

The default type descriptor created for you is defined to say that when the method is called, a single item—a string—will be returned, as shown in Figure 12-19.

The default Return parameter type descriptor with a string type.
Figure 12-19. The default Return parameter type descriptor with a string type.

Rename the parameter to ProductsList, as you want to return a list of products. Click the Type Name, and then click the little arrow on the right to open a dialog box where you can select the type of data being returned. In this dialog box, you will set the outer level of data you are returning to be a collection of products. Not just any products, though—a collection of our C# code definition of products. As shown in Figure 12-20, select the Is Enumerable check box to return enumerable data (a collection that can be iterated over) and select the Product class.

Select the custom Product class as an enumerable type descriptor.
Figure 12-20. Select the custom Product class as an enumerable type descriptor.

Once the outer type descriptor has been created, you’ll add a type descriptor to the ProductsList type descriptor to define what each of the items is inside of the collection. Right-click ProductsList in the BDC Explorer and click Add Type Descriptor to add a sub–type descriptor. This time call it Product, and set its Type to just Product, without selecting the Is Enumerable check box.

You’ll now add the properties of a Product to the product definition. At the moment, the model doesn’t contain a definition of a Product, so you need to define it. Right-click Product and choose Add Type Descriptor. Do this four more times, making sure you’re adding the type descriptor to Product each time (see Figure 12-21).

The Product with five type descriptors defined.
Figure 12-21. The Product with five type descriptors defined.

You added five type descriptors to define each property in your C# class, as shown in Table 12-2. For each type descriptor, you should edit the properties so the name exactly matches the name in the C# class, and also set the Type to match.

Table 12-2. Type descriptors

Name

Type

ProductId

System.Int

Name

System.String

Price

System.Decimal

PriceInPoundSterling

System.Decimal

PriceInYen

System.Decimal

Once you have set the values, the BDC Explorer should look like Figure 12-22.

Configure the type descriptor names to match the property names in the C# class.
Figure 12-22. Configure the type descriptor names to match the property names in the C# class.

The final step is to let SharePoint know that this method is returning the identifier. To do so, select the ProductId type descriptor, and in the Properties pane, set Identifier to ProductId, as shown in Figure 12-23.

Setting the identifier for the ProductId type descriptor.
Figure 12-23. Setting the identifier for the ProductId type descriptor.

Adding Filters

As mentioned previously in this book, you should always consider working with the smallest subset of data you can when working with BCS. There is no point pulling superfluous data across your network and taking up both resources and bandwidth. You have seen how to add filters using SharePoint Designer; in this section, you will look at how to add filters when building a BDC model in Visual Studio.

In this scenario, you will add a Limit filter and a Wildcard filter. The Limit filter will limit the number of items returned from the external system that match the Product Name specified by the Wildcard filter. To configure the method with a Limit filter, you need to add a filter descriptor and In parameter for the Limit and Wildcard filters.

Open the BDC Method Details tool pane for the GetAllProducts method and click the <Add a Filter Descriptor> text. Click Create Filter Descriptor to add a new filter descriptor called FilterDescriptor. You will want to configure the properties shown in Table 12-3.

Table 12-3. Property values for a new filter descriptor

Property

Value

Description

Default Display Name

Limit

The name you’ll see when configuring the Limit filter inside SharePoint

Filter Field

ProductId

The field to which the filter applies

Name

LimitFilter

The internal name of the filter

Type

Limit

The filter type

With the Limit filter descriptor added, you will add the Wildcard filter in the same way, this time using the property values listed in Table 12-4.

Table 12-4. Property values for another new filter descriptor

Property

Value

Default Display Name

Product Name

Filter Field

Name

Name

ProductName

Type

Wildcard

Now you’ll add the two In parameters. The value for the Limit filter will have a default value assigned to it, but you will be able to configure it inside SharePoint. The Wildcard filter will get its value set by the end user, or you could configure it with a static value inside SharePoint.

Back in the Parameters section of the BDC Method Details pane, add a new parameter called LimitParameter and set its direction to In. Add a new parameter for the Wildcard filter, called WildcardParameter, and again set its direction to In.

It is now time to configure the type descriptors that let SharePoint know the data that is going to be passed into this method. Navigate to the BDC Explorer and locate LimitParameter under the Get AllProducts method node. Table 12-5 lists the properties to configure for the type descriptor.

Table 12-5. Properties for the type descriptor

Property

Value

Name

limit

Type Name

System.Int32

Associated Filter

LimitFilter

The Limit filter will take a number of items to return, so set its Type to Int32. The Associated Filter tells SharePoint where it should use the value that is passed in to this parameter. Next, configure the Wildcard parameter as shown in Table 12-6.

Table 12-6. Property values for the Wildcard parameter

Property

Value

Name

wildcard

Type Name

System.String

Associated Filter

ProductName

The final step is to add the method instance. Here you are defining in the model the type of the method, whether it is the default method, the parameter that is being returned, and its display name. In the BDC Method Details pane, click <Add a Method Instance>, and then click Create Finder Instance. Set the properties for the method instance to values listed in Table 12-7, leaving the rest the same.

Table 12-7. Property values for the method instance

Property

Value

Default

True

Type

Finder

Return Parameter Name

ReturnParameter

You are specifying the Return parameter to the first parameter you created; this is the one that returns the collection of Products and defines what a single property consists of.

The Finder method has now been configured with regard to the model. Next, you will add the SpecificFinder method, which allows the end user to select a single record. If you want to be able to use your ECT with an external list, make sure you have these two methods at a minimum.

Adding a SpecificFinder Method

There are quite a few steps involved in creating the SpecificFinder method. Some of the tasks are easier, because you have already done some of the legwork. Add a new method to the ProductExchangeRates ECT, and call this new method GetSingleProduct. Your ECT should now look like Figure 12-24.

Add a new GetSingleProduct method to the ECT.
Figure 12-24. Add a new GetSingleProduct method to the ECT.

For a SpecificFinder method to function, it needs to receive the identifier that uniquely defines a record, so the first thing you will need to do is add an In parameter. As before, select the method and open the BDC Method Details pane. Make sure you find the correct GetSingleProduct method, as this pane now shows both the Finder method and the newly created method. You can minimize the method you’re not interested in by clicking the hyphen (-) next to the method name of the Finder method. Add a new parameter with the property configuration shown in Table 12-8.

Table 12-8. Property configuration for the new parameter

Property

Value

Name

InParameter

Parameter Direction

In

By making these simple changes, you can add the Return parameter to the new parameter. This time, however, the parameter will define a single object that your method will return, which is a Product (see Table 12-9).

Table 12-9. Parameter for the Product object

Property

Value

Name

ReturnParameter

Parameter Direction

Return

The parameters are added for both accepting data into and returning data from the method. Next, you will define the type descriptors to use. Go to the BDC Explorer and expand all of the method, parameter, and type descriptor nodes, as shown in Figure 12-25.

Showing the parameters for the methods so far.
Figure 12-25. Showing the parameters for the methods so far.

The first node to tackle is InParameterTypeDescriptor. This type descriptor must match the identifier defined in our code, both the name and the type. As this value is also the identifier, you must set it, too (see Table 12-10).

Table 12-10. Setting the identifier

Property

Value

Identifier

ProductId

Name

ProductId

Type Name

System.Int32

This is all that is required. It is worth noting that a SpecificFinder does not use a filter descriptor to get the single item; it just uses an In parameter.

Now you will configure the ReturnParameter. Last time, you needed to add the outer type descriptor that defined the collection, and under that, you defined the Product. With the SpecificFinder returning only a single item, you don’t need to add the outer level. A neat feature in Visual Studio is that you don’t need to create the Product structure again, since you can just copy it from the Finder method’s type descriptor. Right-click Product under the ProductsList type descriptor and click Copy, as shown in Figure 12-26.

Copying the type descriptors.
Figure 12-26. Copying the type descriptors.

With the type descriptors now on the clipboard, you can right-click the ReturnParameter of the SpecificFinder method and paste the type descriptors (see Figure 12-27). You will get a warning that you will replace the existing one. Click Yes.

The type descriptors have been copied.
Figure 12-27. The type descriptors have been copied.

This is all you need to do for the type descriptors. You have defined the In parameter type as the identifier, and you have also defined the single object that is being returned by the method. You can now move on to add the method instance using the BDC Method Details pane. In the Instances section, add a new method instance and update its properties, as shown in Table 12-11.

Table 12-11. Properties for a new method instance

Property

Value

Default

True

Type

SpecificFinder

Return Parameter Name

ReturnParameter

That’s it—the BDC model is now configured to support both a Finder and a SpecificFinder method. Before you can use the model in SharePoint, you need to write the code to retrieve the data.

Writing C# Code for the BDC Model

While you have been configuring the BDC model, Visual Studio has been maintaining the file called ProductExchangeRatesService.cs in the Solution Explorer with the method signatures required by the BDC model. The automatic signature generation makes writing the code a good deal easier, as it is easy to see the parameters being passed into the method as well as the return type. The code generated for the model should look like the following:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProductExchangeModel.BdcModel1
{
    public partial class ProductExchangeRatesService
    {
        public static IEnumerable<Product> GetAllProducts(int LimitParameter, string
WildcardParameter)
        {
            throw new System.NotImplementedException();
        }        public static Product GetSingleProduct(int InParameter)
        {
            throw new System.NotImplementedException();
        }
    }
}

We have two methods in the code that match the methods that were created in the model. The first method, GetAllProducts, is the Finder method. It has two parameters, one for the Limit filter and another for the Wildcard filter value. You can also see that the method is returning a collection of Products, just as we specified. The SpecificFinder method has a parameter for the ID, and this time it will return just a single Product.

It is worth reiterating at this point that the model and the code are completely independent from any external system. All you have done is configured a model that defines the concept of a ProductExchangeRate ECT. If you want to make this ECT get its data from any single external system, or even pull data from numerous systems, this is all possible in the code. If the .NET Framework can get the data, then you can use it here. For now, though, you will continue with the scenario of getting some of the data from SQL and enhancing it with some exchange-rate calculated data.

Note

More Info Various technologies are available to connect to a Microsoft SQL database, such as LINQ to SQL (http://msdn.microsoft.com/en-us/library/bb425822.aspx) and the ADO.NET Entity Framework (http://msdn.microsoft.com/en-us/library/bb399572(v=vs.90).aspx).

For the sake of brevity, you will use a generic method to get your data to help demonstrate how this data could come from anywhere. The code also uses a method called GetExchangeRate, which could perform any functionality you want to on your data before presenting it to SharePoint.

The following code is an example you can use for the Finder method:

        /// <summary>
        /// Finder Method
        /// </summary>
        /// <param name="LimitParameter">Limit Filter</param>
        /// <param name="WildcardParameter">Wildcard</param>
        /// <returns>Collection of Products matching filters</returns>
        public static IEnumerable<Product> GetAllProducts(int LimitParameter, string
WildcardParameter)
        {
            // Get the items from the External System(s)
            IEnumerable<DataAccessLayer.ExternalSytemProduct> externalSystemProducts =
                DataAccessLayer.GetProductsFromExternalSystem(LimitParameter,WildcardParameter);

            // Get Exchange rate for pound sterling
            decimal poundSterlingExchangeRate =
CurrencyHelper.GetExchangeRate(Currency.PoundSterling);

            // Get the Exchange rate for Yen
            decimal yenExchangeRate = CurrencyHelper.GetExchangeRate(Currency.Yen);

            // Return collection of Products created from External Data and own values
            return externalSystemProducts.Select(
                externalSystemProduct => new Product
                                             {
                                                 ProductId = externalSystemProduct.ProductID,
                                                 Name = externalSystemProduct.Name,
                                                 Price = externalSystemProduct.ListPrice,
                                                 PriceInPoundSterling =
externalSystemProduct.ListPrice * poundSterlingExchangeRate,
                                                 PriceInYen = externalSystemProduct.ListPrice *
yenExchangeRate
                                             }
                );
        }

The code is passing the filters to a custom method that will call the external system and retrieve the matching data. The code also has methods that call another method to get the exchange rates you are interested in. The final step is to iterate through each item returned from the external system and to create a Product object that we have defined in your own Product.cs class and is also the object that the BDC model has been configured to expect.

For the SpecificFinder method, the code is fairly simple. You are passing in the identifier to get one item that you then convert to a Product and set its properties.

        /// <summary>
        /// Specific Finder Method
        /// </summary>
        /// <param name="InParameter">Identifier</param>
        /// <returns>Single record with matching Identifier</returns>
        public static Product GetSingleProduct(int InParameter)
        {
            // Get the items from the External System(s)
            DataAccessLayer.ExternalSytemProduct externalSystemProduct =
                DataAccessLayer.GetSingleProductFromExternalSystem(InParameter);

            // Get Exchange rate for pound sterling
            decimal poundSterlingExchangeRate =
CurrencyHelper.GetExchangeRate(Currency.PoundSterling);

            // Get the Exchange rate for Yen
            decimal yenExchangeRate = CurrencyHelper.GetExchangeRate(Currency.Yen);

            // Return collection of Products created from External Data and own values
            return new Product
            {
                ProductId = externalSystemProduct.ProductID,
                Name = externalSystemProduct.Name,
                Price = externalSystemProduct.ListPrice,
                PriceInPoundSterling = externalSystemProduct.ListPrice *
poundSterlingExchangeRate,
                PriceInYen = externalSystemProduct.ListPrice * yenExchangeRate
            };
        }

This is the final piece of the puzzle, provided that you have written the code. In the accompanying source code to this book, you will find an example that has the blanks filled in.

To use this ECT, simply press F5 in Visual Studio to deploy the model. Once the model has been deployed, you can use the ECT on a Business Data Web Part, just as you would use any other ECTs you have deployed. In Figure 12-28, you can see all five columns from the Product object, including the two different exchange rates. The Wildcard filter is applied to show the products with Sport in their name.

Viewing the BCS connector ECT on a business data list.
Figure 12-28. Viewing the BCS connector ECT on a business data list.

Using Custom Connectors

Custom connectors offer even more flexibility than is possible with the sort of .NET connector you created in the previous example. Customer connectors offer the ability to create models and code that can be dynamically updated without the need to rewrite the code. The custom connector code can inherit numerous methods that allow it to reflect on the model to change its behavior and a lot more. When creating a custom connector, you are required to make some manual changes to the model and code that are not currently supported by the Visual Studio UI.

Note

See Also For more information about custom connectors, see http://msdn.microsoft.com/en-us/library/ff953161.aspx.

Connecting to Non-Microsoft SQL External Data Sources

In the BCS connector walk-through, you learned that there are two distinct parts of the creation process. The first part is defining the model and the ECTs, and the second part is writing the code methods that return the data in the same format as described by the model. This two-part procedure makes it easy to connect to any data source supported by the .NET Framework. The model itself doesn’t contain information about where the data is coming from, and it just needs to have a strongly typed object that it can use with SharePoint. For example, if you want to connect to Oracle, you can look at the Oracle table manually and work out which fields you want to use, their type, and which field is the primary key/identifier. Once you have this information, you can create a strongly typed class in a BDC model project to represent the data object, and the object would contain all of the fields you are returning from the Oracle table. The next step would be to configure an ECT with the identifier and the methods you want to have, and then add the necessary parameters and type descriptors to match your C# object. Once the model is defined, you are free to connect to your Oracle external system using any method supported by .NET in your service class.

In this section, you will learn how to take models that have been created using SharePoint Designer and scale them up to a Visual Studio solution.

Importing BDC Models into Visual Studio

It is possible to import a BDC model that was previously created in SharePoint Designer to allow you to manage its deployment through a .wsp package. This section outlines this simple process.

First, to export a BDC model from SharePoint Designer, from the navigation tab locate the ECT you want to use. If several ECTs make up a model, you can select multiple items. Then right-click and choose Export BDC Model, as shown in Figure 12-29.

You can export ECTs from SharePoint Designer.
Figure 12-29. You can export ECTs from SharePoint Designer.

Provide a name for the file you’re exporting, and leave the remaining settings at their defaults. Click OK. In the next dialog box, choose a location to save the .bdcm file, so you can find it later.

The next step is to import the model into Visual Studio. With Visual Studio open, create a new empty SharePoint project from the list of projects available. Choose to deploy it as a Sandboxed Solution and click Finish. Once the project has been created, right-click the project name, click Add, and then click Existing Item. Navigate to the .bdcm file you exported earlier. If the model does not contain a .NET assembly, Visual Studio will ask if you want to create one, as shown in Figure 12-30.

Choose if you want to add a .NET assembly to the imported model.
Figure 12-30. Choose if you want to add a .NET assembly to the imported model.

You will not be able to use the UI to manipulate the model the same way you could if you created the model from scratch, but you will be able to deploy the packaged .wsp file.

Building Solutions Using the BCS Application Programming Interface

For developers, the ability to write code against the SharePoint Object Model provides a great way to create solutions without needing to understand the nuances of specific external systems. The code a developer could write for a Microsoft SQL Server external system will be the same for Oracle or even a web service.

Note

The SharePoint Object Model provides an extensive application programming interface (API) for working with BCS. In addition to enabling you to work with ECTs through the object model, the API allows you to administer BCS to perform tasks such as creating and modifying BDC models programmatically. You can read more at http://code.msdn.microsoft.com/windowsdesktop/Creating-SharePoint-2010-ad694d17.

Using the SharePoint Object Model, developers can create solutions that the out-of-the-box Web Parts don’t offer. Writing a BCS solution for a dashboard can really help support a business by providing data from multiple external systems through BCS. Working with the BCS programmatically also opens up the possibility of making decisions based on business data, which we will look at shortly.

Let’s take a look at some code that connects to an ECT, iterates through product category items, and returns products from an associated product category:

    private void GetProductAndProductCategortyData()
        {
            using (new SPServiceContextScope(SPServiceContext.GetContext(SPContext.Current.
Site)))
            {
                // Get the BDC service and metadata catalog.
                var service = SPFarm.Local.Services.GetValue<BdcService>(String.Empty);
                IMetadataCatalog catalog = service.GetDatabaseBackedMetadataCatalog(SPService
Context.Current);
                // Get the entity by using the specified name and namespace.
                IEntity entity = catalog.GetEntity("AdventureWorksModel", "ProductCategory");
                ILobSystemInstance lobSysteminstance = entity.GetLobSystem().
GetLobSystemInstances()[0].Value;

                IFilterCollection defaultFilter = entity.GetDefaultFinderFilters();

                IEntityInstanceEnumerator entityInstanceEnumerator = entity.FindFiltered(default
Filter,lobSysteminstance);

                KeyValuePair<string, IAssociation> keyValuePair =
entity.GetSourceAssociations()[0];

                IAssociation association = keyValuePair.Value;

                // Iterate through each Product Category
                while (entityInstanceEnumerator.MoveNext())
                {
                    IEntityInstance currentProductCategory = entityInstanceEnumerator.Current;
                    if (currentProductCategory != null)
                    {
                        // Get Name of the Product Category
                        var productCategoryName = currentProductCategory.GetFormatted("Name");

                        // Get Enumerator for the Association
                        IEntityInstanceEnumerator associationEnumerator =
currentProductCategory.GetAssociatedInstances(association);

                        // Get Data Table contain Association data
                        var dataTable =
entity.Catalog.Helper.CreateDataTable(associationEnumerator);
                    }
                }
            }

Building Workflows with External Data

Workflows are an excellent example of using external data to drive your organizational business processes. When you consider what BCS offers in terms of providing access to data residing in external systems and making use of that data within SharePoint, it enables scenarios that would have traditionally required human interaction.

For example, consider a simple holiday request form. Say that employee information is stored in an external system—it doesn’t matter what this system is. This external system contains information about the number of paid holidays employees are entitled to. With an ECT already configured with the CRUD methods, it is possible to create the following workflow. A Holiday Request custom list could be created within SharePoint with columns for the employees’ requested days off. When an employee submits a holiday request, a workflow can read the creating user’s details, look up the employee’s current holiday entitlement; and either reject the request or automatically accept it if the employee has a certain job title, or escalate the request to the employee’s manager if it requires further approval. Once a manager accepts the holiday, the workflow can automatically deduct the remaining days from the employee’s record and email a confirmation to the employee. All of this can be achieved without human interaction. If you consider the traditional approach of an employee emailing the personnel team with requested holiday dates, and then personnel team needing to log on, look up a user, work out the user’s entitlement, respond to the user, and then log the holiday in the external system, you can see how building a workflow such as this can really simplify a business process.

Customer order processing is another good candidate for a workflow. If you imagine an InfoPath form library with a Customer external data column, you can see how BCS can benefit this process further. The first benefit of BCS here is that you are assured the customer details associated with the document are correct, because the user who added the document was required to select a customer from the external system rather than enter the information manually, which is error-prone. Once an order has been created and the workflow initiated, it is possible to read the order details from the InfoPath form and check if the items are in stock by looking them up from another ECT. If the items are in stock, the order can continue; if not, the workflow can create a task to notify the customer and create an order to restock the products.

You can write a workflow for use with BCS in several different ways. One way is to create a BCS action, which is a reusable component that you can write in Visual Studio and then use within SharePoint Designer, as shown in Figure 12-31. Creating this type of action provides a way to easily make business decisions in various scenarios based on your existing data.

A custom BCS workflow action in SharePoint Designer.
Figure 12-31. A custom BCS workflow action in SharePoint Designer.

It is also possible to create more complete Sequential and State Machine workflows using Visual Studio and use the BCS Object Model to interact with your external data.

Deploying BDC Models

As mentioned previously, Visual Studio packages the BCS model and, if you’re using a .NET connectivity assembly, the necessary DLLs when you build the project. There is also an option in the Build menu to simply package the solution. When the project is packaged, it creates the .wsp package in the solution directory in the BIN subfolder of the Build Configuration folder. For example, if you’re in debug mode for the ProductExchangeModel created earlier in this chapter, the .wsp will be created in a location similar to the following:

C:SourceProductExchangeModelProductExchangeModelinDebugProductExchangeModel.wsp

The .wsp package is the same as any other solution package you are familiar with in SharePoint. To move this BDC model to another environment, such as from a development server to a staging environment, you can deploy the .wsp package using Windows PowerShell or using STSAdm code.

Summary

In this chapter, you reviewed the various components of building a Business Data Connectivity (BDC) model and the Business Connectivity Services (BCS) connector inside Microsoft Visual Studio. First, you looked at the Business Data Connectivity Model project type and the user interface that Visual Studio offers to help configure the wizard. You then examined the requirements to create an external content type (ECT) with elements such as adding an identifier, adding method types, and configuring their type descriptors. You also saw how to create a C# class to define the object (Product) that represents the data being returned by the ECT. Finally, you learned how to add your own business logic to the generated C# code.

..................Content has been hidden....................

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