Archive for August, 2010

BCS model – a simple editable model

Let’s adjust the previous model to enable adding new items and edit existing ones. 

Open the previous project and open the design view of the model (.bdcm). In the BDC Method Details window select ‘Add a method’ and ‘Create Creator Method’. Two parameters are created, one for input, one as return parameter. Check the type names of both Type Descriptors. Both have to be set to the Customer entity. Probably they are set correctly already, because of the previous ReadList and ReadItem methods. Open the BDC Explorer and make sure the other type descriptors (the ones that make up a Customer) are present at the input and return parameter. Probably they also are there already.
Check the properties of the type descriptors of the input parameter ‘NewCustomer’. The property CreatorField is set to True here. With this parameter you can control the fields displayed on the new form. Since our CustomerId is an auto increment field, delete this type descriptor from the input parameter.
That’s it for the configuration, the only thing left is to update the code at the CustomerService class. As in the previous post I use Linq to Sql, an example:

        public static Customer CreateCustomer(Customer newCustomer)
        {
            using (LinqToSQLClassCustomerDataContext db = new LinqToSQLClassCustomerDataContext(CONNECTION_STRING))
            {
                CustomerBasic newItem = new CustomerBasic();
                newItem.CustomerName = newCustomer.CustomerName;
                newItem.CustomerCity = newCustomer.CustomerCity;
                db.CustomerBasics.InsertOnSubmit(newItem);
                db.SubmitChanges(); 

                Customer returnCust = new Customer
                {
                    CustomerId = newCustomer.CustomerId
                };

                return returnCust;
            }
        }

Deploy the solution and check out the list created on the previous version of this solution. The list seems fine and at the List Tools tab, Items, the New Item button is enabled. Select this button.
When expecting the new form, a Runtime Error occurs.
Open SharePoint Designer and select the list. In the next screen several items of the list are displayed, e.g. Settings, Views and… Forms! As you can see at the picture below there is no NewForm, that’s why the error occurs.
 

And checking the logfile:
SPException thrown: Message: Unable to find the default new form for list
Says the same, no New Form present. 

To get a full functioning list, create a new list based on the External Content Type and the NewForm is present:
  

Ofcourse SharePoint Designer can help you out without creating a new list by selecting NewForm at the Forms section:

When selecting ‘New Item’ in the browser a new Customer can be added.
    

The updater method is just as simple.
In the BDC Method Details window select ‘Add a method’ and ‘Create Updater Method’. One input parameter is created ‘customer’. Check the type name of the Type Descriptor. This has to be set to the Customer entity. Probably it is set correctly already, because of the previous defined methods. Open the BDC Explorer and make sure the other type descriptors (the ones that make up a Customer) are present at the input parameter. Probably they also are there already. Set the Read Only property of the CustomerId type descriptor to false and leave the Updater Field property set to True.    

Now update the code for the updated method to actually update the Customer.

        public static void UpdateCustomer(Customer customer)
        {
            using (LinqToSQLClassCustomerDataContext db = new LinqToSQLClassCustomerDataContext(CONNECTION_STRING))
            {
                CustomerBasic updateItem = (from c in db.CustomerBasics
                                            where c.CustomerId == customer.CustomerId
                                            select c).FirstOrDefault();
                updateItem.CustomerName = customer.CustomerName;
                updateItem.CustomerCity = customer.CustomerCity;
                db.SubmitChanges();
            }
        }

 

Deploy the solution and take a look at the list created with the previous version of the solution. Same story: Runtime Error; Edit Form not present. SharePoint Designer to the rescue: create a new Edit Form and voila!

Url parameters for SharePoint 2007

Nothing new, just a quick recap for the SharePoint 2007 people and the last time I was often asked about this.

No ‘Edit Page’ at ‘Site Actions’ menu

On the pages newform, editform and dispform (aspx pages for list item modifications) there is no ‘Edit Page’ menu option available at the ‘Site Actions’ menu.

When you want to add webparts on these pages you can use SharePoint Designer or add the toolpaneview parameter to the url.
Options for the toolpaneview parameter:
1 – Message in the toolpane: A webpart you attempted to change is either invalid or has been removed by another user. I don’t know where this one is being useful, anybody?
2 – Browse to add a webpart
3 – Search to add a webpart
4 – No toolpane view
5 – Import a custom webpart

Lost a webpart from your page?

