Monday 29 November 2010

SPMetal Extender CodePlex project

I have release a project on codeplex, SPMetal Extender to be able to use additional field types.  Fields in lists can be extended using partial classes.  The project provides a Visual Studio plug-in vsix that generates Linq to sharePoint code for unsupport list fields such as publishing fields.  Additionally the vsix deploys a new template showing how to add 4 additionaly properties to SPMetal.  The Item template is guidance and needs to be adjusted by the developer after it is created.
SPMetal Extender VSIX extension installed
Add a new SPMetal Extended item to a SharePoint project
Generate code for addionnal list fields using Server Explorer using the VS IDE

SPMetal Extender is also published on Microsoft Visual Studio tools gallery 

Saturday 27 November 2010

Error adding webpart containing validation control

Problem: When adding a custom built webpart with asp validator controls to a page, the user will encounter the following error when attempting to save the changes "Error: This page contains content or formatting that is not valid.".
Initial Hypothesis:
This error only happens when the webpart control has validators and prevents the user being able to add the webpart to the page.

Resolution: Disable the validator controls when editing the page.
Add the following public method in the server control code ...
public void EnableValidators(bool enableVal)
{
this.validatorName.Enabled = enableVal;
}
In the Webpart's CreateChildControls() procedure only add the user control/validation when not in edit mode
if (SPContext.Current.FormContext.FormMode == SPControlMode.Edit || SPContext.Current.FormContext.FormMode == SPControlMode.New)
{
//validator.enabled = false
((UserControl1)_ctl).EnableValidators(false);
}
else
{
//validator.enabled = false
((UserControl1)_ctl).EnableValidators(true);
}
}
Add the EnableValidators method to the user control code behind:
 
The validators will then be disabled when adding the web part​ to the page / editing the page, but still work in presentation mode.

Thanks to Paul W

Change to session cookies for Claims Based Authentication

When you log into SharePoint using Claims Based Authentication, a cookie is written/persisted to ​disk (FedAuth) to persist your session, which prevents you having to be authenticated each time you open a new browser or re-boot.  So using a FedAuth cookie allows the browser to close and re-open windows as long as the FedAuth cookie has not expired.  For ADFS, FedAuth cookie expiry is by default set to expire 10 minute earlier than the SAML token.

You can change the cookie to be session based by running this PowerShell script:

$sts = Get-SPSecurityTokenServiceConfig
$sts.UseSessionCookies = $true
$sts.Update()
iisreset

You can revert back to a disk based cookie (default) by running this:

$sts.UseSessionCookies = $false
$sts.Update()
iisreset

Show cookies on a local machine for Internet Explorer

IE > Internet Options> General > Browser history "Settings" > Temporary Internet Files "View files".

Update 2016/03/10
Tip:  I wanted to examine a cookie to check the user being authenticate, and I opened the cookie using a base64 online decoder https://www.base64decode.org/




Update: 2016/11/23
IE Developer tool bar and Fiddler are great and easy to use and pretty feature rich but lately I have been using Chromes Developer toolbar press "Ctrl" + "Shift" + "i".



Linq to SharePoint - CRUD operations

Problem: Code to perform CRUD operations against a SharePoint list using Linq to SharePoint.
Resolution:
1) Read:
DataContext dc = new DataContext();
EntityList Customer = dc.GetList("Customers");
var CustomerItems = from Customers in Customer
select Customers;

Alternative approach


2) Insert:
DataContext dc = new DataContext();
CustomersItem Customer = new CustomersItem();
Customer.Title = "Title";
dc.Customers.InsertOnSubmit(Customer);
dc.SubmitChanges();

3) Update:
DataContext dc = new DataContext();
EntityList Customer = dc.GetList("Customers");
var CustomerItems = (from Customers in Customer
where Customers.Id == Convert.ToInt32(txtEditCustomerId.Text)
select Customers).Single();
CustomerItems.Title = CustomerItems.Title + txtCustomerTitle.Text;
dc.SubmitChanges();

