SharePoint Web Part Life Cycle Woes
0I’ve been meaning to write this post for a long time! A while back I was working on a web part that allows you to browse folders within Picture libraries as Photo Albums. As you can probably imagine this has been quite painful as when it comes to working with SharePoint folders the object model API isn’t brilliant, that’s a topic for another post though.
While building the web part I had some issues with dynamically created controls after post back. After some extended troubleshooting it turns out this was because I hadn’t recreated the controls in the CreateChildControls() override. When trying to find the issue I decided to refresh my memory on the ASP.NET Web Part Life Cycle (this is something that every SharePoint Developer should understand). Phil Harding has done a great blog post here summarising all the events and the order in which they occur, this is a great one to add to your bookmarks.
To explain the problem further have a look at the following piece of code -
namespace HelloWorldWebPart.HelloWorldWebPart
{
[ToolboxItemAttribute(false)]
public class HelloWorldWebPart : WebPart
{
protected override void CreateChildControls()
{
CreateHelloButton();
if (ViewState["CreateHiButton"] != null)
{
if ((bool)ViewState["CreateHiButton"] == true)
{
Button btnHi = new Button();
btnHi.ID = "btnHi";
btnHi.Text = "Hi";
btnHi.Click += new EventHandler(btnHi_Click);
this.Controls.Add(btnHi);
}
}
}
private void CreateHelloButton()
{
Button btnHello = new Button();
btnHello.ID = "Hello";
btnHello.Text = "Hello";
btnHello.Click += new EventHandler(btnHello_Click);
this.Controls.Add(btnHello);
}
private void btnHello_Click(object sender, EventArgs e)
{
this.Controls.Add(new LiteralControl("Hello World!"));
ViewState["CreateHiButton"] = true;
Button btnHi = new Button();
btnHi.ID = "btnHi";
btnHi.Text = "Hi";
btnHi.Click += new EventHandler(btnHi_Click);
this.Controls.Add(btnHi);
}
void btnHi_Click(object sender, EventArgs e)
{
this.Controls.Add(new LiteralControl("Hi!"));
}
}
}
This might not be the best example of the calibre of web part that you might produce for a client but it helps to explain the concept.
We create our controls in the CreateChildControls method as normal. In the example above a button is dynamically created when we click the ‘Hello World’ button. In order for the click handler of the second button to fire we need to recreate that button and tie up the click event handler again after postback in CreateChildControls. Creating the second button in the click handler of the first one is not enough. To do this we set a ViewState value which we query after postback and then create our button again. If we don’t recreate the button again after postback then the click handler will not fire, the below example shows the incorrect code, in this example the click handler for the new button will not fire.
namespace HelloWorldWebPart.HelloWorldWebPart
{
[ToolboxItemAttribute(false)]
public class HelloWorldWebPart : WebPart
{
protected override void CreateChildControls()
{
CreateHelloButton();
}
private void CreateHelloButton()
{
Button btnHello = new Button();
btnHello.ID = "Hello";
btnHello.Text = "Hello";
btnHello.Click += new EventHandler(btnHello_Click);
this.Controls.Add(btnHello);
}
private void btnHello_Click(object sender, EventArgs e)
{
this.Controls.Add(new LiteralControl("Hello World!"));
Button btnHi = new Button();
btnHi.ID = "btnHi";
btnHi.Text = "Hi";
btnHi.Click += new EventHandler(btnHi_Click);
this.Controls.Add(btnHi);
}
void btnHi_Click(object sender, EventArgs e)
{
this.Controls.Add(new LiteralControl("Hi!"));
}
}
}
This is something to watch out for when dynamic creating controls in SharePoint/ASP.NET web parts.
Star Trail Photography – My first go
0After stepping into the world of shooting Panoramas and HDRs with my DSLR, I was looking for my next challenge. I came across Star Trail photography was inspired by a few shots that one of my SharePoint buddies Mark had taken.
He provided me with some beginner steps to follow – thanks Mark! I also found a great blog post discussing it further and giving some more tips and a different technique.
In this post I’ll go through how I got on and the things I have learnt.
Before you continue reading I encourage you to look at the following links -
1. http://www.sharepointstudio.com/Blog/Lists/Posts/Post.aspx?ID=45
2. http://www.jamesvernacotola.com/Resources/How-To-Photograph-Star-Trails/12233655_V7cX4D
To shoot my Star Trail images I used interval mode on my camera (Pentax K-R). This is because I use an infrared remote as a shutter release. Sadly this type of remote does not work with burst mode so I could not lock the button down and leave the camera taking shots. If you have a cable release it should work fine and you can use burst mode as recommended in link 2 above.
If you are in the same boat as me then set your camera up to shoot in intervals. Before you start you will need to turn off ‘Long Exposure Noise Reduction’ (will be an option in one of the menus), this is because after taking the shot the camera performs Dark-frame subtraction. Leaving this on will make your processing time longer so the intervals will not work correctly.
I shot for 20 seconds at f/5.6 with a 25 second interval and ISO 200. I’m not 100 percent sure if the long interval is necessary as in the previous step we turned off Long Exposure NR. However this will still help as the camera will take some time to process the image, for example if you set an interval of one second and tell the camera to take 200 shots, the camera will be finished in only 20. This is a problem I experienced first hand and it was quite annoying so to be safe turn off the NR and set a reasonable interval time.
After you have set your camera up decide how long you want to shoot for, my first photo which in my opinion came out best was taken over a 2-3 hour period. The second photo was taken for over only 1-2 hours, in this one there aren’t as many star trails and they don’t curve as much. Make sure you bear in mind the longer you shoot for, the more chance you are going to get aeroplanes coming into the frame. As we live quite near Brisbane airport I got quite a lot of aeroplane trails!
The final few things to check are -
1. The Weather – make sure there aren’t too many clouds in the sky and that it won’t rain, unless you want your camera getting wet!
2. Battery – make sure it’s fully charged as shooting 300+ shots at 20 seconds each will eat your battery life.
3. SD Card – ensure you have enough room as you will likely get 3gb plus of photos.
Once you are ready to go just set your camera shooting and head back inside.
Post Processing
To post process my shots I used Lightroom initially to make white balance adjustments, adjust sharpening and perform other corrections. I then used the Startrail software fromthat was recommended in link 2 above, thanks Achim Schaller for this awesome piece of software! This little application is great, you load your shots in and click Build > Startrails, then watch in awe as they appear right in front of you.
A good tip to remove aeroplane trails is to click on the first image in the Startrails app and hold the down arrow key to cycle through them, when you see an aeroplane enter make note of the image name. Locate this image in Lightroom and use the Spot Removal tool to remove it. Once you are done you can export again and re-render the trails. If you have lots of trails to do then the Spot Removal tool can be time consuming. You could edit the image in Photoshop and use the healing brush tool, the problem with this is that the file would convert to .tiff format and you lose the ability to make white balance adjustments in the future. I wanted to keep all my images in raw so I could play with the white balance etc later so I chose the painful route and used spot removal.
When doing your first few renders of your star trails export them at a smaller resolution than you normally would e.g. 1000 pixels on the long edge. This will help to speed up the rendering, for my final render I exported at full 12MP, but beware this takes about 10 minutes to render and will produce a large tiff file – mine was 29mb! I’ve found that using images at full resolution e.g. 4000×4000 pixels don’t play nicely with the time-lapse feature of the Startrails application, for example trying to create a time-lapse video just generates an error message. To produce my time-lapse video I used images that were 1600 pixels on the long edge. Also another point to note, the Startrails application doesn’t like rendering videos over 1000 pixels wide so it can’t create HD video. I opted to create mine at the default 640×480 (480P), this gave me a reasonable quality whilst keeping the file size a little lower. Once I had rendered my final star trail images I imported them back into Lightroom to increase the contrast and adjust exposure, I found this was necessary because the Startrails application averages the images during the process and in turn makes them brighter.
You can see how I got on in my Picasa album via the link below, let me know what you think!
![]() |
| 2012-03 Star Trails |
I hope you have found this blog post helpful, if so please leave a comment below.
Synchronous Event Receivers
0SharePoint is a big (massive!) product, there are features and enhancements in SP2010 which I haven’t even used yet – mostly because I haven’t needed to.
One of these is the ability to run after events synchronously (ItemAdded, ListAdded and WebProvisioned). Previously all after events were executed asynchronously and on a background thread in a different process. What we can do now is run these after events on demand, they are executed according to the sequence number.
I used this feature the other day when creating an Event Receiver for a picture library and it’s pretty darn useful. Here’s the scenario I had -
When a picture is added to the library a field needs to automatically update with some EXIF metadata which is extracted from the picture.
The metadata must be visible to the user in the edit form for them to see before clicking OK.
In the above scenario I couldn’t use an asynchronous event receiver because the updated value in the field would not be visible to the user in the edit form. I needed to make sure that the event receiver would run as soon as the item was added and not in a background thread, this way the new value will be visible to the user in the edit form.
In order to make your event receiver Synchronous you can set the Synchronous property of the SPEventReceiverDefinition class (if you are binding programmatically). Or by creating a node in yourXML, see below for examples of each -
Programmatically
MyEventReceiver eventReceiver = new MyEventReceiver(); SPEventReceiverDefinitionCollection eventReceiverCol = myList.EventReceivers; SPEventReceiverDefinition eventReceiverDef = eventReceiverCol.Add(); eventReceiver.Name = “My Event Receiver”; eventReceiver.Synchronization = SPEventReceiverSyncronization.Synchronous; eventReceiver.Type = SPEventReceiverType.ItemAdded; eventReceiver.SequenceNumber = 100; eventReceiver.Assembly = Assembly.GetExecutingAssembly().FullName; eventReceiver.Class = eventReceiver.GetType().ToString(); eventReceiver.Update();
Using XML
<Receivers >
<Receiver>
<Name>MyEventReceiver</Name>
<Type>ItemAdded</Type>
<Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
<Class>MySolution.EventReceivers.MyEventReceiver</Class>
<SequenceNumber>100</SequenceNumber>
<Synchronization>Synchronous</Synchronization>
</Receiver>
</Receivers>
Hope this helps ![]()
Strange goings on with the format of dates in SharePoint Calculated Columns
1
I came across a weird issue this morning whilst debugging a Web Part. I had a list that stored a date in one column and a Calculated Column that returned a date after applying a formula.
The regional settings of the site were set to English (Australia) – see screenshot below.
My calculated column was set up like so (formula and columns blurred out) -
Looking at the list everything appeared fine and the dates were displayed in the correct format (dd/MM/yyyy). Expiry is the calculated column.
However when accessing the list items programmatically and trying to convert the Expiry date into a DateTime it was throwing an exception. The dates being returned programmatically were in the below format -
12/15/2011 10:00:00
This is clearly an invalid date when compared to the culture of my machine (UK).
What I ended up doing was converting the date using US culture (en-US) and then changing the format before converting back into a DateTime.
Below is the code snippet that I used to do this – has anyone seen this issue before? or does SharePoint always store the dates for calculated columns in the Content DB as US format?
IFormatProvider provider = new CultureInfo("en-US");
DateTime date = Convert.ToDateTime(myItem["DateColumn"].ToString(), provider);
string convertedDate = date.ToString("dd/MM/yyyy");
DateTime date1 = Convert.ToDateTime(convertedDate);
I would love to hear back from anyone who has seen this before or can shed any light on it.
Deploying Nintex Workflow Custom Action with Multiple Web Front End’s
0
After quite a break from doing any Nintex development I was required to write a custom Workflow Action for a client. I broke out the Nintex SDK to remind myself how to do this and wrote my action.
I debugged and tested the action on my dev VM and got it ready to deploy to the UAT environment. One key thing that is different about the UAT environment to my VM is the fact that it is a multi server farm with two WFE’s.
I wasn’t 100% sure that the code used in the Nintex SDK to add the action/activity as an AuthorizedType in the web.config would work with multiple WFE’s as it uses the SPWebConfigModification class.
A quick google turned up this post on MSDN – http://blogs.msdn.com/b/malag/archive/2009/05/22/spwebconfigmodification-does-not-work-on-farms-with-multiple-wfes.aspx.
Unfortunately it seems the code Nintex provide tries to get the Farm instance before applying the WebConfigModification – there is however a way around this – read on for more…
In the FeatureActivated event the following code is used to add the WebConfigModification -
AuthorisedTypes.InstallAuthorizedWorkflowTypes(parent, action.ActivityAssembly, activityNamespace, activityTypeName);
In order to get to the bottom of what this method did I decompiled the Nintex Workflow dll and looked for this method. The method uses the below code -
public static void InstallAuthorizedWorkflowTypes(SPWebApplication webApp, string assemblyName, string namespaceName, string typeName)
{
AuthorisedTypes.assemblyName = assemblyName;
AuthorisedTypes.namespaceName = namespaceName;
AuthorisedTypes.typeName = typeName;
AuthorisedTypes.webApp = webApp;
SPSecurity.CodeToRunElevated secureCode = new SPSecurity.CodeToRunElevated(AuthorisedTypes.PerformWebConfigModificationForAuthorizedType);
SPSecurity.RunWithElevatedPrivileges(secureCode);
}
private static void PerformWebConfigModificationForAuthorizedType()
{
try
{
string value = string.Format("<authorizedType Assembly=\"{0}\" Namespace=\"{1}\" TypeName=\"{2}\" Authorized=\"True\" />", AuthorisedTypes.assemblyName, AuthorisedTypes.namespaceName, AuthorisedTypes.typeName);
SPWebConfigModification sPWebConfigModification = new SPWebConfigModification(string.Format("authorizedType[@Assembly='{0}'][@Namespace='{1}'][@TypeName='{2}']", AuthorisedTypes.assemblyName, AuthorisedTypes.namespaceName, AuthorisedTypes.typeName), "configuration/System.Workflow.ComponentModel.WorkflowCompiler/authorizedTypes");
sPWebConfigModification.Owner = "Nintex Workflow 2010";
sPWebConfigModification.Sequence = 0u;
sPWebConfigModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
sPWebConfigModification.Value = value;
if (!AuthorisedTypes.webApp.WebConfigModifications.Contains(sPWebConfigModification))
{
AuthorisedTypes.webApp.WebConfigModifications.Add(sPWebConfigModification);
AuthorisedTypes.webApp.Update();
AuthorisedTypes.webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
}
}
catch (Exception innerException)
{
new NWException(NWResource.GetString("NWException_FailedToInstallAuthorizedTypes"), innerException);
}
}
As you can see it uses the Farm instance to apply the WebConfigModification – this won’t work with multiple WFE’s. What I did was copy the method directly into my FeatureReceiver and modified it to use SPWebService.SPContentService.
Here you can see the final code -
/// <summary>
/// Taken from the Nintex Workflow dll and modified - in multiple WFE environments you cannot get the farm instance - need to use SPWebService.ContentService
/// </summary>
/// <param name="webApp"></param>
/// <param name="assemblyName"></param>
/// <param name="namespaceName"></param>
/// <param name="typeName"></param>
public void PerformWebConfigModificationForAuthorizedTypeCustom(SPWebApplication webApp, string assemblyName, string namespaceName, string typeName)
{
try
{
string value = string.Format("<authorizedType Assembly=\"{0}\" Namespace=\"{1}\" TypeName=\"{2}\" Authorized=\"True\" />", assemblyName, namespaceName, typeName);
SPWebConfigModification sPWebConfigModification = new SPWebConfigModification(string.Format("authorizedType[@Assembly='{0}'][@Namespace='{1}'][@TypeName='{2}']", assemblyName, namespaceName, typeName), "configuration/System.Workflow.ComponentModel.WorkflowCompiler/authorizedTypes");
sPWebConfigModification.Owner = "Nintex Workflow 2010";
sPWebConfigModification.Sequence = 0u;
sPWebConfigModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
sPWebConfigModification.Value = value;
if (!SPWebService.ContentService.WebConfigModifications.Contains(sPWebConfigModification))
{
SPWebService.ContentService.WebConfigModifications.Add(sPWebConfigModification);
SPWebService.ContentService.Update();
SPWebService.ContentService.ApplyWebConfigModifications();
}
}
catch (Exception innerException)
{
// Do something with this exception
}
}
Take note the Nintex SDK also uses the Farm instance in the FeatureDeactivating method so you will need to change this to call the ContentService also.
Hope this helps someone ![]()
*Update – I found this blog post (http://solutionizing.net/2009/05/26/spwebconfigmodification-works-fine/) which suggests that the ContentService class simply provides a constructor to handle if the Farm instance is null. Either way it is the recommended way to access the WebConfigModifications.
GrantAccessToProcessIdentity – A very handy SharePoint PowerShell command!
0
I thought I’d do a write up on this one as its something that always catches me out every time I’m configuring a SharePoint farm.
If you are setting up services e.g. Excel Services or Office Web Apps then it’s likely you will need to grant the service account running the service application permissions on your Content DBs.
Unfortunately it seems that SharePoint doesn’t do this for you when provisioning the Service App and you end up getting an error in the event logs when you try and use the service. The error is as follows -
Source: Microsoft-SharePoint Products-SharePoint Foundation Event ID: 3760 Task Category: Database Level: Critical User: TECHTOOLBOX\svc-spserviceapp-tst Computer: cyclops-test.corp.technologytoolbox.com Description: SQL Database 'WSS_Content' on SQL Server instance 'beast-test' not found. Additional error information from SQL Server is included below. Cannot open database "WSS_Content" requested by the login. The login failed. Login failed for user 'TECHTOOLBOX\svc-spserviceapp-tst'.
In order to fix this you need to run the GrantAccessToProcessIdentity command for the web application in question. To do this use the PowerShell below -
$webApp = Get-SPWebApplication http://cyclops
$webApp.GrantAccessToProcessIdentity("TECHTOOLBOX\svc-spserviceapp")
The access should now be granted and you should be able to use the service application.
Hope this helps! ![]()
RIP Marco Simoncelli ‘Super Sic’
0
I don’t normally write any non-work/SharePoint related posts on here but this is an exception. As most of you who know me will know I am a massive fan of motorcycle racing. I am still in shock from the news yesterday that my favourite MotoGP rider Marco Simoncelli has been killed while racing at Sepang. The crash was very nasty with Marco’s helmet coming off during the incident. Unfortunately this is a one of a kind freak accident and no one is to blame. There is no doubt that MotoGP is a dangerous sport and the riders fully understand and accept this. I can only hope that for Marco it happened very quickly and he wouldn’t have known much about it.
Marco stepped up to MotoGP in 2010 from the 250cc class and looked to be the one to watch. This year he has shaken up the racing and been a real gem to watch – his battles with Lorenzo were especially good. He caused quite a bit of controversy with the other riders over his riding style but seemed to be on really good form recently.
I was at the Phillip Island GP last weekend and watched him get his best result of the season – 2nd!
If anyone is interested I took quite a few pictures of him racing last weekend – you can view them on my Picasa album here. Also if you wish to send a tribute to Marco’s family you can do on the MotoGP website here.
He was such a character on and off the track and instantly recognisable thanks to his big hair!
I want to extend my condolences to his family, friends and team at this difficult time.
RIP Marco we will never forget you…
BIDS SSAS Project Role Error
0
Recently I’ve been spending a lot of time in BIDS (Business Intelligence Development Studio) building SSIS and SSAS projects. I came across a strange error when trying to build a particular SSAS project, the error was –
Error 1 The ‘Role’ with ‘ID’ = ‘Readers’ doesn’t exist in the collection.
This project had contained a role called ‘Readers’ but it had been deleted because it caused problems for other developers as it contained users who did not exist in their development environment domain (take note – never check in Roles into SVN!).
It turns out there is a pretty simple fix for this error – simply recreate the role again with the same name – in my case ‘Readers’. Build your project again – the error should now disappear. You can now delete the role you just created and continue as normal.
There are other suggestions out there for fixing this problem such as manually editing the xml files that define the cube (.cub) although I would not recommend this – the above process is much much easier and there is less risk of breaking anything.
Hope this helps!
The User Information List – a really valuable resource!
0The SharePoint ‘User Information List’ is an often ignored hidden SharePoint list. When a user is added to a SharePoint site their details are copied into the list. It’s really easy to forget its there and it can be a valuable resource when developing in the sandbox.
The other day whilst working on a sandboxed web part I needed to retrieve a link to a users My Site picture and the URL to their My Site itself. I went straight into C# server side and wrote the code to do the job. This then made my web part into a farm solution (because I was using the Microsoft.Office.Server namespace) rather than a sandbox one meaning this wasn’t such a great solution!
It then occurred to me that I could query to the User Information List to get the data I needed – the only caveat here is that the user had to be a member of the site but was willing to accept that.
The great thing about this list is that because it is just a standard SharePoint list we query it from the Client Object Model – ECMAScript in my case. All that is required is some standard ECMAScript code with a CAML query to query items in the list based on your criteria.
Here is an example of said code to retrieve a list item from the User Information List -
function getUserDetails() {
var ctx = new SP.ClientContext.get_current();
userInformationList = ctx.get_web().get_lists().getByTitle("User Information List");
var query = new SP.CamlQuery();
var queryText = "<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='Name'/><Value Type='Text'>iddev\Alex</Value></Eq></Where></Query></View>";
query.set_viewXml(queryText);
userItems = userInformationList.getItems(query);
ctx.load(userItems);
ctx.executeQueryAsync(Function.createDelegate(this, getUserDetailsSuccess),
Function.createDelegate(this, getUserDetailsFailure));
}
You will see here I am hardcoding the value here ‘iddev\Alex’ for test purposes. The best thing to do would be to pass it as a parameter to the function. In our success method ‘getUserDetailsSuccess’ we can then retrieve the values we require from the list item. In this case I will be getting the URL to the user’s My Site picture thumbnail.
function getUserDetailsSuccess(sender, args) {
var listEnumerator = userItems.getEnumerator();
while (listEnumerator.moveNext()) {
var picUrl = listEnumerator.get_current().get_item("Picture");
// Do something with the returned picture url
}
}
As you can see retrieving items from the User Information List is the same as any other SharePoint list and helps to keep your code sandboxable. As for generating your CAML query and experimenting with querying the list I find U2U’s CAML Builder is the best tool for the job!
Hope this helps.


