Wednesday, December 22, 2010

Controls not showing the value you choose after submitting

A quick one before I forget to post about it - common issue when developing a web control (mostly EditorParts these days, or web parts that do not have an ASCX) is that the user chooses values for the text boxes and dropdownd and other controls, click the submit button, but the value in the function that deals with the button click (or the ApplyChanges function in an editorpart) doesnt get the value the user chose. Instead, the value is the old value.
There are several possible things that can cause this (I covered some in a previous article about common mistakes) but one that is so obviously simple that I forget to make sure of is this:
Make sure "base.CreateChildControls();" is the first thing called in the "CreateChildControls" function.
If that doesnt work, read my previous article about the web part life cycle.

Sandbox solutions and the publishing image field type

I recently found out (to my horror) that sandbox solutions do not support (among many other things) the publishing field types. For example, if you want to use the "LinkFieldValue" class from the Microsoft.SharePoint.Publishing.Fields namespace in a sandbox solution, then you are out of luck. So far, fair enough - annoying, but fair. I figured that I can overcome this by not using that class to parse the details of the image from publishing pages, and I will write my own function that will tease out the image URL from the string that the field returns.

How naive am I!

When I tried running this: imageUrl = item[field.Internalname);

The code would time out, and not return anything. The entire page would just hang. No exception thrown or any reason given.

My solution was to use: imageUrl = item.GetFormattedValue(field.InternalName);

Apparently this gets the string value without trying to go through anything that is not supported in sandboxed solutions. Update: after a bit of more trial and error I found that the exception thrown (sometimes) is that the assembly (the publishing one) is not serialiazble:
'item[this.ImgFieldName]' threw an exception of type 'System.Runtime.Serialization.SerializationException'

Sunday, December 12, 2010

"Cannot complete this action." error when adding a field to a list (or a content type)

If you are trying to add a site column to a list, or a content type that has a site column to a list, and get the dreaded "Cannot complete this action.", then have a read below. Note - this is valid for both sharepoint 2007 and 2010.

To troubleshoot this, I turned off the custom errors to see the entire stack trace of the error. The error was thrown by the Microsoft.SharePoint.Library.SPRequest.AddField function. This lead me to read Eric's blog post about the error and he pointed me in the right direction.

It turns out that a lookup column that allows multiple selection is not supported as an indexed column. You'd expect SharePoint to validate that, and indeed you do not get that option when configuring such a column using the user interface.
However - sharepoint does not validate that when you create the site column using CAML (which is what Eric did) or using code (which is what I did).

Eric's blog post shows how you can recreate and resolve the problem if you are creating the column using XML. So just in case you are making the same mistake I was doing, this is how I resolved my issue - I just make sure none of my code-created lookup columns is both multi select AND indexed, as you can see in the code below.

SPFieldLookup newField = web.Fields.GetFieldByInternalName(newColumnInternalName) as SPFieldLookup;
newField.Title = "My Lookup";
newField.AllowMultipleValues = isMultiSelect;
newField.Group = "My Site Columns";
if (!isMultiSelect) newField.Indexed = true; else newField.Indexed = false;
newField.LookupField = myList.Fields["Title"].InternalName; newField.Update();

Sunday, November 21, 2010

The Web application at ... could not be found when creating a new SPSite object

A quick hint for anyone hitting this issue - you are trying to open a SPSite object using a URL and hitting the following error: "The Web application at [...] could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application." is common, and can have several causes.

  1. The obvious: The URL does not exist on the farm. Solution: change the URL you are loading to the correct one.
  2. The not so obvious: the code is in a console or windows application which you are now running with an account that does not have permissions to connect to the SQL server. Solution: either run the application as a different user or grant the user permissions on the SQL database.
  3. The one hiding behind the sofa: the code is in a console or windows application that is compiled with platform target x86, while your SharePoint server is x64. Solution: set the platform target to "Any CPU".

Tuesday, October 19, 2010

Coming to Canada's SharePoint Summit

Hello to all my Canadian readers!

I am excited to announce that I will be speaking in the upcoming Toronto SharePoint Summit!
And not just speaking - from the looks of it I seem to be doing the most speaking of all the other speakers (I guess the organizers figured that the cost of a plane ticket from Australia needs to be covered by three sessions). Please come see me talk on:

Oh - and if anyone has recommendations what to do the week before the conference (last week of January) - please comment here! Ski resorts recommendations would be most welcome.

Saturday, October 16, 2010

PowerPivot For SharePoint

Are you in Canberra this week? even if not, you may want to read this post.

This week I am presenting in the Canberra SharePoint User Group about PowerPivot for SharePoint. I have spent the weekend reading and testing this application - mostly trying to figure out how it is different from Excel Services.

Basically, powerpivot for excel is a powerfull database analysis add on to excel that creates connections to external databases, analyses the relationships for you and allows you to create great pivot tables and charts from this relational external data. This makes creating pivot tables from complex databases very simple.

PowerPivot for SharePoint is a service application that you install from SQL2008R2 features. This adds the ability to open the workbooks that were created by powerpivot on the browser, while still remaining connected to the external database. It also adds a "powerpivot gallery" list template that creates a special document library with a nice and smooth interface to allow the users to look for the pivot sheet they want to open, and it has the default "open in browser" behaviour. The data gets refreshed and accessed on the server, so even users with weak desktops can analyse huge databases (up to 100 million rows - depending on the amount of RAM the server has). A good high level overview can be found on the powerpivot blog on MSDN, installation instructions on MSDN and a demo and a lot of marketing information on the official powerpivot site.

Two thing you should know:
to allow the web application to authenticate to the database the pivot is connected to, you will probably need to activate the "Claims to Windows Token Service" service (which is by default off if you used the configuration wizard to configure for you). Otherwise, the power pivot will keep giving you authentication errors.
The last thing is a problem with the way the powerpivot application is deployed. Don't ask me why, but there is a problem with how it is deployed, as described in this powerpivotgeek's blog post. If you get an error when opening a powerpivot gallery list, check out the geek's post for the solution (simply deploy the solution to the web application...).

So, if you are in town, come say hello and watch me install, set up, and run powerpivot in the Canberra user group. If not, you have a chance to see me next week in the South East Asia SharePoint Conference in singapore.

Monday, August 23, 2010

What do you get when you google "Visual studio 2010"?

I don't know about you, but my search engine of choice just gave me a big surprise as the first result. It only happens when you use google Australia (.com.au), not in google.com:

Am I imagining things, or is the first result a spam site? Microsoft - you may want to do something about this...

Sunday, August 22, 2010

My SharePoint 2010 How To book is now available in print

My second book is now officially published and I can stop fretting about revisions for a while. If you like, take a look at it in Amazon, where you can take a look inside!
SharePoint 2010 How To (Amazon)

If you want to buy either of my books, (paper or digital copy), you can use the following links:

Thursday, August 12, 2010

How to set values for a checkbox choice list field? (SPFieldMultiChoice)

This is a question I just recieved through my "contact" form for this blog. The person (Chris) who asked the question gave a wrong email address, so I will post the answer publicly since I believe this can help other starting sharepoint developers - especially since I saw some wrong tips coming up in google when you search for it. So here is the right way to do it.

Question: "Hi, thanks a mil for those snippets!One question: I'm trying to programatically add selected items of a checkBoxList to a SPListItem, but am not sure in what format it wants it. i.e I've added all items as you suggested - newItem["Name"] = "blah" etc, but when it comes to the field that requires the selected checkboxlist values, I'm stuck."

Answer: to set the value for a check box choice list (a field of type choice, with multiple choices allowed - showing checkboxes), you should use the SPFieldMultiChoiceValue class to set the value. This class allows you to construct the list of choices you want to set for the column by adding the string values to it. Here is an example on how to use it:

SPList sampleList =web.Lists["test"];
SPFieldMultiChoiceValue val = new SPFieldMultiChoiceValue();
val.Add("choice1");
val.Add("choice3");
SPListItem newItem = sampleList.Items.Add();
newItem["Title"] = "This is the new item";
newItem["test"] = val;
newItem.Update();

Wednesday, August 04, 2010

Using jQuery validation in a sharepoint web part

As we all know, a sharepoint page can only have one <form > tag in it. As anyone who wanted to use jQuery validation knows, the validation script needs to run on a form tag.
So how do I use the validation code in a sharepoint web part?

The answer is to run the script against the form that already exists in the page. For example, I had to write a web part with an email address field, and wanted to help the users by validating the text they entered is a valid email address on the client side (I also validate on the server side - just in case someone is running a browser with no script). This is the "Render" override code that I used:

       txtEmailAddress1.CssClass = "required email";
       base.Render(writer);
       if (SPContext.Current.FormContext.FormMode != Microsoft.SharePoint.WebControls.SPControlMode.Edit)
       {
              writer.Write(@"<script>
$().ready(function() {
    $(""#" + this.Page.Form.ClientID + @""").validate();
});
</script>
");
       }

As you can see, I am adding a css class of type "required email" for the text box, and then telling the form on the page to validate using the jquery validation plug in. This of course assumes you added the references to the jquery scripts to the page...which you may want to do as part of the web part (override oninit, and registerclientscriptblock) or as part of the master page (if you expect a lot of web parts to use it).

As for the "if (SPContext.Current.FormContext.FormMode != Microsoft.SharePoint.WebControls.SPControlMode.Edit)" line - you have to be careful that your validation does not prevent you from editing the page. For example, if you remove that "if", you will not be able to change the properties of any web part on the page without first entering a valid email address in the textbox!

I am speaking at the South East Asia SharePoint Conference!

Are you planning to be in Singapore on October 26-27 this year? You should! the speakers are being announced, and I for one will be there for at least one presentation - how to build web parts for 2010. And no, it is not going to be the regular "open visual studio, choose the web part project" presentation...get ready for big things!
See you there!

Saturday, July 31, 2010

A bit more about custom field types and XSL

The following are the attributes you can use in XSL to identify the field you want to change (or access the value of):

  • Name (example: "First_x0020_Column" - the internal name of the column - not the field type!)
  • Type (example: "Text" - the base type of the field type)
  • FieldType (example: "MyCustomFieldType" - the type name of the custom field)
  • DisplayName (example: "First Column" - the title of the column
  • ID (example: "1b858cea-4306-4cf9-91e8-8bb8674dcdf4" - the GUID for the current column

Applying a XSL stylesheet to a custom field

In the MSDN walkthrough and examples on using XSL to create a custom rendering style for a custom field type, the sample XSL all use the field's name as the reference. This is a bit silly - since it means the users need to create the new fields with the exact same name.

While the option to create a custom rendering based on the field name is welcome and will be very useful (if for example I am deploying a column to a farm and I want it to have a unique rendering template), the articles do not explain how to create a XSL rendering template for a field type - regardless of what the fields created from that type are called.

The solution is simple. Lets say your field type is "MyFieldType", then instead of the following line that uses the title of an instance of the field ("my field type"): <xsl:template match="FieldRef[@Name = 'My Field Type']" mode="Text_body"> use the following line instead, which uses the type name of the field: <xsl:template match="FieldRef[@FieldType = 'MyFieldType']" mode="Text_body">

Monday, July 26, 2010

5 Days SharePoint Development Training - Canberra, 16th August, 2010

Are you in Canberra on the week of the 16th, and is just itching for some sharepoint 2010 developer training? look no further!
I have teamed up with my friends from Synergy to deliver the first ever Synergy SharePoint 2010 Development course. For more details on the content of the course and how to register, head to Dimension Data's web site!

Tuesday, July 13, 2010

New look for the blog

Do you like it? Blogger has some new templates, and I figured its time for a change.

Update: following some comments, I reverted to white background again - and removed the width restriction that pissed me off. Is this better?

Monday, July 05, 2010

"The local device name is already in use" error when using AddFieldAsXml

I had the following exception thrown at me today when trying to add a site column using AddFieldAsXml method: "The local device name is already in use".
The reason was that my XML contained a field ID - which is what the XML for a field is supposed to have when it is used as an element file in a feature, but not when you are adding the field using code. So - beware!

Thursday, July 01, 2010

Read my book on Rough Cuts

Do you want a preview of my upcoming book - the 'SharePoint 2010 How To'? simply go to Safari books online and read away! There is also a purchase option if you like what you see...

Sunday, June 20, 2010

SharePoint Conference Australia Presentation Notes

Thanks to everyone who came to see me and Brian present in the Australian SharePoint Conference last week!.
To answer the question that we got during the demo, the silverlight web part project template can be downloaded from this site: http://code.msdn.microsoft.com/vsixforsp.
Also, to see the code for Brian's twitter map web part, see his blog post on the subject: http://blog.brianfarnhill.com/2010/05/21/twitterbing-maps-web-part-how-i-did-it/.
Finally - for everyone who asked for the slide deck, it is now available from my company's (Extelligent Design) web site: http://www.extelligentdesign.com/in-the-news/sharepointconferenceaustraliapresentationnowavailable where you can also purchase KWizCom products (for australian\new Zealand customers only) or contact me about sharepoint training or consulting.

Tuesday, June 01, 2010

Validating Web Part Properties

Nothing is more annoying than configuring a web part by changing its properties and then hitting ok only to see the web part display an error that a property is invalid - and having to open the properties pane again to fix the problem.
To avoid this, best practice is to validate the data entered in the "set" of the web part property. For example, if I have a web part property that needs a comma delimited array of numbers (for example 1,2,3,4) and I don't want to build a tool part just for that, I can still build a property like this:

public string NumberArray
{
    get{return _numberArray;}
    set{_numberArray=value;}
}
The problem with the code above is that it is not validating that the string entered is indeed an array of numbers. To do that, I could change the code to something more like this:
public string NumberArray
{
    get{return _numberArray;}
    set{
          string [] arr = value.split(',');
          foreach (string item in arr)
          {
             int i;
             if(!int.TryParse(item,out i))
                throw new Exception("The item \""+item+"\" is not a valid number");
          }

_numberArray=value;}
}
This will do what I want - preven the user from closing the web part properties pane before fixing the error in the property, but it will not display the nice informative error to the user. Instead, it will show a generic error "An error has occurred" despite the fact that I specified what the error was when I threw the error!
Why? because to do that the exception must be of type WebPartPageUserException.
So the correct code for validating my sample property would be:
public string NumberArray
{
    get{return _numberArray;}
    set{
          string [] arr = value.split(',');
          foreach (string item in arr)
          {
             int i;
             if(!int.TryParse(item,out i))
                throw new WebPartPageUserException("The item \""+item+"\" is not a valid number");
          }

_numberArray=value;}
}

Now - when the users put an invalid value in my property they will be notified that it is invalid, and which value it was.

Sunday, May 30, 2010

Assembly stuck in memory despite being replaced

I had a wonderful time this weekend trying to find out why is it that when I deployed a new version of my solution - one that included more debugging information than the previous one, nothing would come out - it would still print out the old data.
I went as far as to remove the solution entirely, make sure the GAC is clear from the assembly and then manually drag and drop my new assembly (thinking it is my WSP that is stuck with an old assembly) and still I get the old code running instead of the new one.
What didnt I do? I tried IISreset and all sort of tricks, but I could not reboot since it was not my server (partner company asking me to help out with some dev work on their server).
It turns out that if I could reboot it would have saved me all the time I spent - but then I would not have figured out the reason that was happening!

Curious? Well, here it is - I had a windows application running that used sharepoint object model to triger the timer job I was trying to redeploy. The windows application did not have a reference to the timer job code - it just used the OM to query the server what timer jobs are there and then let me choose one and execute it. So I never suspected it was the culprit - especsially since I used it to confirm the timer job was deleted after I removed the old solution.
But it was.
For some reason, just having it running, connected to sharepoint objects, somehow caused the old assembly to remain in memory\cache (I will not pretend to know why or how) and once I closed it I suddenly got the new code running!

There - if I saved someone the same frantic research I was doing this weekend, I am a happy man.

Wednesday, May 19, 2010

Last chance to register to the Australian SharePoint Conference

It is next week in Sydney! didn't you hear? I will be there, speaking about web parts and sharepoint 2010 with my friend Brian Farnhil. Dare you miss it? it is Australia's biggest SharePoint event of the year after all...

There will be:

  • 20 sessions of end user/power user/business content including some great case studies including Telstra, Volvo and a number of Industry verticals such as finance, insurance, legal and engineering
  • 20 sessions of pure technical content for IT Pro, Administrators, Developers and Analysts
  • Content is relevant to those using WSS, MOSS 2007, and new 2010 products

Special offer!
Come see me during the conference and get a 10% discount on all products by KWizCom (offer only valid for Australian and New Zealand customers).

Monday, May 03, 2010

My stupidest mistake of the year

I just spent 2 hours trying to debug why my custom web page server keeps timing out on me...It has a custom list form template that uses an override of the ListFieldIterator. What did I do wrong? take a look at my aweful code...and see if you can spot the infinite loop...

override DefaultTemplateName { get{ return this.DefaultTemplateName; } }

Saturday, May 01, 2010

To Silverlight or not to Silverlight?

I just found that having silverlight installed on my client is not always a good idea when using SharePoint 2010. Yes, it makes for a much better presentation and user interface...but...in some instances you lose functionality!

For instance, when creating a list, if you are using silverlight you get the awesome create dialog - with searching and filtering and all. And all you have to do is choose a template and give the new list a name, and that is it! all the other settings (description, add to navigation) are kept as default. Not happy with the defaults? simply click the "More Options" button and you will get the same dialog that people without silverlight get - the same one that you used to get back in sharepoint 2007.

...

Or do you?

It seems that the more options dialog only offers the basic settings for the lists - not the custom ones. For example, on a task list, the dialog is missing the option to "Send e-mail when ownership is assigned", which is shown in the settings page if you do not have Silverlight .

Since this is something that can be configured later (list settings, advanced settings), I guess it is not going to be high on the priority to change, but it does irk me that by installing Silverlight I am actually losing some settings when creating the list that I used to have before Silverlight .

an idea for SP1?

Friday, April 23, 2010

First win for Office 2010 (and first fail for office x64)

For some reason I cannot fathom, Word 2007 never jumped to the headers when I clicked them in my book documents. That means that when I opened the document map, and saw the headers I wrote, I could not click on them to navigate to them - which is a very useful function, and for some reason Word 2007 refused to do it for all documents for my book.

Word 2010 just installed, and solved this issue! now I can write more comfortably - thanks Microsoft!

Now for the fail...I installed Office x64 - in hope that it would work better on my Windows 2008r2 machine, utilizing whatever it needed from its 12GB RAM (ok, honestly - I don't actually need 64bit office. this version is meant for excel dark wizards who need more power when working on worksheets bigger than 2GB). However, I almost immediately regretted that choice, as now I cannot use the datasheet view in SharePoint (both 2007 and 2010). This technet article explains that this is because the 64bit version does not support the 32bit activeX that is used by the datasheet view:

"The Edit in Datasheet view functionality is not supported if you install 64-bit Office 2010. However, the functionality is available if you install 32-bit Office 2010. "

But...I am still curious to see how I go with 64bit office. so I will keep it on my 2008r2 server, and install the 32bit version on my windows 7 hyper-v machine (and take my screenshots of the datasheet view from there).

update (30 minutes later): it also appears that you cannot install SharePoint designer (since it is 32bit) on the same machine. lucky my win7 virtual machine is so snappy!

Thursday, April 22, 2010

Error downloading prerequisites for SharePoint 2010

When installing SharePoint 2010 (which I am doing now), if you get an error when installing the prerequisites that it couldnt download the components, make sure your firewall is configured to allow it to download.

I don't know which firewall rule specifically blocks the installer, so I just turned the firewall off, let it finish downloading and installing all prerequisites, and then turned the firewall back on. Done!

Sunday, April 18, 2010

SharePoint 2010 How To book is ready!

If you were worried that you'r pre-ordered book will not arrive on time, you can now relax. I have just sent the first complete draft to the publisher, and seeing how Microsoft is due to release the RTM version of SharePoint 2010 this week or the next, I only have to wait for that to be able to add the images, check what changed and what was fixed, and send my publisher the final draft.
Then it may take a few weeks to go over the entire editing process, but I hope this time it will be faster, and then the book is ready to be bought by you!

Monday, April 12, 2010

Book update and MVP status

8 Chapters down...only 6 to go. I intend to finish the book this weekend - wish me luck!. I am finding out a lot of small things that got changed (improved) in 2010 for the end user, and it is slowing me down - but every such thing only boosts my fondness for this version. If I get some time I will blog about those nice little things.
Also - In case you wondered, My MVP award was renewed again this April. Thank you Microsoft for thanking me!

Thursday, March 25, 2010

A new internet site using SharePoint - indigenous.gov.au

Take a look at the new site - an external facing internet site created for the Australian goverment to spread news about the Indigenous Australian related projects. My company, Extelligent Design, helped build the site which includes such features as tagging (with a custom built tag cloud), content query web parts and jquery picture library slide show components. I have helped write some of the components above as part of my day job.

Update: I was asked what the slide show component is - the answer is not flash, nor sliverlight - but a jquery script called galleryview (http://www.spaceforaname.com/jquery/galleryview/) that we customized for our needs (different CSS, do not show descriptions and so on) and then embedded in a web control that pulls information from a picture library, formats it as a UL list, and then uses script to show it as a slide show. Easy, and accessible - because even if you don't have javascript enabled you see the picture as a UL list (which is shown anyway at the bottom to make it accessible for other people).

Sunday, March 14, 2010

My SharePoint 2010 book available for pre-order

I just noticed that Amazon UK is making my 2010 book available for pre-order.
This is a bit stressful for me, since I have only written 5 chapters so far (out of 14 planned) - I guess I'd better start typing faster!
If you are interested in a end user, how to book that covers all the basics for your end users, have a look at the link, and keep a close watch - I will be posting updates. I can tell you that the book will be very similar in structure to the 2007 book I have already published.

Friday, March 12, 2010

Adding the "Sort by modified date" option to SharePoint 2010 search

By default in SharePoint 2010, the search actions link web part does not show the option to change the sorting order to sort by modified date. However, it is easily added back through the web part's properties. Note that it is now shown as a dropdown and not as a link as it did in SharePoint 2007...

SharePoint Foundation - forcing a search index

If you have SharePoint foundation and you want it to index your sites NOW, all you have to do is go to the service job definitions page and tell the timer job to start.
To do it - open central administration > monitoring>review job definitions>"sharepoint foundation search refresh" and click the "run now" button at the bottom.

SharePoint Foundation - no indexer error

If you have installed just SharePoint Foundation (SPF) and created a site collection before turning search service on (which is off by default when you install SPF), you will get an error "your search cannot be completed because this site is not assigned to an indexer.".
After starting the service it still did not resolve the issue, so I tried to find where to assign the indexer to the site. Before long, I realized that it is not on the site collection settings, nor on the web application settings but instead on the content database setting.
Just go to the manage content databases screen in central management, click on the content database in question (usually WSS_Content) and in the middle of the page there is the option to select a search server.

PS - is anyone else finding it puzzling that the default name for a SPF database starts with WSS? Maybe MS will change that before release?

Friday, February 26, 2010

Web Part architecture - what I had to fix in ChartPart

An important aspect of web part architecture is "redeploy-ability".
Redeploy-ability is when you want to use the web part as part of a site template. When you develop a web part, you need to think of redeployment - since the web part will need to be deployed with a set of pre-configured settings into a new site - the web part's properties. If those properties cannot be set as part of the site template, the web part cannot be redeployed.

Let me use ChartPart as an example.
If you don't already know, there is a project called "ChartPart" in codeplex, that shows lists as charts:
chartpart2-1.png
The web part needs to store a lot of information in its properties when it gets configured. For example, it needs to store the X axis and the Y axis columns. For this, the developer created a property called "XAxisSourceColumns", of type "List<string>". That allowed him to add column names to the list easily in the code.
The problem with this, is that this property has to be stored with the web part, and is required for the web part to work - that means if I export the web part, then I expect that when I import it again, all the settings will be there. With a property of type "List<string>", this will not happen - because the web part system does not know how to serialize a "List<string>" object into XML (a .webpart file) and doesnt export those settings. Then, if you import the web part you just exported, you lost those settings. I recommend storing the information as a simple type (defining the properties as strings for example) for serialization purposes.

A second problem, and one that you can see with a lot of Microsoft web parts as well as ChartPart (for example the Content Query Web Part) is that when a web part is connected to a list, the property stores the list's ID - a GUID, instead of the list name. This is smart - because someone may rename the list, and the ID will remain the same, so the web part will keep working. On the other hand - using an ID means that you lose "redeploy-ability" - since a list's ID gets generated randomly every time the site gets created, if your template has the web part set with a specific ID, then when you create a new site off that template, the web part will be broken - since it will not find a list with that ID in the site.
I recommend you store in the web part both the list's ID and the list's name. This way, if there is a list with the ID that was specified, the web part uses it, and therefore does not break when the list's title changes. But if there is no list with that ID (or no ID was set - which is what we will do in a template), the web part will look for a list with the name that was set - which means it will support redeploy-ability.

Finally, a problem with many web parts that allow linking to objects in other sites is that the site url property often expects a value - and does not support a "this site" option (which I like to add as a blank value). This means again that we lose "redeploy-ability" - since there is no way to configure the web part to look in this new site that was created from the template - the web part expects a link to a site...
I recommend supporting a "leave site url empty for current site" as a minimum requirement for a web part, and if you want to be real good, add support for relative URLs.

So how do we resolve this?


Usually we implement "redeploy-ability" when we start writing the web part - we create properties of type string that are not browse-able, and then create ToolParts that populate them using a good user interface - that gets the list of columns (in this example) from the user, then serializes it into a string that gets saved in the web part. It does mean a bit more effort to serialize the list and deserialize the string - but the end result is that when you export the web part you get what you expected - the serialized property gets stored in the .webpart file.

Supporting "blank" as current site url
In ChartPart to make this change was easy - I looked for all the places that SiteUrl property was used, and changed the code to check if the siteurl property is empty then to use the current site url. This is not as effective as you can make it (a function that gets a SPWeb object would have done it better) but it saved me a lot of refactoring:

string url = this.SiteUrl;
if (string.IsNullOrEmpty(url))
   url = SPContext.Current.Web.Url;
using (SPSite site = new SPSite(url)) 
{
   ...
}

Supporting list names as well as IDs
In ChartPart I added a property called ListName and then made the following modifications to all locations that referred to the list ID:

if(this.ListId != null && this.ListId != Guid.Empty)
   list = web.Lists[this.ListId];
else if(!string.IsNullOrEmpty(this.ListName))
   list = web.Lists[this.ListName];
I also changed the toolpart so that when a user picks a list from the dropdown, both the list ID and the list name gets stored.

Serializing complex type properties

In ChartPart for example, since it was already developed and I had to keep supporting existing web parts that store the information as a list, I couldnt remove the existing properties. However, what I did is add a string property for each one of the "List<T>" properties, that return the serialized value of the "List<T>" property it reflects, and when set it sets the "List<T>" property. Here is an example:

//the original property
[Personalizable(PersonalizationScope.Shared)]
public List XAxisSourceColumns
{
    get;
    set;
}
//this is for supporting exporting and importing the web part (which does not serialize List)
//we will have these as pipe seperated strings.
[Personalizable(PersonalizationScope.Shared)]
public string XAxisSourceColumnNames
{
    get
    {
        if (this.XAxisSourceColumns != null)
        {
            string ret = "";
            foreach (string xAxisColumn in this.XAxisSourceColumns)
            {
                if (!string.IsNullOrEmpty(ret))
                    ret += "|";
                ret += xAxisColumn;
            }
            return ret;
        }
        else
            return "";
    }
    set
    {
        this.XAxisSourceColumns = new List();
        if(!string.IsNullOrEmpty(value))
        {                 
            string[] values = value.Split('|');
            this.XAxisSourceColumns.AddRange(values);
        }                
            
    }
}

Monday, February 22, 2010

Making the content query web part deployable

My biggest issue with the CQWP? its not deployable when connected to a specific list in a specific site.
If you configure a CQWP web part to connect to a list in a site, the web part saves the ID (GUID) of the list - and if you want to deploy the web part as part of a feature or onet.xml so that the web part gets added every time a user creates a site, it will fail - because the ID of the list changes every time you create a new site.

My solution? override the web part and implement the following 2 functions:

public class MyBetterQueryWebPart: ContentByQueryWebPart
{
public void SetListGuid()
        {
            if (!string.IsNullOrEmpty(this.WebUrl) && 
!string.IsNullOrEmpty(this.ListName))
            {
                using (SPWeb web = SPContext.Current.Site.OpenWeb(this.WebUrl, true))
                {
                    SPList list = web.Lists[this.ListName];
                    this.ListGuid = list.ID.ToString();
 
                }
            }
 
        }
        protected override void OnLoad(EventArgs e)
        {
            if (!string.IsNullOrEmpty(this.WebUrl) && 
!string.IsNullOrEmpty(this.ListName) && 
string.IsNullOrEmpty(this.ListGuid))
            {
                SetListGuid();
            }
            base.OnLoad(e);
        }
}

This code checks if the web part is in list mode (has a list name and a web url) and is "corrupt" - doesnt have a list ID. if it finds that is the case, it dynamically loads the list ID based on the site url and the list name.

Tuesday, February 16, 2010

Help me decide on a logo for my new company - Extelligent Design

Yes, I have opened my new company and am now working for myself. I will give details soon - including releasing the web site, but I cannot do that without a decent logo. Can you help?

If you are interested in earning $300 USD, go to my logo contest and submit an entry there. It finishes on the 20th of February, so there is not much time.

You don't have to submit an entry - you can also vote on the entries other people entered and let me know what you like. To do that, go to the contest next week when the submissions has ended (after the 20th) and login to vote (you will have to register in that site - which I recommend if you have a few hours to spend looking at photoshop wonders).

At the end of next week I will announce the winner and release my brand new site - offering sharepoint consulting, training and products (I am now the official distributer of KWizCom products in Australia and New Zealand)

Monday, February 15, 2010

Error: "Failed to connect to the database server or the database name does not exist"

I have installed a new development computer at home (quad core, 12GB RAM dell studio xps) and have set up boot from VHD - to a win2008r2 machine.
I figured that setting up SQL and domain controlers on the host would be best, and hyper-v for guests (sharepoint 2007 and sharepoint 2010 beta) that would connect to the host machine's domain and sql.
However, when I tried to connect either version of sharepoint to the SQL, I got the same error:
---------------------------
SharePoint Products and Technologies Configuration Wizard
---------------------------
Failed to connect to the database server or the database name does not exist.
Ensure the database server exists, is a Sql server, and that you have the appropriate permissions to access the database server.
To diagnose the problem, review the extended error information located at C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\LOGS\PSCDiagnostics_2_17_2010_8_45_30_259_232810164.log.
Please consult the SharePoint Products and Technologies Configuration Wizard help for additional information regarding database server security configuration and network access.

The solution? I turned off the firewall on the host machine...So now I am open for attacks, but atleast my virtual machines can talk to my sql on the host... So instead of leaving it off, I just followed this MSDN article that explains how to open the ports for SQL...