It is mentioned in several posts (like this one from René Hézser) that you can use custom fields in BDC models an external links, but I do not really find any real downloadable sample project for that.
Since I like to have complete examples one can download and try in this post I will show you a sample .NET assembly that illustrates using custom field types in external list. For an introduction to .NET connectivity assembly, I suggest you to read and understand the following article:
To understand my code, you should know how we can read BDC metadata from code. The Reading metadata model properties section of the post How do I leverage Secure Store from within my .Net Connectivity Assembly? explains exactly that.
Notice: This goal of this sample only to illustrate the capabilities and the limitations of BCS and external lists. The code example is not intended to be used in production. If you would like to enhance it, you are free to use it at your own risk. You should definitely deal with error handling, concurrency and security issues I would not like to detail here due to lack of time.
Our example is a simple link collection, similar to the standard SharePoint Links list, but in this case our links come from the file system. You should create a local folder on the SharePoint server and copy a few links there from your Favorites folder. The sample code will help to list, read, modify and delete these URL files as well as create new ones from an external list on SharePoint UI.
To make a sample a little bit more exciting we will spice it with some XSL tampering (or let’s call it customization to be politically correct) using SharePoint Designer. It includes using the favicon property of the URL to be displayed next to the link and moving the list item menu to the second field of the view (that is not its standard position for an external list as we will see soon).
The topic of internal structure of URL files as well as reading and writing URL files are really beyond the scope of this post. If you need more info about that visit this page.
As you probably already guessed, the custom field we use in this example will be in this case the built-in (not-so-custom) Hyperlink or Picture field of SharePoint.
Let’s see first the LobSytem and Entities sections:
Note, that you should modify the value of the Folder property to match the path of your local links folder created earlier. If you alter the BDC model and deploy multiple times, don’t forget to delete the corresponding external system between as described in my former post.
You can reach the value of the Folder property from code as illustrated below:
We had to reference the Microsoft.BusinessData assembly to make this code work.
The ExternalLink class used to represent our links in this sample is defined as:
Title will be read from the file name of the URL, this value will be the same as the Description property of the Link (type of SPFieldUrlValue), the Url property of the Link and the IconUrl will be read from the content of the URL file.
Note, that we use the SPFieldUrlValue type for the Link value.
We want our IconUrl property to be displayed as Icon field, so we have to add the DefaultDisplayName attribute to the TypeDescriptor.
The definition of the finder method in the model:
The methods defined in the ExternalLinkService class do nothing more than forwarding the calls to the corresponding static utility methods defined in the Utils class:
For the ReadList method the work is done by these methods:
It is important to note that the GetLink method does some kind of HTML manipulation of data if the link is requested for the finder method (forList is true). It assembles the HTML using the URL of the favicon or the URL of the general icgen.gif if no favicon specified.
Reading and writing the URL file is made by these methods:
After deployment the list should look like this:
If you failed to alter the value of the Folder property in the BDC model to match the path of your local links folder earlier, or if the folder contains no valid URL file, then the list is empty.
As you can see, we do not include the custom Link field in this view, I will give you the answer for this later.
Further things to note:
- The value of the Icon field is not rendered as HTML, so it is no user-friendly.
- The item menu is assigned to the Icon field.
- The list is ordered by the Icon field, not by the Title.
The definition of the specific finder method in the model:
Note the value of the TypeName attribute for the TypeDescriptor having Name “Link”. It is the full name (namespace and class name) of the type used for the custom field. It should match to the type defined in the entity class (see above the type of the Link property of the ExternalLink class).
You can define the custom field type for your type in BDC model using the SPCustomFieldType property of the corresponding TypeDescriptor. I should note, that although at the description of the BDC Custom Properties it is stated that “this property has no effect on methods other than the SpecificFinder”, fortunately it is not exact since you can use it in the case of Updater and Creator methods as well, as you will see soon. But it is true, that the value of this field is not displayed when included in the finder method. If you included the field in the finder, the field header would be displayed in the view but column would contain no value. This is why we have not included this field in the finder method.
I feel this limitation rather sad. If you get used to play with the different RenderPattern elements of your custom fields to customize the item rendering in the list view, you can feel your creativity somewhat restrained.
It is important, that you should use the TypeAsString property of the custom field type class ("URL" in this case) and not the TypeDisplayName property (would be "Hyperlink or Picture") when setting the value of the SPCustomFieldType property.
What if you want to use a custom field and set its properties before using?
Well, then I think you are in a trouble, as the BDC model provides no declarative way to set custom field properties.
You can try to run this code from a console application:
But running the code will result an SPException:
The field ‘Link’ cannot be updated. The field is in a field collection that cannot be updated, such as one returned as part of a query.
If you try to play with the SchemaXml property of the field, setting its value will throw an NotSupportedException.
You can probably workaround this (not yet tested) via inheriting your own custom control from the specific custom control and set properties to the desired values in your class. For example, you can derive an ImageLink custom field type from SPFieldUrl and have its default DisplayFormat set to Image. But creating and deploying a custom field for every and each customization request is rather painful.
For the ReadItem method specified for the SpecificFinder BDC method type the work is done by the GetItem method:
Displaying a link will be similar to this image, assuming there is a favicon specified in the URL.
Things to note:
- The value of the Icon field is more user-friendly than in the case of the list view (finder method). This is due to the little trick with the forList parameter in the GetLink method.
- The caption of the Title and Link fields are the same.
To tell the truth I’ve tried to remove the Title field from this view but without success. I found no declarative nor programmatic way for that.
For example, let’s see the following code:
But running this code will result an NotSupportedException:
Setting property ‘ShowInViewForms’ to value ‘False’ is not supported on Microsoft.SharePoint.SPFieldText for external lists.
The updater method is defined like this:
The following methods in the Utils class will do the job for the Update method:
In the SaveChanges method we change the filename itself (that means the Title field used as the identifier in our model) if the Description of the Link is changed. If there is already a file with the new name, the Title is not changed and it means that the Descriprion remains the same as well.
Note that the Title field is hidden due to the PreUpdaterField="true" setting in the TypeDescriptor.
The deleter method is the simplest one:
And in the Utils class:
The last method defined is the creator:
The Create method is used for URL file creation in the back end:
In this method we should return an ExternalLink entity based on the new URL file.
Note that the Title field is hidden due to the ReadOnly="true" setting in the TypeDescriptor.
Deploying the External List
The solution contains a list instance for our sample as well:
For the details of deploying an external list from Visual Studio 2010 solutions you can read more in this post of Yaroslav Pentsarskyy.
We completed a lot of things, but you may remember that our view created based on the Finder method is not really user-friendly yet. It is time to correct that.
Start SharePoint Designer, and on the Navigation bar (on the left) click on List and Libraries then select our external list called ExternalLinks on the right bottom side in the External Lists group.
Open the ExternalLink List view by double-clicking on it.
In the code view look for this code snippet:
Alter it as illustrated below to change the ordering and to add item context menu to Title field:
Note that even we set the menu to Title, the first field (IconUrl) will still have the menu.
In the design view, select the content of the Icon field cell. If you selected correctly, you should see the <xsl:value-of> tag. Select the Edit Tag… option.
Add the disable-output-escaping="yes" attribute (be sure to use standard quotation marks!) to the tag as shown below and apply the changes:
You can read more about the purpose of this action here.
Save the changes you made on the page, and refresh the view in the browser.
The favicon is shown where it is specified, where it is missing, a standard icon is shown.
When you position the mouse over the icon, the Title of the item is shown as a tooltip.
By clicking the link you open the target URL in a new browser window. The item context menu is bound to the Title, and the items are ordered by the Title as well.
BTW, if you need to change only the order, of course you don’t need to use SPD, simply modify the view on the SharePoint UI.
That is for today, and sorry for the long post. I hope it was worth reading so much and I plan to be back soon with another – bit more complex – BCS sample. You can download this sample from here (including the URL files used in the post).
Lessons learned when working on this sample:
You can use the built-in and custom field types in your BDC model. When setting the SPCustomFieldType property for the TypeDescriptor you should use the TypeAsString property of the custom field type. Use the corresponding field value type for these fields in the BDC model.
Using custom field types is not supported in the Finder views of the external lists.
The custom field support is limited another way also: you cannot set properties of the custom field declaratively, for example from your BDC model. Seems that there is no trivial workaround for this issue.
There are further developer oriented limitations when working with external lists, for example you cannot hide fields on specific view types, like edit or display view.
If you would like to rename your field on the UI, you should apply the DefaultDisplayName attribute with the same value to all instances of the same TypeDescriptor in the model file. If you set it for example only in the Finder method, it seems to have no effect. In this case the Name attribute is displayed.
You can display different values for the same item in the same field in different views (like Finder(s), SpecificFinder).
You can enable HTML rendering by altering the XSL of the XsltListViewWebPart in the .aspx file generated for the view using SPD (or custom code, not covered in this post). It requires circumspection as making HTML errors (like missing closing tags or extra quotes) may cause your view to be rendered totally wrong on the external list UI.
You can set the ordering field both by altering the views on the SharePoint UI or via XSL modification in SPD.
By default, the item menu is linked to the first field in the Finder view, but you can alter that by modifying the rendering XSL using SPD (or custom code, not covered in this post).
LobSystemInstance properties provide a great way to configure your BDC application. You can access these properties even from managed code.
You can alter even the value of the field you used as the identifier of your entity model.
You can deploy your external list declaratively from your Visual Studio solution.