4) Delete:
DataContext dc = new DataContext();
EntityList Customer = dc.GetList("Customers");
var CustomerItems = (from Customers in Customer
where Customers.Id == Convert.ToInt32(txtEditCustomerId.Text)
select Customers).Single();
dc.Customers.DeleteOnSubmit(CustomerItems);
dc.SubmitChanges();

Alternative approach 


Tip: If you are using read-only operation in your LINQ to SharePoint queries set ObjectTrackingEnabled to false to improve performance.
DataContext dc = new DataContext();
dc.ObjectTrackingEnabled = false;

Tip: Use the context on the generated proxy for performing LINQ to SharePoint queries.
More Info:
LINQ to SharePoint: CRUD operation on SharePoint 2010 list using SPLinq
LinqPad
LinqPad for SharePoint 2010

Wednesday 24 November 2010

Extending SPMetal

Problem: Using SPMetal retrieve a list and display the basic columns and the following 3 columns types:
  • Attachments;
  • Html Publishing field; and
  • Image Publishing field.
Resolution:
Extended partial class to retrieve attachments, a html publishing field and a publishing image.  The code link only does the read operation.
Extended partial class (advanced) to retrieve an attachment, a html publishing field, a publishing image and the hidden CreatedBy field.  You can use the parameters.xml when generating the SPMetal proxy to display additional hidden fields such as the CreatedBy field however, if the proxy has already been generated, it is easy to simple extend the partial class to get hidden fields.  This example also adds the code to insert and update the publishing html and the publishing image field columns.

More Info:
SPMetal only generates the proxy classes code against lists that site columns are available in SP2010 foundation.  So you also don't get Manage Metadata or any custom site columns you create.  You also don't get most of the built in columns with the exception of ID & Version using SPMetal.  However, by changing the parameters.xml file you can include them i.e. Modified, CreatedBy.  You can also use the extended partial class method to display the hidden built in site columns - I would use the parametes file and not the extended partial class coding for hidden fields(Field = Site Column).

Friday 19 November 2010

Deploying a Sandbox solution

Problem: I created several wsp packages, unfortunately 1 of the solution projects was marked as a Sandbox solution when the project was created in Visual Studio 2010.  The lookup lists are not deploying correctly in the sandbox solution because I deployed the solution at farm level.

Initial Hypothesis: I notice my lists had strange behaviour.  I check my deployment and 1 of the solutions had not been deployed.  When I deployed the wsp using Powershell (PS> Install-SPSolution ...) it did not error so I had presumed it had installed correctly.  Using PowerShell (PS) I could see the solution holding the list wasn't installed. PS> Get-Solution
Resolution: Retract the solution and remove it from the farm.  Deploy the solution to the Site Collection's solutions and enable the feature/s.  Powershell Commands:
PS> Add-SPUserSolution -LiteralPath D:\packages\.Lists.wsp -Site http://demo.dev

PS> Install-SPUserSolution –Identity Lists.wsp -Site http://demo.dev
PS> Enable-SPFeature –Identity Feature_GeneralLists –url http://demo.dev/

Tip: Update 10 Dec 2010 - If you remove a solution (this also applies to sandbox solutions) (including deactivating the associated features), if the feature deploys content types or site columns, you will need to do an IISreset if you want the content types and site columns removed from the Site Collection (alernatively restart the Web Application so the whole farm is not reset).

Post on deploying fasm wsp's.

Thursday 18 November 2010

Custom Claims Membership Provider

Problem: We have written a custom claims membership provider, it works in development however if fails in the UAT environment.  The Membership provider goes to an LDAP directory (IBM TAM).

Initial Hypothesis: After checking the configuration was correct, I looked at the logs that were informing me that the provider was not returning results.  We can't use wireshark on the UAT environment to verify the call is being made to the LDAP directory.  And the error message is a generic failure message.

Resolution: Use Telnet to check that the WFE/WebService/STS/SharePoint token service can speak to the LDAP directory.
cmd>Telnet 192.168.1.101 389

The Claims web service cannot contact the LDAP directory, most likely cause is the firewall or the windows firewall.  Add a rule to the firewall to allow traffic on port 389.