You are here: Home

SharePoint Dispose Checker – Even more useful than expected

Posted by adrh
No Comments »

By now you have probably heard that the SharePoint Dispose Checker has been released. It's an excellent tool for checking you are disposing of your SharePoint objects correctly!

I downloaded it this morning as soon as I read about it just to see if I have really been as conscientious as I thought I had. Smile

Turns out, according to the output from the tool that I have done a pretty good job of cleaning up after myself. In the 10,000 lines of code mostly devoted to interrogating the SharePoint structure there were only 15 issues raised and all but 2 were false positives – darn those UserProfile personal site objects!

What did surprise me was that the false positives were actually quite useful in bringing to light some areas of the code that were less than perfect. For example, where I had used two instances of the same site in the same code block where one would have sufficed or where although objects were disposed of in a finally block, there were instances where exceptions further up in the code could have lead to one of several objects not being disposed correctly. It also highlighted some areas where although there was a disposal in the finally block the code looked much neater if it was replaced with a using block.

I'd recommend that you run the tool over your code no matter how careful you are for the review value alone.

I'm going to put this into my projects build events – and if I get really keen perhaps I'll parse the output to remove the known false positives automatically.

I wonder why it won't run against the assemblies in the ISAPI directory… Wink

SharePoint Dispose Checker – Even more useful than expected

Posted by adrh
No Comments »

By now you have probably heard that the SharePoint Dispose Checker has been released. It's an excellent tool for checking you are disposing of your SharePoint objects correctly!

I downloaded it this morning as soon as I read about it just to see if I have really been as conscientious as I thought I had. Smile

Turns out, according to the output from the tool that I have done a pretty good job of cleaning up after myself. In the 10,000 lines of code mostly devoted to interrogating the SharePoint structure there were only 15 issues raised and all but 2 were false positives – darn those UserProfile personal site objects!

What did surprise me was that the false positives were actually quite useful in bringing to light some areas of the code that were less than perfect. For example, where I had used two instances of the same site in the same code block where one would have sufficed or where although objects were disposed of in a finally block, there were instances where exceptions further up in the code could have lead to one of several objects not being disposed correctly. It also highlighted some areas where although there was a disposal in the finally block the code looked much neater if it was replaced with a using block.

I'd recommend that you run the tool over your code no matter how careful you are for the review value alone.

I'm going to put this into my projects build events – and if I get really keen perhaps I'll parse the output to remove the known false positives automatically.

I wonder why it won't run against the assemblies in the ISAPI directory… Wink

Yet Another SharePoint Conference Post

Posted by adrh
No Comments »

Yep, BandWagon.JumpOn();!

I'm off to Seattle on Sunday for the SharePoint Conference.

Hopefully I'll be able to get in the door at Kells and put some faces to names! I've never been there, but judging by the number of people interested, I hope they have a large place and a large supply of tasty bevies!

If you're going up from down-under and willing to discuss how great the Blues look this season over a cold one, lemme know! Smile

Yet Another SharePoint Conference Post

Posted by adrh
No Comments »

Yep, BandWagon.JumpOn();!

I'm off to Seattle on Sunday for the SharePoint Conference.

Hopefully I'll be able to get in the door at Kells and put some faces to names! I've never been there, but judging by the number of people interested, I hope they have a large place and a large supply of tasty bevies!

If you're going up from down-under and willing to discuss how great the Blues look this season over a cold one, lemme know! Smile

2008'ified

Posted by adrh
No Comments »

Actually I've been 2008'ed for quite a while now, but only recently fully 2008'rtm'd!

In a recent fit of over-exuberance (somewhat short of the Steve Ballmer opening keynote level mind you), I decided to embark on an upgrade journey.

The plan was to upgrade the development environment for our Product's Server component (including SharePoint Solutions) to Visual Studio 2008, nuke my Vista Machine and re-birth it as a Windows Server 2008 development machine – no more VPC dev for me! Oh, and just for kicks – move our projects from Team Foundation Server 2005 to 2008…

To be honest, I was kind of expecting something to go wrong so I backed up everything – the source, my development server (24Gb of VPC), my desktop and the VPC that TFS is running on.