If you closed a webpart on a page or think your page is loading slow, check out the webpart page maintenance by adding ‘contents=1′:
…/default.aspx?contents=1

jQuery SPServices and autocomplete

On Codeplex the SPServices library is available. This is a jQuery library for SharePoint Web Services.
One of the functions available in the library is the SPAutoComplete:
http://spservices.codeplex.com/wikipage?title=%24%28%29.SPServices.SPAutocomplete  

The SPAutocomplete lets you provide values for a Single line of text column from values in a SharePoint list. The function is highly configurable and can enhance the user experience with forms.  

To use this function you have to put it on a new item form. On one of the fields of this new item form the SPAutoComplete can be implemented and used.  

To make this work, create a new blank webpart page. Open the page in SharePoint Designer and insert a dataview on the page. At the Data Source Library select the list you want to create a new item form for and select Show Data. Select the desired fields to show on the new item form and select Insert Selected Fields as … New Item Form. Save the page and edit the page in the browser.  

Imagine:
I have a list called Customers with a Title column with the name of the customer. In another list I need these names also but I want to suggest the user who adds a new item which customers we already have and how these are spelled.  

Let’s proceed.
Edit the page in the browser and add a Content Editor Webpart, modify the webpart and show the Source Editor to add some code.

<script type="text/javascript" src="../ICTLibrary/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="../ICTLibrary/jquery.SPServices-0.5.4.min.js"></script>
 

<script type="text/javascript">
    $(document).ready(function() {
        $().SPServices.SPAutocomplete({
            sourceList: "Customers",
            sourceColumn: "Title",
            columnName: "CustomerName",
            numChars: 2,
            ignoreCase: true,
            slideDownSpeed: 100,
            debug: true
        });
    });
</script>

For all available options to set please take a look at the link provided earlier, but for the important ones here.
sourceList: the list to get the suggestions from
sourceColumn: the static column name to get the suggestions from
columnName: the displayname of the field in the new item form
You can hide the content editor webpart so you only see the new item form. Go ahead and type the first letters of a customername.

