Thursday, March 25, 2010

Enable/Disable Asp.net validatiors using JavaScript

ASP.NET provides predefined validators for controls in ASP.NET pages:
  • RequiredFieldValidator
  • RegularExpressionValidator
  • ...

These validation controls offer the server-side property "Enabled" to be able to Enable/Disable them from server-side code. But what if we want to Enable/Disable them in client-side code (Javascript): Then there is a predefined JS method: ValidatorEnable(ValidatorId, Boolean); which allows us to do so.

To enable a control we would do like:
ValidatorEnable(document.getElementById('<%= validatorUserName.ClientID %>'), true);

And to disabe it:
ValidatorEnable(document.getElementById('<%= validatorUserName.ClientID %>'), false);

Couldn't it be easier?

Wednesday, March 17, 2010

Code to change SPListItem permissions with a non-full-control user

Recently I faced the need to change SharePoint's List Items permissions programmatically. The tricky part of it was the fact that the user performing the action had only contributor rights on the site. The workaround to perform such action is to run the code as a user with elevated privileges. So here is my first approach:
Guid SiteId = SPContext.Current.Site.ID;
Guid
WebId = SPContext
.Current.Web.ID;

SPSecurity.RunWithElevatedPrivileges(delegate()
{
using
(SPSite ElevatedSite = new SPSite
(SiteId))
{
using
(SPWeb
ElevatedWeb = ElevatedSite.OpenWeb(WebId))
{
//Code to change permissions

}

}

});

Using this code, at the moment you execute the sentences to change the permissions, you get an error like: "The security validation for this page is invalid". The way to solve this error is to set the AllowUnsafeUpdates property to true for the SPWeb object and validate the form digest control used in the current request. Hence the code snippet will look like this:

Guid SiteId = SPContext.Current.Site.ID;
Guid
WebId = SPContext.Current.Web.ID;

SPSecurity.RunWithElevatedPrivileges(delegate()
{
using
(SPSite ElevatedSite = new SPSite(SiteId))
{
using
(SPWeb ElevatedWeb = ElevatedSite.OpenWeb(WebId))
{
ElevatedWeb.AllowUnsafeUpdates = true;
ElevatedWeb.Update();
SPUtility
.ValidateFormDigest();

//Code to change permissions

ElevatedWeb.AllowUnsafeUpdates = false;
}
}
});

And finally the code to change the permissions would look some thing like this:

listItem.BreakRoleInheritance(false);
SPRoleAssignment
role = new SPRoleAssignment(SPContext.Current.Web.EnsureUser("SOMEUSERorGROUP"));
role.RoleDefinitionBindings.Add(ElevatedWeb.RoleDefinitions.GetByType(SPRoleType.Contributor)); //Or any other SPRoleType
listItem.RoleAssignments.Add(role);
listItem.Update();

This worked for me. Hope it helps!

Monday, March 15, 2010

SharePoint Full Error Messages

While testing a SharePoint app, it is useful to see the "real" error messages instead of the nice "An unknown error occured. Please contact your system administrator".

As I'm always forgetting how to set the web.config to show the "real" errors, here are the couple of steps which need to be done:
  1. Switch custom errors off
    <system.web>

    <customErrors mode="Off" />

    </system.web>
  2. Enable CallStack
    <SharePoint>

    <SafeMode CallStack="true" />

    </SharePoint>

Thursday, March 11, 2010

Solution to: Cannot convert type 'Microsoft.SharePoint.WebControls.ScriptLink' to 'System.Web.UI.IAttributeAccessor'

An error occurred during the processing of . http://server/_catalogs/masterpage/YOURMASTER.master(18): error CS0030: Cannot convert type 'Microsoft.SharePoint.WebControls.ScriptLink' to 'System.Web.UI.IAttributeAccessor'

When deploying and setting a customized master page to a SharePoint site collection through a feature, after the deployment of the solution and feature activation success, you can end up having the above listed error.

I guess this error might be caused for several reasons. But if you use SharePoint Designer to customize the master page and then Export option to export it into a file, SharePoint Designer adds a lot of non-sense code to the file.

In order to solve the error, you just have to copy & paste the code into a new text file and save this file as your new master page to deploy.

Hope it helps.

Friday, January 22, 2010

Upload multiple files attached to a SharePoint list item.

Recently I faced the need of programming a control for uploading multiple files attached to a SharePoint list item. Following this video example I could easily create an ASP.NET control to upload multiple files to a web server. Then I just addapted the code to upload the files attached to the SharePoint list item and the final result is as follows:
SPWeb mySite = SPContext.Current.Web;
SPList myList = mySite.Lists["myList"];
SPListItem myListItem = myList.Items.Add();

myListItem["Title"] = "myTitle";
...

if (HttpContext.Current.Request.Files.Count > 0)
{
HttpFileCollection uploads = HttpContext.Current.Request.Files;
SPAttachmentCollection attachments;

for (int i = 0; i < uploads.Count; i++)
{
Stream fs = uploads[i].InputStream;
byte[] fileContents = new byte[fs.Length];
fs.Read(fileContents, 0, (int)fs.Length);
fs.Close();
attachments = myListItem.Attachments;
string fileName = Path.GetFileName(uploads[i].FileName);
attachments.Add(fileName, fileContents);
}
myListItem.Update();
}

I hope this helps!

Thursday, January 21, 2010

Trying to use an SPWeb object that has been closed or disposed and is no longer valid.

Developing in SharePoint you can come across this error (Trying to use an SPWeb object that has been closed or disposed and is no longer valid) for so many reasons.
The one I faced today was because I was using a SPWeb object initialized to the current context, so something like:
SPWeb site = SPContext.Current.Web

In order to skip the Dispose statement I wrapped the my code into a using block, so I had something like:

using (SPWeb site = SPContext.Current.Web)
{
...
}

The problem is that when we execute SPWeb site = SPContext.Current.Web, an object is not actually created and the site variable only gets a reference to the existing object, which in this particular case is the current context. Then at the end of the using block, the code will actually dispose the current context, which is a non-desirable efect.

So in order to avoid this error, just don't try to dispose the current context!

You can read more info about all that in: Best Practices: Using Disposable Windows SharePoint Services Objects (http://msdn.microsoft.com/en-us/library/aa973248.aspx)

SharePoint Web Part Maintenance Page

For some reason I never remember this: If you have a SharePoint web part which causes a problem on a page and it prevents it from loading, you can always browse to the web part maintenance page, which allows you to close, reset and delete web parts from a particular page.
The way to browse into the web part maintenance page is adding ?contents=1 to the end of the page's url. For example: http://mysharepointsite/default.aspx?contents=1.