Click here to monitor SSC

Charles Lee

  • SharePoint 2010 release date - is it that important?

    Posted Wednesday, March 10, 2010 10:00 AM | 5 Comments

    There has been lots of excitement in the SharePoint community over the last few days as Microsoft have announced the official release date of SharePoint 2010. May 12th is the date for your diaries (RTM in April.)

    The twittersphere has been telling everyone for the last few days about this news and there is much excitement.

    The major conferences this year all seem to have a SharePoint 2010 focus and some are entirely focussed on the new product (e.g. SharePoint Evolution Conference.) 

    Now by all accounts Microsoft have plugged some significant functionality gaps that exist in WSS 3.0 and MOSS 2007 and provided some exciting new functionality.  You don't need me to tell you about these as the MVPs (and other community members) are doing a sterling job, after all that is why Microsoft has MVPs in the first place.

    Lets get real for a second though as there is a significant investment involved in moving to SharePoint 2010: 

    • Firstly you need 64 bit architecture across the board, now for some environments that is no inconsequential hurdle, that's a pretty significant roadblock.  
    • The development farm, test farm and UAT farm are all going to require the same infrastructure upgrades.
    • To take advantage of the tooling for SP2010 you will need to upgrade to Visual Studio 2010 and your development team is going to require 64 bit hardware/OS too. 
      I would not recommend installing SP 2010 in client installation mode (i.e. for Windows 7) on your developer machines, I would use this for demo machines only.
    • Something that lots of people seem to forget in all their whooping and hollering about the new release is that there is a large amount of end user training going to be required as the browser UI has now adopted the omnipotent ribbon interface and there are other new and more complicated features.
    • SharePoint Designer has also entirely changed in both look and feel and some significant feature changes have taken place.
    • Lest we should forget that some companies have not long upgraded to MOSS 2007 and are yet to see a significant ROI for that project. And the reticence that most companies feel about implementing v1 Microsoft products. 

    This is only the surface of the deeper issues which would be involved in any upgrade process, so I guess I share a small part of the concern voiced by Mark Miller of EndUserSharePoint.com

    Is SharePoint 2010 relevant?

    I don't share this sentiment in its entirety as I firmly believe that all companies should be looking at SharePoint 2010 from day one, however most large scale existing implementations of MOSS 2007 are going to be several years away from a serious upgrade project.  So should the conference organisers and the SharePoint community as a whole be a little more understanding of the real world issues?  It's easy to get carried away in the excitement of a new product and new tools to play with but there needs to be a focus on the real world issues that most people are facing day to day and at the moment and for the short term future (at the very least the next 12 months) that is fairly and squarely in the WSS 2.0/3.0 and SPS 2003/MOSS 2007 camps.

    Don't get me wrong, I am very very excited about getting to grips with SharePoint 2010 in the real world and I cannot wait for my first real project to come along, but for now I am just being realistic about the reality for most people who work with SharePoint.

    I have been spending a lot of time on www.sharepointoverflow.com recently as there is a community of people building up who are committed to answering the real world questions that folks are dealing with every day.  I urge you to take a look and either ask or answer some questions direct from the front line of the SharePoint world.

  • SharePoint: Numeric/Integer Site Column (Field) Types

    Posted Monday, March 01, 2010 10:00 AM | 1 Comments

    What field type should you use when creating number based site columns as part of a SharePoint feature?

    Windows SharePoint Services 3.0 provides you with an extensible and flexible method of developing and deploying Site Columns and Content Types (both of which are required for most SharePoint projects requiring list or library based data storage) via the feature framework (more on this in my next full article.) However there is an interesting behaviour when working with a column or field which is required to hold a number, which I thought I would blog about today.

    When creating Site Columns in the browser you get a nice rich UI in order to choose the properties of this field:

    image

    image

    However when you are recreating this as a feature defined in CAML (Collaborative Application Mark-up Language), which is a type of XML (more on this in my article) then you do not get such a rich experience.  You would need to add something like this to the element manifest defined in your feature:

    <Field SourceID="http://schemas.microsoft.com/sharepoint/3.0"
           ID="{C272E927-3748-48db-8FC0-6C7B72A6D220}"
           Group="My Site Columns"
           Name="MyNumber"
           DisplayName="My Number"
           Type="Numeric"
           Commas="FALSE"
           Decimals="0"
           Required="FALSE"
           ReadOnly="FALSE"
           Sealed="FALSE"
           Hidden="FALSE" />

    OK, its not as nice as the browser UI but I can deal with this.

    Hang on.

    Commas="FALSE" and yet for my number 1234 I get 1,234.  That is not what I wanted or expected.  What gives?

    The answer lies in the difference between a type of "Numeric" which is an implementation of the SPFieldNumber class and "Integer" which does not correspond to a given SPField class but rather represents a positive or negative integer.  The numeric type does not respect the settings of Commas or NegativeFormat (which defines how to display negative numbers.)  So we can set the Type to Integer and we are good to go.  Yes?

    Sadly no!

    You will notice at this point that if you deploy your site column into SharePoint something has gone wrong.  Your site column is not listed in the Site Column Gallery.  The deployment must have failed then?  But no, a quick look at the site columns via the API reveals that the column is there.  What new evil is this?  Unfortunately the base type for integer fields has this lovely attribute set on it:

    UserCreatable = FALSE

    So WSS 3.0 accordingly hides your field in the gallery as you cannot create fields of this type.

    However!

    You can use them in content types just like any other field (except not in the browser UI), and if you add them to the content type as part of your feature then they will show up in the UI as a field on that content type. 

    Most of the time you are not going to be too concerned that your site columns are not listed in the gallery as you will know that they are there and that they are still useable. So not as bad as you thought after all.  Just a little quirky.  But that is SharePoint for you.

  • SharePoint: Where have my content types gone?

    Posted Tuesday, February 02, 2010 7:00 AM | 0 Comments

    Have all your SharePoint site columns and content types ever mysteriously vanished from your site collection?  What could cause this catastrophe to occur?

    At one time or another when you are developing solutions for SharePoint (MOSS 2007/WSS 3.0) you will be creating and deleting site collections regularly in order to test a piece of functionality.  It is quite possible that you have done this before so you'll know what I am talking about.

    One thing that might scare you a little is if you click on Site Settings > Site Content Types and you're faced with the following:

    image

    By this point panic has set in and you are surely either running around the room like a headless chicken or else you have put your coat on and are heading for the nearest high street coffee emporium.

    Where are my Content Types?

    You will notice that the same is true of your Site Columns too!   Wait, come back. Take off that coat, you can get a coffee in a minute.

    The solution is simple and could easily be solved with one simple thing.  Time.  The Site Content Type Gallery and the Site Column Gallery are both cached on the WFE and this is only updated via a timer job.  Because you have just deleted and recreated a site collection on the exact same URL as a previously existing one this timer job has not yet run to re-populate this cache.  I think this is the ConfigRefresh job, but I am not certain.

    If you want to be sure then you can run the following command on your server(s) and you will see that all the site columns and content types will come straight back:

    iisreset -noforce

    Of course if you just wait then the timer job will run and all will be well.

    This one has caught me out before, so hopefully this will help someone out and stop them running for coffee instead of doing a simple iisreset.

  • The Upgrade Path to SharePoint 2010

    Posted Friday, January 22, 2010 7:00 AM | 3 Comments

    If your looking at the public beta of SharePoint 2010 and thinking, "We are going to need to upgrade, but where do I start?" then hopefully this basic guide should help you on how to plan and what action to take in preparation for an upgrade.

    Upgrade vs. Migration

    In my view there are two significantly different approaches to an upgrade.  One would be a traditional upgrade where you are upgrading your existing infrastructure and then upgrading your binaries and content.  The other would be creating a new infrastructure entirely and then migrating all your content from one to the other (upgrading it in the process.)  The benefit to this approach being that you are not taking any excess baggage with you (see below.)  Both approaches have significant advantages and disadvantages and will probably come down to issues of budget or politics or both any way.  I am going to look at preparing your environment for a traditional upgrade.

    Planning, planning, planning and more. you guessed it!

    1. Document your environment thoroughly.  You cannot upgrade effectively if you don't know what you have to begin with.  If you already have documentation then make sure it is up to date.

    2. Initiate some thorough performance analysis on you hardware.  If it's not performing great then this is the time to be putting in budget requests for new kit and planning your infrastructure upgrades.  Management like figures so get some raw stats in place to back up your requests.

    3. Customisations - ensure they are documented thoroughly (as above) check your infrastructure for rogue customisations that you might not be aware of.  Look in the GAC, 12 Hive, Add/Remove Programs, Solutions store, and anywhere else for undocumented customisations.   If you use 3rd party tools/add-ons then contact your ISV.  What are their plans for 2010?  What is their roadmap for these?  Does it fit in with your plans?

    4. Put together an Upgrade Strategy.  It will make more sense if you get it all down on paper and it will allow you to see any gaps or issues.  Show it to other stakeholders and get some feedback you are guaranteed to have missed something.

    5. There are lots of stakeholders and interested parties who are going to need to know what is happening when.  Create a communications plan. Who will be told what and when.

    6. An upgrade to 2010 is going to have an impact on end users (obviously), so create a training plan.  Who will be trained when and to what level, and who will deliver that training.  Costs should be built into budget plans for this year.

    7. Consider some of the other issues at this time:
      • Are you going to install a sand box for the developers to play with?
      • Are you going to run a pilot scheme?
      • Are you going to run concurrent 2007/2010 environments?

    Preparing your environment

    1. Are your MOSS 2007 (or WSS) environments up to at least SP2?  I would say get them to at least the latest CU (December CU at the moment.)

    2. Run the upgrade check tool that has been provided in SP2 (that is why it is there).  The command is stsadm -o preupgradecheck.  This will generate a HTML report (similar to that shown below) which will details any issues that should be fixed prior to an upgrade.

      image

    3. Deal with the issues raised above.  The tool has been written for a reason, if you don't deal with all the issues raised by this tool in some way then you are setting yourself up for a fall.

    4. Offload all your excess baggage.  And by this I mean go through your environments and remove any templates, features and site definitions which are not being used.  You can always restore them to the new farm later if need be.  Also check your server event logs and ULS logs.  Ensure that all recurring issues are fixed before you upgrade.  Additionally archive any unused sites (do not delete them though, just in case!)

    Upgrading the infrastructure

    1. All your servers are going to need to be running on 64 bit OS, so the majority of older farms are going to need full OS installations on all the servers.

    2. Look back at the performance analysis you did in the planning phase, can you see any areas that require beefing up.  Need more RAM in your indexing server?  Might it be best to perform your indexing on a physical box where before it coped on a VM?

    3. How are you going to upgrade all this hardware?  The easiest way is to add a new server in to your farm and then 'swing' each of the old servers out one at a time to be blown away and rebuilt as the specifications demand.  The new server is there to handle some of the excess load from the different servers as your remove them.

    Testing

    1. Test every step of your upgrade path in a non-production environment first. 

    2. If you have the resources then build an evaluation farm as an exact replica of your live environment.  You can then use this to test out your upgrade strategy to ensure all works as planned.

    3. Once you have performed an evaluation upgrade then review it and ensure that everything went to plan.  Revise your plans of the back of this evaluation.

    What about the dev team?

    1. Don't forget to plan an upgrade of your dev and testing platforms.

    2. Does you dev team now need 64 bit desktops or are they going to develop on VM?

    3. Will you upgrade the dev team to Visual Studio 2010?  The tooling is significantly improved, so I would say that should be a big 'yes'.

    Other issues to consider

    1. IE6 support has been dropped in SP2010, this will have a dramatic effect on your content authors /contributors if they are still running on IE6.  Upgrade!

    2. This would be a great time to revisit your Information Architecture using some of the new support for managed meta data and importing taxonomies.  Separate project, but seriously now is the time!

    3. Same goes for look and feel really.   Your sites will upgrade in 2007 rendering mode, but look to upgrade the visuals as soon as you can (it's only one button click, but you'll have to ensure that your CSS and JavaScript is set up to cope with some of the new web part renderings - that's what the evaluation farm is there for though.)

    Essentially the upgrade path comes down to three things.

    1. Plan everything
    2. Prepare for anything
    3. Test everything

    I hope that this little whistle-stop tour of the upgrade path has helped.  If nothing else it means that I have got all this stuff down to refer to myself.

    Note: Look here for more information on what is available in SharePoint 2010.

  • SharePoint: The security validation for this page is invalid

    Posted Tuesday, January 05, 2010 7:00 AM | 1 Comments

    Happy new year to you all.  I am starting off 2010 with an article I have been meaning to write for ages, it addresses an error that has come up several times whilst I have been developing solutions that operate outside of the parameters of a standard SharePoint customisation. Quite often when developing this type of solution I have come across this error message:

    The security validation for this page is invalid 

    Its not the greatest error message in the world as its meaning is ambiguous and that is never good with error messages.  For one thing you might not actually be developing a page. You will come across this same error when using the code in a console application or in a web service.  In fact you are more likely to come across it in those scenarios given that the absence of the digest controls which SharePoint implements is usually the root cause of the issue.

    Some classes and methods which you may call in a bit of custom code require that SharePoint performs a security validation to ensure that the call is coming from a legitimate SharePoint source.  There are two different kinds of validation depending upon the type of action being taken and therefore two different solutions to this issue.

    Updating a site or site collection using the SPWeb and SPSite classes.

    You may be using code to similar to this when seeing this issue:

    Using site As New SPSite(URL)
        Dim list As SPList = GetList("listname")
        Dim listItem As SPListItem = list.Items.Add()
        listItem("Title") = "Test Item"
        listItem.Update()
    End Using

    This code could fail with the above error for two reasons.  Firstly you are using a function to retrieve the SPList object and this could well be the cause.  The solution here is to put the code to get the required SPList object within the same Using statement.

    The second problem is that you have not prepared for a potentially 'unsafe' operation.  This can be resolved by setting the AllowUnsafeUpdates property on your SPSite and SPWeb objects.

    A better code sample for this operation would be:

    Using site As New SPSite(URL)
        site.AllowUnsafeUpdates = True
        Using web As SPWeb = site.OpenWeb
            web.AllowUnsafeUpdates = True
            Dim list As SPList = web.Lists("listname")
            Dim listItem As SPListItem = list.Items.Add()
            listItem("Title") = "Test Item"
            listItem.Update()
        End Using
    End Using

    This is a much safer and more secure method of performing the same operation, but this method should not cause the security validation error.

    Site collection administration operations

    Code which uses classes and methods from the Microsoft.SharePoint.Administration namespace can often fall foul of this security validation error.  Especially code which creates or deletes site collections as these methods tend to require a more global form digest  to be present on the requesting page.

    You can however disable the requirement for this security validation at the web application level in order to allow code executing in a different scenario to complete successfully.

    The following code example disables the form digest requirement prior to creating a new site collection, but then restores it to its previous state once the process is complete.  It is important to restore the original setting as we will not know what it was set to prior to this code running.

    Dim webapp As SPWebApplication = SPWebApplication.Lookup(New Uri(URL))

    'Save the current settings
    Dim CurrentFormDigestSettings As Boolean = webapp.FormDigestSettings.Enabled

    'disable the form digest validation
    webapp.FormDigestSettings.Enabled = False

    'create the new site collection
    Dim spSites As SPSiteCollection = webapp.Sites
    webapp.Sites.Add(FullURL, Name, Description, nLCID, Nothing, OwnerLogin, OwnerName, OwnerEmail)

    'restore the original setting 
    webapp.FormDigestSettings.Enabled = CurrentFormDigestSettings

    Disabling the FormDigestSettings.Enabled property should allow this code to execute safely out side of the 'expected' method that SharePoint defaults to.

    What not to do!

    There are various articles out on the internet detailing methods to resolve this error and some of them make reference to switching off security validation for the entire web application.  This can be done by changing the settings found at Central Administration > Application Management > Web Application General Settings

    image

    This is not an approach that I would recommend.  You are compromising the security of an entire web application in order to allow a piece of custom code to function and that way bad things live.  Much better to take some time, review your code and ensure that you are writing appropriate code for your problem.

    Hopefully this has helped you resolve the issue, or helped you to avoid ever running into it in the first place.

  • Deploying InfoPath templates within MOSS 2007

    Posted Monday, December 14, 2009 7:00 AM | 2 Comments

    I am going to start with a quote that I want everyone to remember.  It should be in the mind of anyone developing InfoPath solutions for SharePoint.

    "Never, ever publish an InfoPath form directly from InfoPath into a production SharePoint environment."

    I have seen this too many times and it will make your administrators really rather grumpy.  The reason is that although InfoPath will package your form up in a WSP (that's a good thing), unfortunately it will give the WSP and the associated feature a GUID for a name (although the feature will display an appropriate friendly name in the UI.) 

    What's the problem with that?  Well, the problem will come when you try and find the WSP or feature that deploys your form because you want to make some change.  You'll end up trawling through the feature directory to find the folder which contains your template.

    A much better solution is to develop your own feature to deploy your form template, and to do this is really rather simple, more information can be found here.

    The real benefit to deploying your templates in this fashion is that you can deploy your feature within your own WSP.  Rarely have I come across a SharePoint project which is just a single InfoPath form,  more likely it's a series of forms, or more often a form as part of a wider solution involving workflow, event receivers and other components.  Therefore being able to bundle this feature in with other components in your WSP can prove invaluable.

    What happens during feature deployment?

    If you have followed the instructions within the article above then you will be using a feature which utilises the XsnFeatureReceiver class from within the Microsoft.Office.InfoPath.Server assembly.  But what does this feature receiver actually do?  It has two functions as far as I can tell:

    1. In the FeatureInstalled event of the feature receiver any .xsn files included within the feature are registered to the farm using the RegisterFormTemplate method of the FormTemplateCollection.  These will then show up in Manage Form Templates within Central Administration.
    2. In the FeatureActivated event of the feature receiver (this is run when you activate the appropriate feature in Site Collection Features) the form template is copied to the FormServerTemplates directory within the root web of the site collection.  At the same time a site content type is created which uses this template and which includes the fields promoted within the template.  It's more difficult to know exactly what this code is doing as the code has been obfuscated.

    These are just some insights and thoughts around this process.  There does seem to be a lot of information out there but I cannot find one clear guide on the whole process.  This might be a subject for a future article.

  • Initiate a SharePoint workflow from a button on the list view.

    Posted Tuesday, November 24, 2009 7:00 AM | 18 Comments

    I came across a scenario recently where a project required that a list of items could have a button or link on a list view, which would cause a workflow to start.

    Essentially the users involved were not happy using the out-of-the-box way that SharePoint (WSS 3.0) allows users to manually initiate workflows. They believed there were too many steps involved.

    After a bit of searching, I came up with a method involving the use of a hyperlink column on the list in question, coupled with a very simple workflow. I will outline the steps involved in this process below. This is not the most graceful solution I am sure, but it is a simple solution to what can be a tricky problem.

    How was it done?

    Note: I am assuming that you have a simple workflow attached to a list, if not then please create a simple SharePoint Designer workflow. You can see how to do this here.

    1. Add a new hyperlink column to your list, this is going to represent the button which users click on to start the workflow, so give the column an appropriate name.

     CreateWFColumn

    2. Click on the list settings for your list and select 'Advanced settings', ensure that 'Allow management of content types' is set to 'Yes'. This will allow us to hide the hyperlink column from the forms involved, if your list is a custom list then you may be able to go to 'Form settings' within list settings and make more detailed amendments to what appears on the new, display and edit forms.

    ManageCTs

    3. In the 'Content Types' section of the 'List Settings' page, click on the content type for your list. Then click on the name of your column. On the 'Change List Content Type Column' page click on the radio button for 'Hidden'. Click 'OK' and return to your list, you should see an empty space for your new column. However if you click on 'New' or try to edit an existing item your column should not display.

    HideColumn

    4. I have a simple workflow attached to this list. This basic workflow merely adds an entry to the workflow history list saying 'Workflow started OK'. I assume your workflow is going to be slightly more complex, however the principle is the same. If you click on an item in your list (if you don't have one then create a quick test entry), and select the 'Workflows' icon from the item toolbar. Now click on the name of your workflow.

    ItemToolbar

    5. You should now be looking at the initiation page which SharePoint Designer has created for us, now this page can be customised to say whatever you wish via SharePoint Designer, but I am going to leave it as the default for now. The important part here is the URL and parameters.

    WFInit

    The URL of this page will be something similar to:

    http://SITE URL/List Name/Workflows/Workflow Name/Workflow Name.aspx

    and it should have 4 URL parameters, these are as follows:

    List
    The guid which identifies the list involved. This will not change for each link required on our list.

    ID
    The numerical ID of the list item involved. This is the key to making this process work.

    TemplateID
    The guid of the workflow to be initiated. This will not change for each link required on our list. Note: This guid, unlike the list guid above requires the braces {}, though these may be url encoded (so don't be surprised to see the guid starting %7B which is { when URL encoded).

    Source
    The referring URL, responses will be redirected back to here once the workflow is successfully started.

    You can probably see that we could manipulate this URL to generate a link for our new hyperlink column by simply altering the ID parameter being sent to this page. How can we do this? We simply use another workflow!

    6. Ensure you have copied the URL from step 5 to the clipboard. Open SharePoint Designer and create a new workflow for this site. This simple workflow should be set to 'Automatically start this workflow when a new item is created' only.

    WF1

    7. Click 'Next' and then add a 'Build Dynamic String' action click on 'dynamic string' and paste your URL into the 'String Builder' window. Find the ID parameter and delete the value which you had pasted in. Leaving the cursor in this location click on 'Add Lookup' and select the 'ID' column of the 'Current Item'.

    WFLookup

    Click 'OK'. Your URL should now look similar to that shown above. At the end of the URL add a comma (,) followed by the text which you want your hyperlink column to display in the list view. For example I have added ', Start my workflow'. There must be a space between your comma and your link text. Otherwise you will get the entire URL as the text for your hyperlink!

    Click 'OK' again.

    8. Add another action to 'Update List Item' and with Current Item selected click on 'Add'. The 'Value Assignment' dialog will allow you to assign your new hyperlink column to the value of the URL string we have just generated. Select your new hyperlink column from the 'Set this field:' list. Next to the 'To this value:' list select the 'fx' button. In the 'Source:' drop down select 'Workflow Data' and in the 'Field:' select your variable (probably named with the default 'Variable: variable')

    WFVariable

    ValueAssign

    Click 'OK' then 'OK' again on the 'Value Assignment' dialog. The 'Update List Item' dialog should now show this field and value in the list of items to be updated. Click 'OK' again.

    9. We can now click 'Finish' to complete our simple workflow. SharePoint Designer will now generate the required files and bind this workflow to your list.

    10. Go to your list and click on 'New' in the list toolbar, complete a test item (noting that your hyperlink column is not listed). Click 'OK' and you should return to your list view and your hyperlink column should be populated with the display value you entered in stage 7.

    ListView

    Clicking on this hyperlink should take you to the initiation page that SharePoint Designer created for you, but (crucially) the ID will be the ID for the item which the hyperlink column exists on.

    Clicking 'Start' on this page will start your workflow as designed in SharePoint Designer.

    So there you go! Wait for it.There are a few buts.

    Issues

    1. Document Libraries with check in/out enabled
    This is the same as designing any workflow which is going to update these items, you must handle checking in/out. Because our workflow is only initiated on creation then this is not a major issue. I did come across some problems in this scenario, but they were overcome by having the workflow check the item back in before updating.

    2. Custom Workflow
    This workaround is designed for dealing with either SharePoint Designer workflows or custom workflows which use an initiation form as SPD always creates a workflow initiation form anyway. It will not work for custom workflows that do not require an initiation form as there is no URL to link to (This is a scenario that I am interested in so if anyone has any recommendations then please post a comment). If your custom workflow uses an InfoPath form to initiate then you might want to look at creating links to the following URL:

    http://SITE URL/_layouts/IniWrkflIP.aspx

    This page takes similar parameters to the SPD generated page except you can supply an xsn location for your InfoPath form too. More information can be found here. The above technique should work perfectly well in this scenario, I just haven't tried it.

  • Using the JQuery dialog widget in a custom SharePoint web part

    Posted Wednesday, November 11, 2009 10:00 AM | 20 Comments

    If you have played around with the dialog widget in JQuery UI you may have noticed a couple of things.

    1. Like a lot of JavaScript libraries it messes with the DOM (Document Object Model) at what might be unexpected times and therefore it does not play well with SharePoint.

    2. It breaks the web part verb menu (the 'edit' drop down menu)

    Actually it (like a lot of the JQuery UI widgets) is an incredibly powerful tool to your client side arsenal, and as long as you adhere to some best practice it will work perfectly happily within SharePoint, or any other ASP.Net site.

    1. It messes with the DOM.

    Specifically it does not play well with the ASP.Net page post back model. This is fairly well documented across the Interweb (although the actual solution is not).

    The dialog widget is initiated via code similar to this:

    $('#dialog').dialog();

    When JQuery sees this it initiates the widget and actually moves your entire div tag to the root of the DOM (see screenshot below). Therefore outside of the form tag. So any ASP.Net controls which you may have in this div will not be included in any post backs therefore none of their events will fire.

    JQueryDialogDOM

    Never fear however as this is easily fixed by moving the parent element of your div, which will be another div which is created by JQuery and putting this at the root of the form instead (see code sample below).

    2. It breaks the web part 'edit' menu.

    Actually it doesn't. But if you have followed some code examples that are out there then it might. Essentially it may mess with this if your call to initiate the dialog is happening before the page has entirely loaded.

    Fortunately JQuery has a handy way of ensuring that no matter where your code is defined on the page it will only run when the page has loaded up. This is simply accessed using:

    $(document).ready();

    Any function supplied to this method will be loaded in memory and run when the page has finished loading. How great is that!

    As long as you follow these two items of best practice you should have no problems using the JQuery dialog widget from within SharePoint.

    Code

    The following code example is how I would use the dialog widget. At some point you need to run the initiateModalDialog method passing in the id of the div to use as a dialog. This will then run when the page is loaded and will initiate your dialog.

    When you want to show it then call openModalDialog and optionally (because JQuery will render a nice close button in the top tight hand corner) you could call closeModalDialog to close it.

    Note: If you are using this within a web part then make sure your selector (the id of your div) is unique to your web part in case you have multiple web parts on the same page.

    function initiateModalDialog(selector) {
    
    //initiates the dialog when the page has finished loading
    $(document).ready(function() {    
    
        $('#' + selector).dialog({   
            autoOpen: false,   
            bgiframe: true,    
            draggable: false,   
            width: 600,   
            resizable: false,   
            modal: true,   
            show: 'slide' 
    
        });  
    
    }); 
    
    }
    
    //Opens the selected div as a modal dialog
    function openModalDialog(selector) {
    
        //Opens the dialog
        $('#' + selector).dialog('open');           
    
        //Appends the dialog to the ASP.Net form to allow postbacks
        $('#' + selector).parent().appendTo($("form:first"));   
    }    
    
    //Closes the selected div dialog
    function closeModalDialog(selector) {           
        $('#' + selector).dialog('close');  
    }

    Obviously the options which are passed to the initiation method such as 'draggable' and 'resizable' are up to you, but for this to work you must set autoOpen to false otherwise your dialog will open straight away (unless that is what you intended of course).

    For further information please read the JQuery UI dialog widget documentation.

  • SharePoint 2010 - What to look forward to.

    Posted Wednesday, November 04, 2009 10:44 AM | 3 Comments

    For many months now the intricate details of what's under the bonnet (that's the hood to all US readers) of SharePoint 2010 has been for a select bunch of SharePoint MVPs and Microsoft partners, and it has been protected by an NDA (Non-Disclosure Agreement) threatening to bring the world down around the ears of any who should divulge these secrets.

    However, the twittering for #SPC09 (SharePoint Conference 2009) has died down, the casino tables of Vegas have emptied (at least of SharePoint bods anyway) and that can only mean one thing.

    The word is out.

    The NDA is no more!

    And blimey have the jungle drums been beating.  Every MVP, Microsoft partner and SharePoint blogger  (even Microsoft have published some stuff) from here to somewhere very far from here, have been blogging, chatting and spilling the proverbial beans on SharePoint 2010.

    So am I going to do the same? No.  I am just going to highlight the best of theirs instead.

    MSDN

    Andrew Connell

    Chris O'Brien

    Spencer Harbar

    Others

    List of SharePoint 2010 Web Parts
    SharePoint 2010 Central Admin.. Where is everything
    SharePoint 2010 Hits the Jackpot

    So read up and savour what's coming down the pipeline!

  • Using a People Picker in SharePoint Workflow Initiation

    Posted Wednesday, October 28, 2009 3:11 PM | 25 Comments

    Creating a workflow from SharePoint Designer is limiting in many ways, but it's also very quick and easy, and it covers a large majority of every day scenarios. One of the major flaws for me has always been the inability to select 'Person' as a data type for an initiation variable (assuming that this would render a nice people picker control in the initiation form and maybe pass back the User ID to the workflow).

    I have been determined to resolve this and have come up with a quick and easy fix using some bespoke client side code within the initiation form.

    NOTE: In my workflow I actually want to send an email so I am doing a little more in the JavaScript. This only works because on this project UserID@domain.com is a valid email alias. However the techniques outlined here should assist anyone who needs people data into a workflow.

    First of all create a new SPD workflow. Give it a name and select your list. Ensure that 'Allow this workflow to be started manually' is checked (so we get an initiation form generated for us).

    CreateWorkflow

    1. Select Initiation. and Add.

    2. In the Add Field dialog enter a Field name, in my case 'email' and select 'Single line of text'.

      InitData

    3. Leave Default value blank and click on Finish. Then OK.

    4. Back in your Workflow Designer click Next.

    5. In this simple example I am just going to send an email, so click Actions and select Send an email. Click on 'this message' to define your email.

    6. Click the address book on the To: line and in the Select Users dialog select Workflow Lookup. and click Add >>.

    7. Define your workflow lookup as Source: Workflow Data and Field: Initiation: email (or whatever you called your initiation variable)

      WFLookup

    8. Click OK. Then OK again.

    9. Enter a value in Subject: And also for the body text. Click OK.

    10. Now click Finish as we are done creating this simple workflow.

    11. If you open up the folder structure which SPD has created under Workflows you will see that there should be three files created:

      1. the xoml file
      2. an xml config file
      3. an aspx page

        files

    12. The final one is the one we are interested in as this contains the initiation form for our workflow.

    13. Double click on this so we can take a look.

    14. You will note that essentially this is a standard SharePoint page with a DataFormWebPart which is set up to pass the initiation data to our workflow. In this case we should have a single text box for our initiation variable.

    15. If you look at the code view you will see that various assemblies and namespaces have been included within this page already. Including the Microsoft.SharePoint.WebControls namespace which contains the PeopleEditor control. This is the key to getting people data from the users.

    16. In code view if you put some spaces above the DataFormWebPart definition then we can include this control on the page. Just copy the code below:

      <sharepoint:peopleeditor
          id="pplPicker"
          runat="server"
          allowempty="False"
          validatorenabled="True"
          onvaluechangedclientscript="SetPeopleValues()"
          allowtypein="False">
      </sharepoint:peopleeditor>

    17. Essentially this is adding the control to the page and setting some properties. The really important properties here are:

      OnValueChangedClientScript
      This property allows us to specify some client side JavaScript which we wish to run every time the value in the people picker is changed.

      AllowTypeIn
      This property restricts the user from manually typing into the people picker and forces them to use the Browse dialog to select users. See final note.

    18. Next we need to add the JavaScript to our page.

    19. At the very top of your page after all the Page and Register tags you will notice the opening <asp:content> tag for PlaceHolderMain. We need to place the following code above this control on the page:

      <asp:Content
          id="Content1"
          runat="server"
          contentplaceholderid="PlaceHolderAdditionalPageHead"> 
          <script type="text/javascript">

              function SetPeopleValues()   
              {         
                  //Retrieve the semi-colon separated
                  //list of user id's
           
                  var people = document.getElementById('ctl00_PlaceHolderMain_pplPicker_downlevelTextBox').value;     
                  document.getElementById('ctl00_PlaceHolderMain_InitiationForm_ff1_1').value = people;     
                  if (people=='')     
                  {       
                      alert('No people selected');
                  } else {       
                     
      //Split the list by ; to get an
                      //array of domain user names
             
                      var arrPeople = new Array();       
                      arrPeople = people.split(';');

                     
      //Create an empty string to hold the
                      //email addresses
             
                      var strEmails = '';

                      //Loop through the array of usernames       
                      var arrEndIndex = arrPeople.length - 1;       
                      var i=0;       
                      while (i <= arrEndIndex)       
                      {         
                         
      //Strip the domain name off and append
                          //the email address elements
               
                          var person = String(arrPeople[i]);         
                          person = person.toLowerCase().replace('DOMAIN\\','');         
                          var email = person + '@domain.com';
                          //Add this email address to our string         
                          strEmails = strEmails + email;

                         
      //If this is the final email then add this
                          //value to the text box in our initiation
                          //form control, otherwise add the
                          //semi-colon
               
                          if (i == arrEndIndex)         
                          {           
                              document.getElementById('ctl00_PlaceHolderMain_InitiationForm_ff1_1').value = strEmails;         
                          } else {           
                              strEmails = strEmails + '; ';        
                          }
                          i=i+1;
                      }     
                  }   
              }

        </script>
      </asp:Content>

    20. This uses the PlaceHolderAdditionalPageHead place holder to 'inject' some JavaScript into the head of the html page.

      Essentially this code is retrieving the value from our people picker and inserting it into the text box held on the DataFormWebPart. In my case I am doing some additional processing (to generate a semi-colon separated list of email addresses).

      NOTE: By default the PeoplePicker control (that is the TextArea html control that is rendered by the PeopleEditor SharePoint control) contains a semi-colon separated list of user names, of the form DOMAIN\UserName, so if you wanted to ignore the string parsing and processing elements of the javascript you could just set this value to the textbox straight away and then do any text processing on these values within your workflow (see below).

      function SetPeopleValues()
      {             
          //Retrieve the semi-colon separated list of user id's   
          var people = document.getElementById('ctl00_PlaceHolderMain_pplPicker_downlevelTextBox').value;   
          document.getElementById('ctl00_PlaceHolderMain_InitiationForm_ff1_1').value = people;
      }

    21. To tidy up the look and feel of your form select the <tr>
      tag that contains the textbox control from within your DataFormWebPart and set the style tag to:

      style="visibility: hidden"

      This will mean that the end user does not see the data being passed to this textbox they just select their users and click Start.

      If you save all the changes you have made to this form then try and initiate your workflow you will see that you should be able to select your users using the Browse button and then click start, an email containing the details set out in your workflow should be emailed to the users selected in your People Picker.

      And that's it!

    NOTE: If you don't declare the PeopleEditor control with AllowTypeIn set to false then your end users could manually type in any name regardless of whether or not it exists or can be resolved. In this scenario clicking start will not cause the people picker to resolve the names first and the value of your textbox will be empty as our JavaScript will not run. If anyone has any ideas on this could they please post comments as I would like to get this working.

  • Programmatically uploading an image to a SharePoint Picture Library

    Posted Wednesday, October 21, 2009 1:54 PM | 11 Comments

    SharePoint's ability to store and maintain libraries of resources (such as images, documents and other files) is a very useful weapon in a SharePoint developer's arsenal. In this article I will show how you can leverage the power of a Picture Library to store uploaded content for use across your Site Collection.

    It's fairly simple to navigate to the user interface for a picture library and upload a new file. It is almost as simple as clicking 'Upload Picture' from the Upload menu. However you will additionally be encouraged to add meta-data to your picture in order to better catalogue it.

    Uploading a picture

    However when you are writing a custom SharePoint solution like a web part or an application page you may not want the user to have to navigate away from your solution in order to upload the image into the requisite picture library. Luckily the SharePoint object model combined with some fairly simple ASP.Net code can simplify this task for you.

    The basic concept is simple you take a standard ASP.Net FileUpload control and add this in to your solution. This control provides the basic user interface needed to upload a file and it has some very useful methods for working with the file once it has been uploaded.

    The FileUpload control

    In addition to this control you will need some ASP.Net code in order to retrieve the contents of this file and some simple Windows SharePoint Services (WSS) 3.0 code to place this picture in the requisite picture library.

    You will need to access a Stream of the data from the file uploaded in the FileUpload control. This can then be used to create a new document in the Picture Library. The FileUpload control has a handy property called PostedFile which will provide access to the file which is being uploaded and in turn this has a property called InputStream which contains the Stream of data from the file. Some simple code to achieve this would be:

    Dim streamImage As Stream = Nothing
    If fleInput.HasFile Then
        streamImage = fleInput.PostedFile.InputStream
    End If

    The HasFile property of the FileUpload control is fairly self explanatory as it merely indicates if a file has been selected in the control.

    The SPPictureLibrary class in WSS 3.0 is dedicated to managing the resources held within a picture library; essentially this is identical to the SPDocumentLibrary class with the addition of 3 properties (ThumbnailSize, WebImageHeight and WebImageWidth) which control how the images display within this picture library. Although this class exists there is no need to use it unless you are interested in dealing with one of those 3 properties. In fact your code only requires the RootFolder property on the SPList class.

    The RootFolder property is an instance of the SPFolder class and this provides access to the SPFileCollection which represents the files in this library. So uploading a new file is a case of adding a new SPFile instance into this collection. The code for this would be as shown below:

    Using Site As New SPSite("SITECOLLECTIONURL")
        Using Web As SPWeb = Site.OpenWeb("SITEURL")
            Dim pics As SPList = Web.Lists("PICTURELIBRARYNAME")
            pics.RootFolder.Files.Add( _
               
    fleInput.FileName, streamImage)
        End Using
    End Using

    Essentially you are adding the Stream as a new file to your picture library. In actual fact because this code is operating at such a low level you can use it to upload any file into a document library within SharePoint.

    Image uploaded

    This article has shown how you can use a simple FileUpload control and the power of WSS 3.0 to simplify the uploading of files into Picture Libraries and other SharePoint document libraries.

<February 2012>
SuMoTuWeThFrSa
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910
How to Kill a Company in One Step or Save it in Three
 The majority of companies that suffer a major data loss subsequently go out of business. David Wesley... Read more...

Migrating from OCS 2007 R2 to Lync: Part 4
 Having migrated the rest of our users and legacy resources across, and start getting ready to... Read more...

Automated Script-generation with Powershell and SMO
 In the first of a series of articles on automating the process of building, modifying and copying SQL... Read more...

Seth Godin: Big in the IT Business
 Seth Godin has transformed our understanding of marketing in IT. He invented the concept of 'permission... Read more...

Using SQL Test Database Unit Testing with TeamCity Continuous Integration
 With database applications, the process of test and integration can be frustratingly slow because so... Read more...