I need not have bothered really (although something would have happened if I didn't) because it took me nearly as long to do all the backing up as it did to do the upgrades!

For Visual Studio 2005 -> 2008 I checked out the project, opened it in VS 2008, let the wizard run, ignored a few warnings and voila – upgraded! This is a pretty complex sort of solution, made up of a dozen projects, tens of thousands of lines of code, custom targets and build events etc, and so I was a little uneasy until we'd re-built and tested everything, but after some pretty thorough testing everything came through perfectly!

The desktop upgrade was also very smooth. Well, it was really a re-build from scratch, but the Features concept in Windows Server 2008 makes things a little quicker, and once I got over the issue of having to slipstream SP1 MOSS with the help of this post I was done. In search of the best possible experience (and so I didn't get Vista envy), I also ran through the tweaks provided here. I noticed today that there are a few more in Part 2 which look interesting like adjusting the priority for foreground tasks, but I'm certainly not complaining. It performs very, very well – and it looks pretty. Smile

TFS it turned out was the easiest of the lot! I was really careful with this one, not only did I back up the databases, but I also made a copy of the VPC – just in case. I did a bit of trawling through the net to check for any nasty surprises, and I'm sure that there are people for whom this has not been smooth sailing, but for me it was simply a matter of un-installing TFS 2005, without removing the database and installing 2008 – which prompted be to use the existing databases – and hey presto, 2008'ified!!

In summary, I'm extremely happy with the performance of the whole environment, the speed at which I was able to get set up with the latest and greatest and the lack of gotchas that often accompany these sorts of exercises!

[Feeling brave]And now lets migrate our Visual SourceSafe database…

 

 

2008'ified

Posted by adrh
No Comments »

Actually I've been 2008'ed for quite a while now, but only recently fully 2008'rtm'd!

In a recent fit of over-exuberance (somewhat short of the Steve Ballmer opening keynote level mind you), I decided to embark on an upgrade journey.

The plan was to upgrade the development environment for our Product's Server component (including SharePoint Solutions) to Visual Studio 2008, nuke my Vista Machine and re-birth it as a Windows Server 2008 development machine – no more VPC dev for me! Oh, and just for kicks – move our projects from Team Foundation Server 2005 to 2008…

To be honest, I was kind of expecting something to go wrong so I backed up everything – the source, my development server (24Gb of VPC), my desktop and the VPC that TFS is running on.

I need not have bothered really (although something would have happened if I didn't) because it took me nearly as long to do all the backing up as it did to do the upgrades!

For Visual Studio 2005 -> 2008 I checked out the project, opened it in VS 2008, let the wizard run, ignored a few warnings and voila – upgraded! This is a pretty complex sort of solution, made up of a dozen projects, tens of thousands of lines of code, custom targets and build events etc, and so I was a little uneasy until we'd re-built and tested everything, but after some pretty thorough testing everything came through perfectly!

The desktop upgrade was also very smooth. Well, it was really a re-build from scratch, but the Features concept in Windows Server 2008 makes things a little quicker, and once I got over the issue of having to slipstream SP1 MOSS with the help of this post I was done. In search of the best possible experience (and so I didn't get Vista envy), I also ran through the tweaks provided here. I noticed today that there are a few more in Part 2 which look interesting like adjusting the priority for foreground tasks, but I'm certainly not complaining. It performs very, very well – and it looks pretty. Smile

TFS it turned out was the easiest of the lot! I was really careful with this one, not only did I back up the databases, but I also made a copy of the VPC – just in case. I did a bit of trawling through the net to check for any nasty surprises, and I'm sure that there are people for whom this has not been smooth sailing, but for me it was simply a matter of un-installing TFS 2005, without removing the database and installing 2008 – which prompted be to use the existing databases – and hey presto, 2008'ified!!

In summary, I'm extremely happy with the performance of the whole environment, the speed at which I was able to get set up with the latest and greatest and the lack of gotchas that often accompany these sorts of exercises!

[Feeling brave]And now lets migrate our Visual SourceSafe database…

 

 

Free SharePoint Business Data Catalog Column

Posted by adrh
No Comments »

I have decided to release the custom BDC column that I created to the public domain. This custom column type provides a BDC Column type that can be created at the Site Column level and therefore used in Site Content Types. Out of the box this is not possible, and the ability to reuse BDC columns across sites and content has been identified as a common requirement. At this stage there are a number of things that are not yet implemented, including related fields, refreshing and nicer admin UI. However, I have created a Project on CodePlex so if you are interested in participating let me know! There is plenty of scope for features and function!

The new column is included in a SharePoint Solution (.wsp package) and can be deployed to SharePoint via the standard solution deployment framework.

Once installed a new column type is available to be chosen when creating columns in lists and when creating site columns:

When the BDC field type is selected the user is presented with a custom UI which displays all BDC Applications (and their Entities) registered on the current Server's Share Services Provider. The user also has the ability to set the fields that will be displayed in the Entity picker dialog when searching.

 Enough of the UI already, where's the code I hear you ask! … 

To get the data for the Application and Entity drop downs, we query the BDC metadata:

//Declare the relevent references
using Microsoft.Office.Server.ApplicationRegistry.Runtime;
using Microsoft.Office.Server.ApplicationRegistry.MetadataModel;

For the Applications.

//Get the Line of Business Instances.
NamedLobSystemInstanceDictionary sysInstances = ApplicationRegistry.GetLobSystemInstances();
cboApplications.Items.Clear();

//Loop through their names and add them to the drop down.
foreach (String name in sysInstances.Keys)
{
 cboApplications.Items.Add(name);
}

For the Entities, once an application is selected.

LobSystemInstance currentInstance = sysInstances[cboApplications.SelectedValue];

//Get the Entities for the given Application.
NamedEntityDictionary currentEntities = currentInstance.GetEntities();

foreach (String name in currentEntities.Keys)
{
 cboEntities.Items.Add(name);
}

Once created the column appears as a Site Column, and is available for use in Content Types.

When rendered in a list form, the field is very similar to the out of the box BDC column:

 

The picker dialog used to find and select Entity items is almost identical to the standard SharePoint BDC Picker. This dialog is AJAX enabled so that if AJAX is enabled on the server the user will experience the AJAX feel, ie. no page refreshes for search and selection. The fall back if AJAX is not enabled is a standard aspx style form with full page refresh required for operations such as searching. There is a great blog entry from the Microsoft SharePoint Team (via Mike Ammerlaan's blog on the subject) on Integrating ASP.Net AJAX with SharePoint that you should read if you want AJAX to be available on you SharePoint server. If you install your AJAX enabled solution on a server where this process is not complete, it should still function in the standard ASP.Net (ie. without AJAX) way. In theory, now that SP1 is out this is supported too, although I'm not sure that configuring it is any easier…

The Pop Up is called via a JavaScript function on the book image above. This function build a URL based on the Application, Entity and Display Fields properties of the column. To save time and make the popup consistent with the standard UI, it is based on the pickerdialog.master Master page.

The fields displayed in the list view are set when the column is defined, but can be modified once the column is created by editing the settings of the new column.

   
We use the following code to get the list of Finders and populate the dropdown of fields to search on. Finders are defined in the XML definition of the Application and control the way data is retrieved from the external source in relation to searching.

NamedLobSystemInstanceDictionary sysInstances = ApplicationRegistry.GetLobSystemInstances();

LobSystemInstance myIns = sysInstances[Request["BDCApplication"]];

Entity myEntity = myIns.GetEntities()[Request["BDCEntity"]];

FilterCollection fc = myEntity.GetFinderFilters();

The GridView containing the search results is contained within an AJAX UpdatePanel so that operations that would normally cause postback (and hence full page refreshes) are handled in the background. Inside the CreateChildControls we set up the AJAX UpdatePanel, GridView and Trigger Controls.

dvUpdatePanel = new System.Web.UI.UpdatePanel();

ajaxScriptManager = new System.Web.UI.ScriptManager();
ajaxScriptManager.EnablePartialRendering = true;
Controls.Add(ajaxScriptManager);

//Fixup the UpdatePanel. This function is defined in the blog from SharePoint Team on AJAX and SharePoint.
EnsureUpdatePanelFixups();

//Create a conditional Update Panel and make sure the Children of the Panel cause updates.
dvUpdatePanel.UpdateMode = System.Web.UI.UpdatePanelUpdateMode.Conditional;
dvUpdatePanel.ChildrenAsTriggers = true;
dvUpdatePanel.ContentTemplateContainer.Controls.Add(gvResults);

//Create a postback trigger on the search button to handle the search.
System.Web.UI.AsyncPostBackTrigger uptTrigger=new System.Web.UI.AsyncPostBackTrigger();
uptTrigger.ControlID = btnGoSearch.UniqueID;
uptTrigger.EventName = "Click";
dvUpdatePanel.Triggers.Add(uptTrigger);

//Set up a new SharePoint Grid View and turn off Auto Generate so we can control the columns.
gvResults = new SPGridView();
gvResults.ID="gvResults";
gvResults.AutoGenerateColumns = false;

 

Searching for Entities to show in the GridView is handled using the objects and methods provided by the SharePoint object model:

NamedLobSystemInstanceDictionary sysInstances = ApplicationRegistry.GetLobSystemInstances();
LobSystemInstance myIns = sysInstances[Request["BDCApplication"]];
Entity myEntity = myIns.GetEntities()[Request["BDCEntity"]];

//Build up a finder collection which is the query for the BDC source.
FilterCollection fc = myEntity.GetFinderFilters();

for (int iCounter = 0; iCounter < fc.Count; iCounter++)
      {
       if (fc[iCounter].Name == sFinderName || sFinderName == "")
            {
             switch (fc[iCounter].GetType().FullName)
                  {
                   case "Microsoft.Office.Server.ApplicationRegistry.Runtime.WildcardFilter":
                         ((WildcardFilter)fc[iCounter]).SystemIndependentValue = "*" + sQueryString + "*";
    break;
   case "Microsoft.Office.Server.ApplicationRegistry.Runtime.ComparisonFilter":
                         ((ComparisonFilter)fc[iCounter]).Value = Convert.ChangeType(sQueryString, ((ComparisonFilter)fc[iCounter]).GetFilterValueType());
                               break;
   case "Microsoft.Office.Server.ApplicationRegistry.Runtime.LimitFilter":
                         ((LimitFilter)fc[iCounter]).Value = Math.Min(0xc9, ((LimitFilter)fc[iCounter]).MaximumValue);
                               break;
     }
      }
 }

IEntityInstanceEnumerator prodEntityInstanceEnumerator = myEntity.FindFiltered(fc, myIns);

//Create a data table to store the results.
DataTable Results = new DataTable("BDCData");
Resultset.Tables.Add(Results);

//Get the collection of IDs and create an array to store their names.
IdentifierCollection EntIDS = myEntity.GetIdentifiers();
string[] sIDNames = new string[EntIDS.Count];

//Get the names.
int nCounter = 0;

foreach (Identifier currentID in EntIDS)
{
 sIDNames[nCounter] = currentID.Name;
 nCounter++;
}

//Add columns to the results data table named as per the Entities fields.
//Check if there any of the fields have show in picker set so we know to display only those fields.
Boolean blnShowInPickers = false;
foreach (Field f in myEntity.GetFinderView().Fields)
 {
        if (f.TypeDescriptor.GetProperties().ContainsKey("ShowInPicker"))
              {
               if (((Boolean)f.TypeDescriptor.GetProperties()["ShowInPicker"]))
               {
                     blnShowInPickers = true;
    }
   }
 }

DataColumn currentColumn = null;
foreach (Field f in myEntity.GetFinderView().Fields)
      {
 //Add the default display name to the caption if there is one so we can pull it out when we create the list.
       if (f.DefaultDisplayName == "")
            {
             currentColumn = Results.Columns.Add(f.Name);
     }
            else
            {
             currentColumn = Results.Columns.Add(f.Name);
                currentColumn.Caption = f.DefaultDisplayName;
     }

            if (blnShowInPickers)
            {
  //Only show fields that have show in picker set (if any do).
             if (f.Name != sTitle)
                  {
                   if (f.TypeDescriptor.GetProperties().ContainsKey("ShowInPicker"))
                        {
                         if (((Boolean)f.TypeDescriptor.GetProperties()["ShowInPicker"]))
                              {
                               currentColumn.ExtendedProperties.Add("ShowInPicker", "TRUE");
         }
         else
                              {
                               currentColumn.ExtendedProperties.Add("ShowInPicker", "FALSE");
         }
   }
    }
                  else
                  {
                   currentColumn.ExtendedProperties.Add("ShowInPicker", "TRUE");
    }
     }
            else
            {
  //Else if the field is an identifier or it's the title field then show it.
             if (f.TypeDescriptor.ContainsIdentifier || f.Name == sTitle)
                  {
                   currentColumn.ExtendedProperties.Add("ShowInPicker", "TRUE");
    }
                  else
                  {
                   currentColumn.ExtendedProperties.Add("ShowInPicker", "FALSE");
      }
      }
 }

//Loop through the found Entity instances and add them to the results.
while (prodEntityInstanceEnumerator.MoveNext())
{
 try
 {
  IEntityInstance IE = prodEntityInstanceEnumerator.Current;
  DataRow newResultRow = Results.NewRow();
  System.Collections.IList MyList = (System.Collections.IList)IE.GetIdentifierValues();

  //Create an array to hold the identifiers.
  object[] oIdentitiers = new object[sIDNames.Length];

  for (int iCounter = 0; iCounter < MyList.Count; iCounter++)
  {
   oIdentitiers[iCounter] = MyList[iCounter].ToString();
  }

  foreach (Field f in myEntity.GetFinderView().Fields)
  {
   if (IE[f] != null)
   {
    newResultRow[f.Name] = IE[f];
   }
  }

  Results.Rows.Add(newResultRow);
 }

 catch (Exception rowex)
 {
 }
}

//Grab the Display Fields and add columns for them in the Grid View.
gvResults.DataSource = Resultset;
string[] keys = Request["DisplayFields"].ToUpper().Split(',');
gvResults.DataKeyNames = keys;
gvResults.Columns.Clear();

foreach (DataColumn currentCol in ((DataTable)gvResults.DataSource).Columns)
{
        string[] displayFields = Request["DisplayFields"].ToUpper().Split(',');
        if (Array.BinarySearch(displayFields,currentCol.ColumnName.ToString().ToUpper())>=0)
  
 {
                BoundField newfield=new BoundField();
                newfield.HeaderText=currentCol.ColumnName.ToString();
                newfield.DataField=currentCol.ColumnName.ToString();
         gvResults.Columns.Add(newfield);
 }
}

//Bind the results to the grid.
gvResults.DataBind();

Feel free to wander over to CodePlex and grab a copy if this is a requirement for you or your clients and feel free to offer any suggestions you think of!

I'm off for a month with the Kids and the Family, so I wish you all a great Xmas, Holiday, or work time!

 

 

 

Free SharePoint Business Data Catalog Column

Posted by adrh
No Comments »

I have decided to release the custom BDC column that I created to the public domain. This custom column type provides a BDC Column type that can be created at the Site Column level and therefore used in Site Content Types. Out of the box this is not possible, and the ability to reuse BDC columns across sites and content has been identified as a common requirement. At this stage there are a number of things that are not yet implemented, including related fields, refreshing and nicer admin UI. However, I have created a Project on CodePlex so if you are interested in participating let me know! There is plenty of scope for features and function!

The new column is included in a SharePoint Solution (.wsp package) and can be deployed to SharePoint via the standard solution deployment framework.

Once installed a new column type is available to be chosen when creating columns in lists and when creating site columns:

When the BDC field type is selected the user is presented with a custom UI which displays all BDC Applications (and their Entities) registered on the current Server's Share Services Provider. The user also has the ability to set the fields that will be displayed in the Entity picker dialog when searching.

 Enough of the UI already, where's the code I hear you ask! … 

To get the data for the Application and Entity drop downs, we query the BDC metadata:

//Declare the relevent references
using Microsoft.Office.Server.ApplicationRegistry.Runtime;
using Microsoft.Office.Server.ApplicationRegistry.MetadataModel;

For the Applications.

//Get the Line of Business Instances.
NamedLobSystemInstanceDictionary sysInstances = ApplicationRegistry.GetLobSystemInstances();
cboApplications.Items.Clear();

//Loop through their names and add them to the drop down.
foreach (String name in sysInstances.Keys)
{
 cboApplications.Items.Add(name);
}

For the Entities, once an application is selected.

LobSystemInstance currentInstance = sysInstances[cboApplications.SelectedValue];

//Get the Entities for the given Application.
NamedEntityDictionary currentEntities = currentInstance.GetEntities();

foreach (String name in currentEntities.Keys)
{
 cboEntities.Items.Add(name);
}

Once created the column appears as a Site Column, and is available for use in Content Types.

When rendered in a list form, the field is very similar to the out of the box BDC column:

 

The picker dialog used to find and select Entity items is almost identical to the standard SharePoint BDC Picker. This dialog is AJAX enabled so that if AJAX is enabled on the server the user will experience the AJAX feel, ie. no page refreshes for search and selection. The fall back if AJAX is not enabled is a standard aspx style form with full page refresh required for operations such as searching. There is a great blog entry from the Microsoft SharePoint Team (via Mike Ammerlaan's blog on the subject) on Integrating ASP.Net AJAX with SharePoint that you should read if you want AJAX to be available on you SharePoint server. If you install your AJAX enabled solution on a server where this process is not complete, it should still function in the standard ASP.Net (ie. without AJAX) way. In theory, now that SP1 is out this is supported too, although I'm not sure that configuring it is any easier…

The Pop Up is called via a JavaScript function on the book image above. This function build a URL based on the Application, Entity and Display Fields properties of the column. To save time and make the popup consistent with the standard UI, it is based on the pickerdialog.master Master page.

The fields displayed in the list view are set when the column is defined, but can be modified once the column is created by editing the settings of the new column.

   
We use the following code to get the list of Finders and populate the dropdown of fields to search on. Finders are defined in the XML definition of the Application and control the way data is retrieved from the external source in relation to searching.

NamedLobSystemInstanceDictionary sysInstances = ApplicationRegistry.GetLobSystemInstances();

LobSystemInstance myIns = sysInstances[Request["BDCApplication"]];

Entity myEntity = myIns.GetEntities()[Request["BDCEntity"]];

FilterCollection fc = myEntity.GetFinderFilters();

The GridView containing the search results is contained within an AJAX UpdatePanel so that operations that would normally cause postback (and hence full page refreshes) are handled in the background. Inside the CreateChildControls we set up the AJAX UpdatePanel, GridView and Trigger Controls.

dvUpdatePanel = new System.Web.UI.UpdatePanel();

ajaxScriptManager = new System.Web.UI.ScriptManager();
ajaxScriptManager.EnablePartialRendering = true;
Controls.Add(ajaxScriptManager);

//Fixup the UpdatePanel. This function is defined in the blog from SharePoint Team on AJAX and SharePoint.
EnsureUpdatePanelFixups();

//Create a conditional Update Panel and make sure the Children of the Panel cause updates.
dvUpdatePanel.UpdateMode = System.Web.UI.UpdatePanelUpdateMode.Conditional;
dvUpdatePanel.ChildrenAsTriggers = true;
dvUpdatePanel.ContentTemplateContainer.Controls.Add(gvResults);

//Create a postback trigger on the search button to handle the search.
System.Web.UI.AsyncPostBackTrigger uptTrigger=new System.Web.UI.AsyncPostBackTrigger();
uptTrigger.ControlID = btnGoSearch.UniqueID;
uptTrigger.EventName = "Click";
dvUpdatePanel.Triggers.Add(uptTrigger);

//Set up a new SharePoint Grid View and turn off Auto Generate so we can control the columns.
gvResults = new SPGridView();
gvResults.ID="gvResults";
gvResults.AutoGenerateColumns = false;

 

Searching for Entities to show in the GridView is handled using the objects and methods provided by the SharePoint object model:

NamedLobSystemInstanceDictionary sysInstances = ApplicationRegistry.GetLobSystemInstances();
LobSystemInstance myIns = sysInstances[Request["BDCApplication"]];
Entity myEntity = myIns.GetEntities()[Request["BDCEntity"]];

//Build up a finder collection which is the query for the BDC source.
FilterCollection fc = myEntity.GetFinderFilters();

for (int iCounter = 0; iCounter < fc.Count; iCounter++)
      {
       if (fc[iCounter].Name == sFinderName || sFinderName == "")
            {
             switch (fc[iCounter].GetType().FullName)
                  {
                   case "Microsoft.Office.Server.ApplicationRegistry.Runtime.WildcardFilter":
                         ((WildcardFilter)fc[iCounter]).SystemIndependentValue = "*" + sQueryString + "*";
    break;
   case "Microsoft.Office.Server.ApplicationRegistry.Runtime.ComparisonFilter":
                         ((ComparisonFilter)fc[iCounter]).Value = Convert.ChangeType(sQueryString, ((ComparisonFilter)fc[iCounter]).GetFilterValueType());
                               break;
   case "Microsoft.Office.Server.ApplicationRegistry.Runtime.LimitFilter":
                         ((LimitFilter)fc[iCounter]).Value = Math.Min(0xc9, ((LimitFilter)fc[iCounter]).MaximumValue);
                               break;
     }
      }
 }

IEntityInstanceEnumerator prodEntityInstanceEnumerator = myEntity.FindFiltered(fc, myIns);

//Create a data table to store the results.
DataTable Results = new DataTable("BDCData");
Resultset.Tables.Add(Results);

//Get the collection of IDs and create an array to store their names.
IdentifierCollection EntIDS = myEntity.GetIdentifiers();
string[] sIDNames = new string[EntIDS.Count];

//Get the names.
int nCounter = 0;

foreach (Identifier currentID in EntIDS)
{
 sIDNames[nCounter] = currentID.Name;
 nCounter++;
}

//Add columns to the results data table named as per the Entities fields.
//Check if there any of the fields have show in picker set so we know to display only those fields.
Boolean blnShowInPickers = false;
foreach (Field f in myEntity.GetFinderView().Fields)
 {
        if (f.TypeDescriptor.GetProperties().ContainsKey("ShowInPicker"))
              {
               if (((Boolean)f.TypeDescriptor.GetProperties()["ShowInPicker"]))
               {
                     blnShowInPickers = true;
    }
   }
 }

DataColumn currentColumn = null;
foreach (Field f in myEntity.GetFinderView().Fields)
      {
 //Add the default display name to the caption if there is one so we can pull it out when we create the list.
       if (f.DefaultDisplayName == "")
            {
             currentColumn = Results.Columns.Add(f.Name);
     }
            else
            {
             currentColumn = Results.Columns.Add(f.Name);
                currentColumn.Caption = f.DefaultDisplayName;
     }

            if (blnShowInPickers)
            {
  //Only show fields that have show in picker set (if any do).
             if (f.Name != sTitle)
                  {
                   if (f.TypeDescriptor.GetProperties().ContainsKey("ShowInPicker"))
                        {
                         if (((Boolean)f.TypeDescriptor.GetProperties()["ShowInPicker"]))
                              {
                               currentColumn.ExtendedProperties.Add("ShowInPicker", "TRUE");
         }
         else
                              {
                               currentColumn.ExtendedProperties.Add("ShowInPicker", "FALSE");
         }
   }
    }
                  else
                  {
                   currentColumn.ExtendedProperties.Add("ShowInPicker", "TRUE");
    }
     }
            else
            {
  //Else if the field is an identifier or it's the title field then show it.
             if (f.TypeDescriptor.ContainsIdentifier || f.Name == sTitle)
                  {
                   currentColumn.ExtendedProperties.Add("ShowInPicker", "TRUE");
    }
                  else
                  {
                   currentColumn.ExtendedProperties.Add("ShowInPicker", "FALSE");
      }
      }
 }

//Loop through the found Entity instances and add them to the results.
while (prodEntityInstanceEnumerator.MoveNext())
{
 try
 {
  IEntityInstance IE = prodEntityInstanceEnumerator.Current;
  DataRow newResultRow = Results.NewRow();
  System.Collections.IList MyList = (System.Collections.IList)IE.GetIdentifierValues();

  //Create an array to hold the identifiers.
  object[] oIdentitiers = new object[sIDNames.Length];

  for (int iCounter = 0; iCounter < MyList.Count; iCounter++)
  {
   oIdentitiers[iCounter] = MyList[iCounter].ToString();
  }

  foreach (Field f in myEntity.GetFinderView().Fields)
  {
   if (IE[f] != null)
   {
    newResultRow[f.Name] = IE[f];
   }
  }

  Results.Rows.Add(newResultRow);
 }

 catch (Exception rowex)
 {
 }
}

//Grab the Display Fields and add columns for them in the Grid View.
gvResults.DataSource = Resultset;
string[] keys = Request["DisplayFields"].ToUpper().Split(',');
gvResults.DataKeyNames = keys;
gvResults.Columns.Clear();

foreach (DataColumn currentCol in ((DataTable)gvResults.DataSource).Columns)
{
        string[] displayFields = Request["DisplayFields"].ToUpper().Split(',');
        if (Array.BinarySearch(displayFields,currentCol.ColumnName.ToString().ToUpper())>=0)
  
 {
                BoundField newfield=new BoundField();
                newfield.HeaderText=currentCol.ColumnName.ToString();
                newfield.DataField=currentCol.ColumnName.ToString();
         gvResults.Columns.Add(newfield);
 }
}

//Bind the results to the grid.
gvResults.DataBind();

Feel free to wander over to CodePlex and grab a copy if this is a requirement for you or your clients and feel free to offer any suggestions you think of!

I'm off for a month with the Kids and the Family, so I wish you all a great Xmas, Holiday, or work time!

 

 

 

Best Practice : Using disposable objects in SharePoint

Posted by adrh
No Comments »

I found this article on MSDN via Andrew's post posing the question "So is it best practice to only use C# for SharePoint development?". A good question and one that will have plenty of comment from all I imagine. For what it's worth (although not the point of this post), I'm a fan of C# because I like using (SPSite currentSite=new SPSite(http://Server)) …

The interesting thing I took from the MSDN article was that objects that are accessed via SPSite objects, like RootWeb and ParentWeb need to be explicitly disposed of when you're finished with them. I had not appreciated this. I figured that if you 'used' using on the SPSite object then that would dispose all the members etc of that object. Not so say our MS friends! Smile

This means:

String str;
using(SPSite oSPSite = new SPSite("http://server"))
{
   str = oSPSite.RootWeb.Title;
   str = oSPSite.RootWeb.Url;

   … additional processing on RootWeb …

oSPSite.RootWeb.Dispose();
}

And, in the interest of fairness: 

Dim str as string
Dim oSPSite as SPSite

oSPSite=new SPSite(http://server)

str = oSPSite.RootWeb.Title
str = oSPSite.RootWeb.Url

… additional processing on RootWeb …

oSPSite.RootWeb.Dispose()
oSPSite.Dispose()

Not really that difficult, but it will make a difference to your memory usage, have positive performance benefits and keep the "Potentially excessive number of SPRequest objects (11) currently unreleased on thread" error messages out of the already huge logs!

Regardless of you language of choice, this article is definitely worth a read if you are coding for SharePoint!

 

Best Practice : Using disposable objects in SharePoint

Posted by adrh
No Comments »

I found this article on MSDN via Andrew's post posing the question "So is it best practice to only use C# for SharePoint development?". A good question and one that will have plenty of comment from all I imagine. For what it's worth (although not the point of this post), I'm a fan of C# because I like using (SPSite currentSite=new SPSite(http://Server)) …

The interesting thing I took from the MSDN article was that objects that are accessed via SPSite objects, like RootWeb and ParentWeb need to be explicitly disposed of when you're finished with them. I had not appreciated this. I figured that if you 'used' using on the SPSite object then that would dispose all the members etc of that object. Not so say our MS friends! Smile

This means:

String str;
using(SPSite oSPSite = new SPSite("http://server"))
{
   str = oSPSite.RootWeb.Title;
   str = oSPSite.RootWeb.Url;

   … additional processing on RootWeb …

oSPSite.RootWeb.Dispose();
}

And, in the interest of fairness: 

Dim str as string
Dim oSPSite as SPSite

oSPSite=new SPSite(http://server)

str = oSPSite.RootWeb.Title
str = oSPSite.RootWeb.Url

… additional processing on RootWeb …

oSPSite.RootWeb.Dispose()
oSPSite.Dispose()

Not really that difficult, but it will make a difference to your memory usage, have positive performance benefits and keep the "Potentially excessive number of SPRequest objects (11) currently unreleased on thread" error messages out of the already huge logs!

Regardless of you language of choice, this article is definitely worth a read if you are coding for SharePoint!