Ofcourse you want to use the autocomplete function on other pages or in other webparts and not only on a new item form.
For this purpose you can use the jQuery UI plugin (http://docs.jquery.com/UI/Autocomplete, implemented in release 1.8) in combination with the SPServices library.
With the SPServices library the items can be pulled out of the desired list and column and with the auto complete function of the jQuery UI the source can be set to the values to show.
To get the desired data from the list:

            $().SPServices({
                operation: "GetListItems",
                async: false,
                listName: "Customers",
                CAMLViewFields: '<ViewFields><FieldRef/></ViewFields>',
                CAMLQuery: '<Query><OrderBy><FieldRef Name=\'Title\' Ascending=\'True\' /></OrderBy></Query>',
                completefunc: function(xData, Status) {
                    $(xData.responseXML).find("[nodeName= z:row]").each(function() {
                        itemSource[k] = $(this).attr('ows_Title');
                        k = k + 1;
                    });
                }
            });

  

And use the gathered data in the input field at the page:

            $("input#autocompletebox").autocomplete({
                source: itemSource,
                minLength: 2
            });

Where ‘autocompletebox’ is the id of the input control:

<input id="autocompletebox" />

  

And the output of this all in the browser:

BCS model – a simple read only model

In the first part, BCS model – some basics , I talked about the items Visual Studio creates for you, the meaning of these items and some about renaming files. The next step is to create a simple model to show the functionality of the model.  

Just create a new project in Visual Studio based on the template ‘Business Data Connectivity Model’ and give the project a name. In the next screen you can see a BSC model can be deployed only as a farm solution, not a sandboxed solution, and select the site for debugging.  

Rename the class Entity1 to Customer, rename the file Entity1.cs to Customer.cs and update the design view of the model (.bdcm) by setting the name of the entity to Customer. By the last rename the Entity1Service is automatically renamed to CustomerService. A quick refresh of the previous post: ‘The entity on the design has a custom property which points to the entity service. With this connection the code in the service can be adjusted to the changes made in the design surface or BDC Method Details.‘

Delete the methods at the BDC Method Details window and clean the CustomerService by deleting the methods.
Change the Customer entity to:

    public partial class Customer
    {
        public int CustomerId { get; set; }
        public string CustomerName { get; set; }
        public string CustomerCity { get; set; }
    }

And update the design view by renaming Identifier1 to CustomerId and change its type to System.Int32. All in sync now.  

Now let’s create the methods for the entity and start with the simplest one, a Finder method to list all the Customers.
In the BDC Method Details window select ‘Add a method’ and ‘Create Finder Method’. The ReadList method is created now with a return type descriptor with the name CustomerList. Since this is just a name, check the Type Name in the properties window: System.Collections.Generic.IEnumerable`1[System.String]
We have to change the generic list of strings to a generic list of Customers by selecting the arrow next to the type, select the tab Current Project and select the Customer entity.

The type name changed now to:
System.Collections.Generic.IEnumerable`1[[ITIdea.BCSBasics.BdcModel1.Customer, BdcModelSub]]
And the CustomerService class is updated as well.The return type of the method is a generic list of Customer objects. The next thing we have to do is to specify our Customer object to return the fields representing the Customer object. Therefor we have to add additional type descriptors at the Customer return type at the BDC Explorer. 

Select in the BDC Explorer to the Customer type descriptor of the ReadList method. Right click and select Add Type Descriptor. Change the name to CustomerId and the type to System.Int32, set the Identifier property to CustomerId and ReadOnly to True. Add two others with the name CustomerName and type System.String and the name CustomerCity and type System.String.

When you don’t define the object and you create a list based on the entity (External Content Type) you will receive the following message when displaying the list:

To retrieve one customer at a time we create a Specific Finder method.  

In the BDC Method Details window select ‘Add a method’ and ‘Create Specific Finder Method’. The ReadItem method is created with two parameters: a return parameter customer and an input parameter customerId. The type descriptor’s type name of the customer parameter is set the System.String at the properties window, change this to return a Customer type.
The other type descriptors are already there because we defined them at the ReadList method.  

The last thing we have to do now is to write some implementation of our methods ReadItem and ReadList. Now change these method to return just one Customer at ReadItem and a list of Customers at ReadList.  (I will  leave this for your own fantasy, I use a Linq to Sql class to quickly connect to a table in a database)

Deploy the project and create a list based on this External Content type.

As you notice you can view all the Customers you defined in the ReadList method and you can view the details of one customer.
Of course you can change the displayname of the columns to whatever you want by changing the Default Display Name at the properties of a specific Type Descriptor in Visual Studio.  

In case you don’t see the contents of the list, check BCS - possible errors.

This is all great but it would be really nice to add new items and edit existing ones –> will be my next post.

BCS – Possible errors

It is possible you receive one the following messages after you deployed a BCS solutions to your SharePoint environment: 

Unable to display this Web Part. To troubleshoot the problem, open this Web page in a Microsoft SharePoint Foundation-compatible HTML editor such as Microsoft SharePoint Designer. If the problem persists, contact your Web server administrator.   

Correlation ID:{correlation GUID}  

Check the SharePoint logfile and perform a search on the correlation guid, this will help you determine the problem. 

Access denied by Business Data Connectivity  

In this case you have to set the object permissions in Central Administration; Application Management; Manage Service Applications; Business Data Connectivity Service.

Incorrect AutoSync specification for member ‘CustomerId’

Check if the primary key in the database is the same as in the Linq to Sql model. Set the AutoSync property in the Linq to Sql model to OnInsert.

jQuery intellisense for Visual Studio 2008

To enable jQuery intellisense for Visual Studio 2008 install SP1 first, here is the link: http://www.microsoft.com/downloads/details.aspx?FamilyId=FBEE1648-7106-44A7-9649-6D9F6D58056E&displaylang=en

Restart your system, you will be asked to do.

Install the VS2008 SP1 Hotfix KB 958502: http://code.msdn.microsoft.com/KB958502/Release/ProjectReleases.aspx?ReleaseId=1736
This hotfix adds jscript editor support for “-vsdoc.js” intellisense documentation files.

When you receive the message
“None of the products that are addressed by this software update are installed on this computer. Click Cancel to exit setup.”
make sure you installed VS2008 SP1.

After installing start Visual Studio and create a new ASP.NET project.
Add a folder and put the script file and the -vsdoc.js into this folder.

You can find these files at http://docs.jquery.com/Downloading_jQuery, the -vsdoc.js can be found at the Visual Studio link.

To add a reference in Default.aspx to the script file, drag the script file from the solution explorer to the source view of the aspx file. This adds the reference to your page:
<script src=”scripts/jquery-1.4.1.js” type=”text/javascript”></script>

To use the jQuery intellisense now add script tags en start to type $., you will see the intellisense show up:

By the way, VS 2010 has built-in support for –vsdoc files.

BCS model – some basics

To create a BCS model in Visual Studio, create a new project based on the template ‘Business Data Connectivity Model’ and give the project a name. In the next screen you can see a BSC model can be deployed only as a farm solution, not a sandboxed solution, and select the site for debugging. 

Visual Studio now creates a couple of things for you: 

1.    Entity1.cs – describes the schema for the entity; also known as External Content Type in Central Administration, Business Data Connectivity Service page; a class with properties.
2.    EntityService1.cs – implementation for CRUD methods. These methods, Create, Read, Update, Delete, can be implemented by the following BCS operations:   

  • Finder (e.g. ReadList)
  • SpecificFinder (e.g. ReadItem)
  • Creator (e.g. CreateItem)
  • Deleter (e.g. DeleteItem)
  • Updater (regular update and synchronize offline content back to the store)

Visual Studio creates ReadList and ReadItem example methods for you. 

3.    BdcModel1.bdcm – the model definition (diagram) in design view, the BDC Designer.
4.    BdcModel1.bdcm.diagram – the xml definition of the design layout of the model diagram. 

When you open the .bdcm file in Visual Studio a new Explorer window is available: the BDC Explorer (View, Other Windows, BDC Explorer).  The layout of this explorer can also be seen when you open the .bdcm file e.g. in Notepad. It is just an xml file which described the whole model: LobInstances, Entities, Methods and MethodInstances, everything. Of course Visual Studio is using this xml file to generate the contents of the BDC Explorer. 

Another new window can be used when viewing the .bdcm file: BDC Method Details. As the name suggests the details of the methods of the selected entity are displayed: the mapping to the method name and parameters with the Direction (In, Out, InOut, Return) and the Type Descriptor (e.g. Entity1 at ReadItem and IEnumerable<Entity1> at ReadList for the return parameters). You can select an entity on the designer window or the BDC Explorer. 

When you don’t like the default names for e.g. Entity1, I don’t, you can rename the entity. After renaming the entity switch to the design view of the model. Here the entities name still is Entity1. So make sure you keep in mind there’s no automatic update between the entity definition and the entity design (the model), because the entity on the design represents the metadata and it’s our responsibility to provide the mapping between the code and the metadata. 

The entity on the design has a custom property which points to the entity service. With this connection the code in the service can be adjusted to the changes made in the design surface or BDC Method Details. 

Keep in mind that the initially generated ReadList and ReadItem methods in the service are not deleted when you delete the methods at the design surface or BDC Method Details. I don’t know why, loosely coupled? The methods you create yourself are updated very well. 

Just delete the generated methods in the BDC Method Details and update the service file. 

Let’s create a Specific Finder method ourselves by selecting ‘Add a method’ in the BDC Method Details pane and select ‘Create Specific Finder Method’. A method is created with the default name ‘ReadItem’ with a return parameter with the name ‘person’ and Type Descriptor ‘Person’. Remember that the Type Descriptor displayed here is just a name; it doesn’t tell you the type of the return parameter. At the properties window of the Type Descriptor you will find a property ‘Type Name’, that’s your type. The default type here is System.String, change this to your type. The format will be <namespace>.<class>, <External System Name> 

When you create the project the model is named BdcModel1. This name seems to appear on different places. Can I rename this without punishment? 

In the BDC Explorer the name BdcModel1 appears three times:

I guess the name of the LobSystemInstances can be changed without punishment at this time, because it is an instance name I don’t use it anywhere because I have basic code. So I start a brand new project and I change the LobSystemInstance name from BdcModel1 to BdcLobInstance. Where can I find this change after deployment? 

Central Administration, Business Data Connectivity Service page: no changes at all. I expected a rename to happen on the External System Instance name:
 

And when creating an external list based on the external content type I expected the name of the datasource to change, but no renaming done… 

Well, allright then, let’s rename the model itself in the BDC Explorer from BdcModel1 to BdcModelChanged:
 

The model is renamed as expected:
 

And the Lob instance name is also renamed!
 

And when creating an external list based on the external content type:
 

So, something is wrong with my system or the model itself has to be renamed in order to rename the LobSystemInstance name in the browser. 

We still have two items with the same name, let’s rename them too:
 

The BDC Model name is BdcModelMain, the External System Name is BdcModelSub and the External System Instance Name is BdcLobInstance. All renamed! 

A summary in the following picture: