Posts Tagged ‘Visual Studio 2010’
Upgrading a feature property
In SharePoint 2010 features can be upgraded, awesome!
I was just testing this when I discovered something curious when updating a property.
Suppose the following feature definition file:
<?xml version="1.0" encoding="utf-8" ?> <Feature xmlns="http://schemas.microsoft.com/sharepoint/" Version="1.0.0.0"> <Properties> <Property Key="MyProp" Value="initialValue" /> </Properties> </Feature>
The property value of the MyProp key is “initialValue”.
After adjusting the feature definition file to perform an upgrade the file looks like this:
<?xml version="1.0" encoding="utf-8" ?> <Feature xmlns="http://schemas.microsoft.com/sharepoint/" Version="1.1.0.0"> <UpgradeActions> <VersionRange BeginVersion="1.0.0.0" EndVersion="2.0.0.0"> <CustomUpgradeAction Name="UpgradeToOtherVersion"/> </VersionRange> </UpgradeActions> <Properties> <Property Key="MyProp" Value="newValue" /> </Properties> </Feature>
And I changed the property value of the MyProp key to “newValue”.
In the FeatureUpgrading event receiver I was checking the property value with the following statement:
SPFeatureProperty property1 = properties.Feature.Properties["MyProp"]; string initalValue = property1.Value;
and the result of property1.Value: “initialValue” ! I was suprised because I expected “newValue”.
After checking some other values and reading documentation on MSDN I came up with the following code to get the new property value:
SPFeatureProperty property2 = properties.Definition.Properties["MyProp"]; string updatedValue = property2.Value;
And the result:

The difference according to the documentation on MSDN is:
properties.Feature.Properties["MyProp"] – Gets the collection of properties for the Feature Link to MSDN
properties.Definition.Properties["MyProp"] – Gets a standardized property bag object that contains per-Feature settings that are specified in the Feature definition Link to MSDN
So I guess my conclusion is:
the property bag for the feature is updated to the new value after upgrading the feature and the property of the feature isn’t.
This sounds weird to me and I’m not sure I understand. Has anyone suggestions or experience with it?
[UPDATE]
While tweeting about this issue Chris O’Brien helped me out on this:
A feature has 1 definition and n instances. The code in FeatureUpgrading is used to upgrade the instances.
The property in the example updates the feature definition and not the running instances.
So properties.Feature.Properties["MyProp"] gets the property value of the running instance and properties.Definition.Properties["MyProp"] get the value of the property in the feature definition.
That’s it and not so weird after all! Thanks Chris!
SPDisposeCheck How to suppress a false positive
Recently I asked a question on Twitter on how to suppress a false positive with the SPDispose check tool and Wictor Wilén pointed me to the right direction.
Several times I’m asked about the solution so I’m sharing it with you now.
First of all you have to download the SPDisposeCheck tool and the SPDisposeCheckRules for Visual Studio 2010.
SPDisposeCheck tool: http://download.microsoft.com/download/B/4/D/B4D279A0-E159-40BF-A5E8-F49ABDBE95C7/SPDisposeCheck.msi
SPDisposeCheckRules for Visual Studio 2010: http://spdisposecheckstatic.codeplex.com/releases
After downloading install the SPDisposeCheck tool on your machine and extract the zip file for the rules. The zip file contains a readme-vs2010.txt with instructions. Follow these instructions.
The SPDisposeCheck tool is installed on the following location:
C:\Program Files (x86)\Microsoft\SharePoint Dispose Check
At this location a zip file called SPDisposeExamplesSource.zip can be found. In this zip file several classes are stored, one of them is the class SPDisposeCheckIgnoreAttribute.cs.
To suppress a false positive you have to include this class in your project.
After including the attribute to suppress a false positive can be used:
[SPDisposeCheckIgnoreAttribute(SPDisposeCheckID.SPDisposeCheckID_110, "Don't want to do it")]
public void CreatingSPSiteLeak()
{
SPSite siteCollection = new SPSite("http://moss");
// siteCollection leaked
}
The above example is an example from another class in the zip file: SPSiteLeak.cs
SharePoint 2010 Custom Health Rule to check if the Solution Resource timerjobs are enabled when the Sandboxed Code Service is started
To monitor additional items not by default set up in SharePoint, custom health analyzer rules can be defined. For example the sandboxed solutions can be monitored a little bit better than SharePoint default provides.
When the Microsoft SharePoint Foundation Sandboxed Code Service is started sandboxed solutions can be deployed and used. To monitor the resources consumed by the sandboxed solutions a couple of timerjobs do the work of measuring and collecting the consumed resources:
- Solution Daily Resource Usage Update
- Solution Resource Usage Log Processing
- Solution Resource Usage Update
Wouldn’t it be nice to be sure the timerjobs are running when the Sandboxed Code Service is running?
Please continue reading on how to set this up.
Building the rule
To set up a health analyzer rule, start with an empty SharePoint project. Add a class and inherit from SPHealthAnalysisRule. This is the class for the rule definition.
The class can also be inherited from SPRepairableHealthAnalysisRule. This means the rule can repair the problem. When using this the method Repair() has to be implemented as well.
To define a rule some properties has to be overridden, like
- Category – Health Analyzer Rule Definitions are grouped by Category in the default view.
- Summary – the title for the rule.
- Explanation – displayed in the Health Reports list when the rule fails.
- Remedy – displayed in the Health Reports list when the rule fails.
- ErrorLevel – severity of the failure of the rule.
All rule definitions can be found in the rule definition list: Central Administration, Monitoring, Review rule definitions.
The Health Reports list can be found in the Central Administration, Monitoring, Review problems and solutions.
The rule can be scheduled by overriding the AutomaticExecutionParameters property. In the get accessor return a SPHealthAnalysisRuleAutomaticExecutionParameters object.
When you don’t override the property the rule can be scheduled manually by a farm administrator.
public override SPHealthAnalysisRuleAutomaticExecutionParameters AutomaticExecutionParameters
{
get
{
SPHealthAnalysisRuleAutomaticExecutionParameters parameter = new SPHealthAnalysisRuleAutomaticExecutionParameters();
parameter.Schedule = SPHealthCheckSchedule.Hourly;
parameter.Scope = SPHealthCheckScope.Any;
parameter.RepairAutomatically = false;
parameter.ServiceType = typeof(SPTimerService);
return parameter;
}
}
In the code above the rule is scheduled on an hourly basis and the scope is set to SPHealthCheckScope.Any. This means the rule will run on the first available computer with the specified service.
The code that identifies the real problem is the Check() method. The Check() method returns the outcome of the check: SPHeathStatus.Failed or SPHealthStatus.Passed. When Failed is the outcome of the check the rule will be displayed in the Health Reports list.
public override SPHealthCheckStatus Check()
{
jobTitleOfDisabledJobs.Clear();
SPUserCodeService userCodeService = SPUserCodeService.Local;
if (userCodeService.IsEnabled)
{
using (SPSite site = new SPSite("your_site_url"))
foreach (SPJobDefinition job in site.WebApplication.JobDefinitions)
{
switch (job.Title)
{
case "Solution Daily Resource Usage Update":
AddJobTitle(job);
break;
case "Solution Resource Usage Log Processing":
AddJobTitle(job);
break;
case "Solution Resource Usage Update":
AddJobTitle(job);
break;
default:
break;
}
}
if (jobTitleOfDisabledJobs.Count != 0)
{
return SPHealthCheckStatus.Failed;
}
}
return SPHealthCheckStatus.Passed;
}
The above code first checks if the Sandboxes Code Service is started. If so, it checks if the timerjobs involved in measuring the resources consumed by the solutions are enabled.
The AddJobTitle() method adds the title(s) of the disabled job(s) to a generic list of strings:
private void AddJobTitle(SPJobDefinition job)
{
if (job.IsDisabled)
{
jobTitleOfDisabledJobs.Add(job.Title);
}
}
This list is used at the Explanation property to inform the farm administrator exactly which job(s) aren’t enabled:
public override string Explanation
{
get
{
string jobTitles = string.Empty;
for (int i = 0; i < jobTitleOfDisabledJobs.Count; i++)
{
jobTitles += jobTitleOfDisabledJobs[i].ToString();
if (i != jobTitleOfDisabledJobs.Count - 1)
{
jobTitles += " / ";
}
}
return "The Microsoft SharePoint Foundation Sandboxed Code Service is started, but not all the timerjobs are: " + jobTitles;
}
}
Deploy the rule
To deploy the rule add a feature, scope it to farm level, and an event receiver to the feature.
Override the FeatureInstalled and FeatureUninstalling to register and unregister the rule:
public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
try
{
Assembly currentAssembly = Assembly.GetExecutingAssembly();
IDictionary<Type, Exception> exceptions = SPHealthAnalyzer.RegisterRules(currentAssembly);
if (exceptions != null)
{
if (exceptions.Count == 0)
{
//ok
}
else
{
//something went wrong, take appropriate action
}
}
}
catch (Exception ex)
{
throw new Exception("There was an error registering the health rule: " + ex.Message);
}
}
public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
try
{
Assembly currentAssembly = Assembly.GetExecutingAssembly();
IDictionary<Type, Exception> exceptions = SPHealthAnalyzer.UnregisterRules(currentAssembly);
if (exceptions != null)
{
if (exceptions.Count == 0)
{
//ok
}
else
{
//something went wrong, take appropriate action
}
}
}
catch (Exception ex)
{
throw new Exception("There was an error removing the health rule: " + ex.Message);
}
}
After the deployment, the rule can be found in the rule definition list: Central Administration, Monitoring, Review rule definitions. The default view at this list is showing all the defined rules EXCEPT the rules defined with the categoy System. Ofcourse it’s possible to create an additional view to show all the rules.
Run and test the rule
The rule is now scheduled to run every hour. To speed things up select the rule and press Run Now. The timerjob which actually runs the Health Analyzer jobs, this is dependent of the schedule, is in this case Health Analysis Job (Hourly, Microsoft SharePoint Foundation Timer, Any Server). Make this timerjob also run now and check the Health Reports list.
Check if the rule fails when enabling and disabling the sandbox timerjobs which are checked in the rule. Note that the Explanation of the rule changes when different sandbox timerjobs are disabled or enabled.
Keep in mind when debugging the rule that you attach the debugger to the timer services: OWSTimer.exe process.

Issues
Register Assemly in GAC
When developing the rule the following error occurred in my environment:
Error occurred in deployment step ‘Add Solution’: Health analyzer rule registration requires that the {0} assembly be registered in the global assembly cache.
The workaround for me was to adjust the Site URL property of the project before every deployment. I know it’s not a nice solution and likely not THE solution, but it worked for me and restarting several services and jobs didn’t do the trick unfortunately.
Settings are not updated
If you change your mind on for example the category or explanation while developing it is possible that after the deployment of the solution with the changed items and the rule fails, the rule shows up at the ‘old’ category or with the ‘old’ explanation. This is one of the possible ‘issues’ which can occur if you don’t restart the Timer Service Recyle timerjob. This job is like an iisreset, but for the timer service, it recycles the Timer Service to free resources.
Summary
Health Analysis Rules are not that hard to program, except a few things to know, but can be really usefull to have an overview of issues at the farm.
Paging with Client OM and CAML
CAML can be used in the Client OM to query for example a list. When the list contains a lot of items it’s not a good idea to show all the items at once. CAML supports row limits, so a <RowLimit> element can be passed in the CAML query and show a subset of the results.
Maybe the user wants to browse through all the results, so all items has to be displayed on the page in some sort of form. Here paging of the results come in handy.
To use paging, the ListItemCollectionPosition property of the ListItemCollection object can be used.
To keep track of paging the ListItemCollectionPosition of the CAML query has to be set to the ListItemCollectionPosition of your own object. This way the position of the starting point of the query can be set before querying the list and iterate through the pages until there are no pages left anymore.
For testing purposes a Windows Forms application is created, with 2 buttons and a listbox.
The first button, named Start, gets the first 500 items of a list and displays the result as one item in the listbox. By pressing the second button, named Next, the next 500 results will be displayed until there are no pages left to display. When there are no pages left, the Next button is disabled. By pressing the Start button the process can be started again at the beginning.
In this example a list called LargeList is used, the list contains 2500 items.
The CAML query used gets the Title field of an item and set the RowLimit to 500 items. After getting the items the ListItemCollectionPosition is stored in a property called itemPosition to keep track of the position of the starting point of the next query.
As soon as the itemPosition equals null, the results of the last page are gathered.
The example code:
public Microsoft.SharePoint.Client.ListItemCollectionPosition itemPosition { get; set; }
public ClientContext context { get; set; }
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
listBoxResults.Items.Clear();
buttonNext.Enabled = true;
GetPage();
}
private void GetPage()
{
List largeList = context.Web.Lists.GetByTitle("LargeList");
CamlQuery query = new CamlQuery();
query.ListItemCollectionPosition = itemPosition;
query.ViewXml = "<View><FieldRef Name='Title' /><RowLimit>500</RowLimit></View>";
ListItemCollection collection = largeList.GetItems(query);
context.Load(collection);
context.ExecuteQuery();
itemPosition = collection.ListItemCollectionPosition;
string result = string.Empty;
foreach (ListItem item in collection)
{
result += item["Title"].ToString();
}
if (itemPosition == null)
{
listBoxResults.Items.Add(result + Environment.NewLine + " Position: Last page " + collection.Count + " items");
buttonNext.Enabled = false;
return;
}
listBoxResults.Items.Add(result + Environment.NewLine + " Position: " + itemPosition.PagingInfo);
}
private void buttonNext_Click(object sender, EventArgs e)
{
GetPage();
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
context.Dispose();
}
private void Form1_Load(object sender, EventArgs e)
{
context = new ClientContext("<your_context>");
}
A better user experience with the dialog framework and notifications
Today I am playing around with the dialog framework and simple ribbon buttons. I want the user to select one or more items from a list and update the Status field for all the items selected. The user can edit multiple items in datasheet view of course, but I’m making it just a little friendlier to the user.
I give myself two challenges for today:
Add a button to the ribbon, enabling it when one or more items in the list are selected and update the Status field to ‘Completed’ of the selected items. This will be described at the paragraph ‘Just the button’ below.
For more flexibility I will extend the above solution by a modal dialog where the user can choose a value for the Status column instead of setting the value to ‘Completed’ (and is not mentioned to the user anywhere), update the selected items and give the user a notification message if the update was successful and mentioning the Status value from the control on the modal dialog. This will be described at the paragraph ‘Modal dialog’ below.
The last option will give the user a better experience and will be a lot more flexible, because I’m not setting the value of the Status field in the code, but let the user choose from a predefined set of values.
Not really challenges, but I just want to point out a few things which are maybe interested to you. I’m not going to explain the basics of the ribbon or the dialog framework, because there are a lot of excellent posts out there.
Just the button
Add a button to the ribbon: please check out the cmdui.xml file located the SharePoint root folder, template\global\xml. Here you find a lot of definitions and examples you can use yourself and really helpful by positioning the controls on the ribbon.
To just enable a button when one or more items in a list are selected is quite easy:
when defining a CustomAction with for example a button, you also define a CommandUIHandler. One of the attributes is EnabledScript:
EnabledScript="javascript: function enableMarkAsCompletedButton(){
var items = SP.ListOperation.Selection.getSelectedItems();
return (items.length >= 1);
}
enableMarkAsCompletedButton();”
Check the above code to enable the button (in this case) only when one or more items are selected. Here the client object model for ECMA script is used to get the selected items.
Another attribute is CommandAction, the real action to occur when the button in the ribbon is clicked. The code used here:
CommandAction="javascript:
var context = SP.ClientContext.get_current();
var currentList = context.get_web().get_lists().getById(SP.ListOperation.Selection.getSelectedList());
var items = SP.ListOperation.Selection.getSelectedItems();
var singleItem;
for (var i in items) {
singleItem = currentList.getItemById(items[i].id);
singleItem.set_item('Status', 'Completed');
singleItem.update();
}
//actually submit
context.executeQueryAsync(OnSuccess, OnError);
function OnSuccess() {
window.location.href = window.location.href;
}
function OnError(sender, args) {
alert('Error' + args.get_message());
} "
First grab the context and the list we’re at. The getSelectedList() is the input of the getById() function. The result is the actual list where later the getItemById() function can be used on.
Also check the for-loop. You can’t use items[i].id directly in the getItemById() function on the list, but you have to grab the id of the single item and use this as the input parameter. Don’t use the context.load() function, just execute the query asynchronously. The OnSuccess() function refreshes the page so the adjusted value can be seen and an alert is displayed when an error occurs.
Modal dialog
By using a modal dialog and give the result back to the user the user experience will be much better. I don’t use a predefined value in the code but let the user choose which Status to set on all the selected items at once. Because I’m using a dialog some additional text to explain the function and result better will be convenient for the user.
For displaying a modal dialog the function SP.UI.ModalDialog.showModalDialog(options) will be used. The options I’m going to use here are the url, width, height and the most important to explain here the dialogReturnValueCallback.
The url is a custom page which will be opened. At the dialogReturnValueCallback a callback function will be specified, this means what is going to happen when the user closes the dialog. At our case the selected items in the list will be updated with the new status.
A lot of the above code can be reused at this scenario:
enabling the button when one or more list items are selected will not change at all.
updating the list items will occur at a different moment, because we’re going to display a dialog first to let the user choose the Status for the selected items.
First let’s look at the showModalDialog(options) and the page that will be opened at the url. I put the page at a subdirectory of the _layouts folder, so referencing is easy.
In the page itself I put a dropdown control with some status values and a button to actually set the status. For better user experience I will list the selected items at the model dialog, so the user is still aware of what items are going to change. To list the items selected I will add the parameters listguid and the id’s of the items selected to the url at the options for the showModalDialog function:
var options = {
url: '/_layouts/ITIdea.DialogFramework/PageSetStatus.aspx?listguid=' + SP.ListOperation.Selection.getSelectedList() + '&items=' + selectedItems,
height : 600,
width : 500,
dialogReturnValueCallback : CloseCallback};
SP.UI.ModalDialog.showModalDialog(options);
And at the Page_Load function of the page I’m getting the listguid and selected items and display it in a simple label control on the page (please do not use this code as production code!):
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["listguid"] != null && Request.QueryString["items"] != null)
{
string list = Request.QueryString["listguid"].Substring(1, Request.QueryString["listguid"].Length - 2);
Guid listGuid = new Guid(list);
List<string> selectedItems = new List<string>();
selectedItems.AddRange(Request.QueryString["items"].Split(','));
SPList selectedList = SPContext.Current.Web.Lists[listGuid];
string result = "Selected items: <br />";
foreach (string item in selectedItems)
{
result += selectedList.GetItemById(int.Parse(item)).Title + "<br />";
}
selectedItemsText.InnerHtml = result;
}
}
And this is how is looks like in its simplest form:

After the ‘Set’ button is selected the list items will be updated and for better user experience the user will be notified by a yellow notification on the right of the screen to what status the selected items are set. All this can be done at the function defined at dialogReturnValueCallback in the options of the showModalDialog, CloseCallback:
function CloseCallback(result, target) {
if(result == SP.UI.DialogResult.OK){
SP.UI.Notify.addNotification('Status value is set to ' + target, true);
//set the status of all the selected items to the text
AdjustFields(target);
}
if(result == SP.UI.DialogResult.Cancel){
SP.UI.Notify.addNotification('Result is Cancel');
}
}
function AdjustFields(newValue){
var context = SP.ClientContext.get_current();
var currentList = context.get_web().get_lists().getById(SP.ListOperation.Selection.getSelectedList());
var items = SP.ListOperation.Selection.getSelectedItems();
var singleItem;
for (var i in items) {
singleItem = currentList.getItemById(items[i].id);
singleItem.set_item('Status', newValue);
singleItem.update();
}
//actually submit
context.executeQueryAsync(OnSuccess, OnError);
}
function OnSuccess() {
setTimeout(window.location.href = window.location.href, 3000);
}
function OnError(sender, args) {
alert('Error' + args.get_message());
}
The code for actually update the selected list items is moved to the AdjustFields function with newValue as input parameter and executed at the callback function of the dialog. This newValue is the value selected in the dropdown by the user at the modal dialog. How did we get that value over here?
Here another function of the SP.UI.ModalDialog comes in: commonModalDialogClose().
With this function you can set your own return value which will be used at the callback function of the showModalDialog(). Real nice function!!
To set a custom return value for the callback function, I use the commonModalDialogClose at the click eventhandler for the Set button at the page which is displayed as the modal dialog:
function SetNewStatus_Click() {
var resultText = document.getElementById('StatusChoices').value;
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, resultText);
}
In the above code the element ‘StatusChoices’ is the id of the dropdown control with the different status values. With the commonModalDialogClose() the dialog result is set to OK and the result value is set to the selected value in the dropdownbox.
By setting the result to OK, the code in the CloseCallback() function will execute the code in the first if-statement. Here the message for the notification is set and the return value (target parameter, which was set at SetNewStatus_Click() ) is added to the notification message.
After explaining this simple example you’re getting the idea of a better user experience with modal dialogs and notification messages. Inform the user as much as you can, the options are given to you by SharePoint and who are we not using them…
Enable ECMA COM Intellisense Visual Studio 2010
While investigating and playing with the dialog framework of SharePoint 2010 I really missed some intellisense of the client object model for the javascript(ECMA) code. It seems real easy to enable intellisense and saves a lot of time!
First create a js file in Visual Studio 2010.
Add the line below as the first line:
/// <reference name="MicrosoftAjax.js" />
This line of script has to be referenced as the first line, because it has all the default methods for Sys.* available (this js is a Visual Studio file). Also the declaration of the js file which uses the intellisense is dependent of the order in which they appear in the js file. Some of the SP objects depend on this file.
After the base reference for Visual Studio add the SharePoint ECMA script files:
/// <reference path=”file://C:/Program Files/Common Files/Microsoft Shared/Web Server Extensions/14/TEMPLATE/LAYOUTS/SP.core.debug.js” />
/// <reference path=”file://C:/Program Files/Common Files/Microsoft Shared/Web Server Extensions/14/TEMPLATE/LAYOUTS/SP.debug.js” />
These two files are the primary files needed for the intellisense.
After these references you can add every debug.js file available in the SharePoint root(14) layouts folder you want.
For example developing the dialog framework add the following reference:
/// <reference path=”file://C:/Program Files/Common Files/Microsoft Shared/Web Server Extensions/14/TEMPLATE/LAYOUTS/SP.UI.Dialog.debug.js” />
When you add a reference and the intellisense is not updated with the last reference, press Ctrl-Shift-J and you will see the statusbar indicating the intellisense is updating:
![]()
Please remove the references to the debug.js files while deploying to a production environment.
More options: http://msdn.microsoft.com/en-us/library/ff798328.aspx
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!
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 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:

Set Developer Dashboard level by Visual Studio
In my previous post about the Developer Dashboard I showed you how to switch it on/off/on demand by PowerShell.
Ofcourse this can be done in Visual Studio as well:
SPWebService cs = SPWebService.ContentService; cs.DeveloperDashboardSettings.DisplayLevel = (SPDeveloperDashboardLevel)selectedValue; cs.DeveloperDashboardSettings.Update();
Make sure, if you make a webpart to set the developer dashboard level, you deploy this as a Farm Solution and deploy it to the Central Administration (Project Properties, set Site URL to your CA location).
The code will not work on another site, only at the CA, because the developer dashboard is a farm wide setting. If you do try to use the webpart in another site than CA, a security exception will be thrown:
System.Security.SecurityException: Access denied.
When you deploy the solution to the CA and try to use it on another site (or visa versa) you get the message:
A Web Part or Web Form Control on this Page cannot be displayed or imported. The type is not registered as safe.
After deploying a webpart to set the level of the Developer Dashboard, just go to the Central Administration e.g. to the Application Management page and edit the page. Two webpart zones will be visible and just add the webpart as you normally would.
An example:





