Archives

Archives / 2011
  • Summing up the year of 2011 and embracing 2012

    Tags: Personal, SharePoint 2010, SharePoint 2010 Web Parts in Action

    It's that time of the year, when you're thinking about what you've done and accomplished the last twelve months. I've been writing a summary for the last five years (2006, 2007, 2008, 2009 and 2010) and I always think it's fun to look back at the year gone and do some predictions for the upcoming one.

    This year has been totally crazy - I've been enjoying my work and clients/projects at Connecta and I totally love that we have such a strong team and offering. I can really feel the momentum we have in our team and projects, and nothing is stopping us now...

    Writing

    As usual I've been jotting down a couple of blog posts, some better than others (IMO) and unfortunately there are several that I just haven't had time to publish. I have on average 1.000 subscribers to my feed and a whole lot of other users finding my writings through the search engines - thank you all readers! These are the top ones for the last 12 months.

    1. Calling a WCF service using jQuery in SharePoint - the correct way
    2. Working with URLs in SharePoint 2010 JavaScripts
    3. SharePoint 2010 Ribbon Controls - Part 4 - The TextBox control
    4. SharePoint 2010 Ribbon Controls - Part 5 - The Button control
    5. Improve performance of your SharePoint 2010 applications using Windows Server AppFabric caching

    Interesting to see jQuery and JavaScript posts topping the list - might give us a hint on what's been popular this year... The post that still is #1 is the Fix the SharePoint DCOM 10016 error on Windows Server 2008 R2 (remember where you read this first :-).

    SharePoint 2010 Web Parts in ActionI also finally got my book SharePoint 2010 Web Parts in Action published in April. It took over a year of writing, re-writing, testing, reviewing etc etc to get it done. And when the books finally arrived in printed form it was such a great feeling. It's a tough competition on SharePoint books nowadays, and I'm glad to see quite good sales figures and especially great reviews (if you haven't already - head on to Amazon and tell me what you think).

    MVP again...

    In April I was re-awarded the Microsoft Most Valuable Professional - SharePoint Server award. This is an award for your on- and offline community contributions. Being a part of the SharePoint MVP community is great and gives you a lot of amazing contacts with some great people.

    The Master!

    The MCM - Microsoft Certified Master - program was the highlight of the year! In April/May I attended the R8 rotation of the SharePoint 2010 MCM program which was three long and tiresome weeks with best-in-breed SharePoint training by the best of the best. I passed all three written exams and the qualification lab on first attempt and was allows to call my self a SharePoint 2010 MCM in the end of May. Since that rotation I've really felt that my SharePoint skills and confidence has improved - and I do think that also my customers feel the same. I did a post about my experiences of the MCM program a couple of months back - and if you're interested go ahead and read it.

    MCM

    Conferences and travels

    This year has also been filled with a lot of conferences and travelling. First of all in march all MVP's met up in Redmond, at the Microsoft campus, for the annual MVP Summit. This was my first visit to Redmond and the summit and I met a lot of the people I've only met through the online world previously. I had a blast with paintball, late nights and beers talking to some really great friends. A couple of months later I went back to Redmond for the MCM - the weather was the same as in March! October and November was quite hectic with another trip over the pond to the SPC 2011, a trip to the European SharePoint Conference in Berlin and finally the Southeast Asia SharePoint Conference in Singapore. I also managed to do a couple of conferences on home turf as well.

    The International SharePoint Conference 2012I've already planned a couple of trips for 2012 - at least two trips to US again, one is the SPC 2012 in Las Vegas where I hope to meet a lot of you. I have also planned a trip to London in late April for the International SharePoint Conference. This will be an extraordinary conference with two really cool tracks - one IT-pro and one dev, where we'll build one big solution during three days. I promise to get back to you with more information about it as soon as it's available.

    SharePoint

    Yea, as usual this year has been all about SharePoint for me. I've seen the product mature, I've learnt more about it (again) than I ever could expect and I see a huge and increasing demand for the platform. If you're new in IT - bet on SharePoint! We've also seen the birth of Office 365. I'm running both my work and personal e-mail in the hosted Exchange solution and I'm very satisfied. This fall I've spent a lot of time with SharePoint Online trying to do real work and deployments. To put in in nice words I should say that I'm more of an on-premise guy!

    Predictions

    In these recap posts I've done some predictions for the upcoming year. I had three last year and I was right about two of them: Windows 8 is communicated and with Hyper-V support.  I've been thinking quite hard on what predictions to have this year, trying not to reveal anything or stating anything obvious. So here are my predictions for 2012.

    • Silverlight will die! - yeah, Microsoft haven't put it in those words, but that's what's going to happen. We'll probably see Silverlight doing it lasts breaths on the Windows Phone 7 platform though. HTML5 and JavaScript will take over.
    • Second Browser World War - for a couple of years browsers have tried to strive for a common standard, and Internet Explorer has finally caught up. Since the HTML5 standard is far from standardized we will see Firefox, Chrome, Safari and IE add its own proprietary "interpretations" of the standard which will diversify the browser world once again. It's already happening, unfortunately...
    • Windows Phone momentum - I do think that the movement of Windows Phone 7+ will finally accelerate 2012. Great hardware, Nokia, great apps, unlimited marketing money and people getting bored of icons in a row are a few of the reasons. And I never ever had my WP7 phone crash - but for the Android devices we have in the family it's a part of the daily routine...
    • Less cloudy - this is more of a wish than a prediction but I do hope that 2012 will be less cloudy. I'm so fed up with the term "cloud"! Of course hosted services will still be a major option but I do think that more and more customers are going to look at internal hosting and/or hybrid solutions.

    What do you think?

    Thank you and a happy new year

    So, I do not think I will be posting anything more this year! It's been a fantastic year but I'm sure 2012 will beat 2011 big time. Thank you all readers and followers and thank you to all new friends I've met throughout this year and thank you to everyone supporting me and has to put up with late night IM's or e-mails (you know who you are!).

    Now, enjoy your last days of 2011 and have really great New Years Eve - I know I will (even though enjoy incorporates some work!).

  • Suddenly getting Access Denied on your SharePoint 2010 User Profile Sync

    Tags: Security, SharePoint 2010

    The last week I stumbled upon a really interesting new and shiny User Profile Synchronization issue - one of these things that just make your day! We had to manually initialize a full synchronization, after doing some updates to one of the user profile properties, and the user profile synchronization would not just start...

    Timer Job - Access DeniedEverything looked fine (on the surface) and we tried the incremental sync, which also looked like it was starting but nothing happened. The sync service was up and running and the FIM services was started, the MIISClient showed no activity. We took a look at the timer jobs, which are responsible for kicking of the synchronizations and saw that they all failed with the error message Access Denied.

    No more than this simple error message. Since the timer jobs are executed using the Farm Account this sounded very peculiar. Oh, and you who still have your Farm Account in the local administrators group would probably never see this error, you'll be aware of this in a minute!

    Next resort was to dig in to the trace logs (ULS), using my favorite SharePoint tool: ULSViewer. And there we had a Critical and an Unexpected entry, related to this Access Denied error message. ULS Logs

    The accompanying stack trace showed me that it was some problems getting the instance of the Management Agents.

    Stack Trace

    Time to fire up my second best SharePoint tool: Reflector! Peeking into the failing method in the User Profile assembly revealed that the Access Denied was thrown while trying to retrieve the MA's using WMI. Now, this sounds really weird. As usual nothing has been changed in the farm (and this time I knew it for a fact) - but you should always check with the admins, which I did and no new policies or similar had been applied to any machines recently.

    On the machine that hosted the sync service/FIM Services I started a Management Console and added the WMI snap-in and took a look at the Security tab for the local machine. And this is what I found:

    Weird WMI permissons

    The security settings for the MicrosoftIdentityIntegrationServer looked not just right, it more or less looked liked the default WMI security settings. (And as you can see the Administrators group is there - so that's why you who still have the farm account in the administrators group, probably never see this error...). A quick comparison with the identical staging environment showed a whole lot more permissions.

    Correct WMI permissions

    To be exact the following permissions did not exist for the environment that showed the Access Denied:

    • WSS_ADMIN_WPG group - Execute Methods, Provider Write, Enable Account, Remote Enable
    • FIMSyncOperators group - Execute Methods, Provider Write, Enable Account, Remote Enable
    • FIMSyncBrowse group - Execute Methods, Provider Write, Enable Account, Remote Enable
    • FIMSyncPasswordSet group - Execute Methods, Provider Write, Enable Account, Remote Enable

    I fixed the permissions using the WMI management console, went back to Central Admin and started the synchronization manually and within a minute the synchronization was running beautifully!

    I do not know about any supportability on this one - and you should NOT be doing this unless you really have to. A safer way might be to unprovision and reprovision the User Profile Synchronization Service - this should correctly set this permissions.

    So, what caused this then? I've not yet found the actual source of the problem (which is frustrating to me at least), but I now how to fix it if it appears. Safe sources tell me that this might happen when you're doing a backup of the UPSS (and this is done in the correct way, which stops and starts the UPSS so no ongoing syncs are interfering with the backup). Question remains open...

    Happy Christmas everyone!

  • SharePoint Online and External Data using JSONP

    Tags: SharePoint 2010, Office 365

    It was some time since I did a real blog post and I have been fiddling with a specific topic, which I'm going to write about, for quite some time now. I've been working an Office 365 Intranet and been doing two conferences lately where I've demonstrated Office 365 and Windows Azure integration. One of the challenges (and boy, there are many) of Office 365 and SharePoint Online are access to External Data or services. In a few blog posts I will describe how you can work around these issues using some very simple techniques. All that is to it is that you have to "think outside the box" and not always go down the traditional SharePoint way of doing things.

    So let's get started! How do I in my SharePoint Online solution access remote/LOB data in a SQL Server database, web service or what not? The first and obvious candidate most think of is Business Connectivity Services - didn't they announce that in Anaheim!? Yea, it can be done and it works - but not as you (and I previously) expected. Steve Fox (MSFT) did show it at the SharePoint Conference 2011 and also wrote a blog post about it. The caveat is that you have to go through the Client Object Model to access the data in the external list, not using the Sandboxed server side API - that dog won't hunt.

    I'm going to do basically the same thing as Steve did but using a slightly different technique - which I find more easy and more straightforward, considering I'm not using the asynchronous Client Object Model but instead uses standard jQuery, jQuery templates JsRender, JSONP and WCF.

    This is how we'll build this little sample. First of all we have a database stored in SQL Azure. This database is surfaced through a WCF endpoint in a Windows Azure Web Role. This WCF service will be consumed by a JavaScript using jQuery and JSONP as transport in a Web Part (I'll use a Sandboxed Visual Web Part for this) and rendered using JsRender (not jQuery templates which I recently shown in a few sessions).

    The data flow

    The secret sauce - JSON-P

    First of all before digging into how this is actually implemented we need to sort out how we're actually going to transport data from the WCF endpoint to SharePoint Online.

    The best and easiest way is to use JSON notation to transport the data; jQuery has great support for that and it's very easy to program using JSON structures in JavaScript. The only problem is that SharePoint Online and the WCF service is going to be hosted on different domains - and therefore it will be a cross-domain scripting issue. To overcome this issue JSONP (JSON with Padding) can be used. JSONP is a very clever method. Instead of returning a string from the remote domain and then being parsed by the caller, a JavaScript method is returned, which returns the JSON structure when evaluated, and this returned response is dynamically appended to the calling document as a script tag. Smart huh? Only problem is that we need to fiddle somewhat with our WCF endpoints, and that's what we'll discuss next...

    Setting up the WCF endpoint

    In this sample we need a database with one or more tables and then generate an ADO.NET Entity Data Model from that. That data model is then exposed through a WCF Data Service. WCF Data Services uses the OData protocol and supports JSON format but not JSONP. Fortunately I was not the first one lacking this feature and there is a simple extension you can download to accomplish this. This extension is an attribute that you add to your Data Service class and makes the service support the $format=json and $callback=? query string parameters.

    Once you have downloaded and included the class into your project you decorate your DataService class with the JSONPSupportBehavior attribute and it should look something like this:

    [JSONPSupportBehavior()]
    [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class Users : DataService {
        public static void InitializeService(DataServiceConfiguration config) {
            config.SetEntitySetAccessRule("Users", EntitySetRights.AllRead);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }
    }

    Now we're all set to consume this from SharePoint Online.

    Consuming the JSONP enabled WCF endpoint from a Web Part

    Create a new Empty Sandboxed SharePoint project and then add a Sandboxed Visual Web Part (make sure that you have the Visual Studio SharePoint Powertools installed to get this Sandbox enabled Visual Web Part). We're only going to use HTML and JavaScript for this one, so you could do the same thing using a Content Editor Web Part, SharePoint Designer or whatever you prefer.

    Note: I'm using the new JsRender technique here, instead of the just recently abandoned jQuery Templates. The JsRender is not even in beta yet so the syntax might/will be changed over time. Read more about the change here.

    First of all in our user control we need to import the jQuery 1.7 file. Instead of uploading it to our SharePoint site we'll use a CDN for this (which will boost your overall performance and save you one file to maintain).

    <script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.min.js"></script>/<

    The JsRender.js file is not yet available on any CDN's so we have to add that JavaScript file into a new Empty Module SPI. You can deploy it to any folder or library, in this case I'm deploying it to the SiteAssets library of the site. Since we're talking about SharePoint Online here and we cannot guarantee that the file will be in a specific site this JavaScript file must be included dynamically or by using server side code to get the correct Web Url. We're doing the former one, and you will see the code in just a bit.

    The next thing is to define some markup where we would like to show our data from the WCF service. We'll define a table with an id equal to "list" and add a nice default row, which just says loading (makes it a bit more nice to the user).

    <h1>Users</h1>
    <table>
        <tbody id='list'>
            <tr><td><img src="/_layouts/images/loadingcirclests16.gif" />Loading data.../</td></tr>
        </tbody>
    </table>

    After that we need to define the template that JsRender will use when applying the data to the table. This is done in a script tag using the type="text/x-jquery-tmpl" like this:

    <script id="UsersTemplate" type="text/x-jquery-tmpl">
        <tr>             
            <td><b>{{=Name}}</b></td>              
            <td>{{=Company}}</td>         
        </tr>     
    </script>

    The final thing is to add the script that will load the data from the WCF service and then when it retrieves the response it will use the JsRender template to populate the table.

    <script type="text/javascript">
        SP.SOD.executeOrDelayUntilScriptLoaded(doTheRemoteStuff, 'SP.js');
        var rootWeb;
    
        function doTheRemoteStuff() {
            var clientContext = new SP.ClientContext();
            var siteColl = clientContext.get_site();
            rootWeb = siteColl.get_rootWeb();
            clientContext.load(rootWeb);
            clientContext.executeQueryAsync(succeeded, failed);
        }
    
        function succeeded() {
            var elm = document.createElement('script');
            elm.type = 'text/javascript';
            elm.src = rootWeb.get_serverRelativeUrl() + '/SiteAssets/JsRender.js';
            document.getElementsByTagName('head')[0].appendChild(elm);
    
            $.getJSON("http://mycloudapp.cloudapp.net/Users.svc/Users?$filter=email ne ''&$format=json&$callback=?",
                function (data) {
                    $("#list").empty();
                    $("#list").html($("#UsersTemplate").render(data.d));
                });    
        }
        function failed() {
            SP.UI.Notify.addNotification('Something failed...');
        }
    </script>

    The script starts with using the Script-On-Demand features of SharePoint 2010 to delay execute the doTheRemoteStuff() function. Once the SP.js file is loaded the function is executed. The function will use Client Object Model to retrieve the Url to the root web, to ensure that this Web Part will work on sub webs as well. This is needed so that we dynamically can add the JsRender.js file that was added to the SiteAssets library in the root web.

    Once we have the root web loaded the succeded() method is going to execute. This is where we first dynamically insert the JsRender.js file into the head element, referencing our own JsRender.js file. Once that is done we will use the jQuery getJSON method to get all users from the Data Service (in this case all users that has an e-mail address). To make the response a JSONP response it is important to add $format=json&callback=? to the query string in the getJSON method.

    When the response is returned the table is cleared and the rendered data is added as inner HTML of the table. The jQuery extension method $(template).render(data) is the JsRender method that generates the HTML from the template and the JSON strucutre.

    Once this project is deployed and activated in the Sandbox and the Web Part is added to a page it will first show you the loading message and then after just a second a nicely table with the data from your SQL Azure backend.

    A SharePoint Online Web Part displaying data from a SQL Server Azure database

    Summary

    This post intends to demonstrate how to solve a very common problem in SharePoint Online - fetching data from LOB systems. I used SQL Azure and a Windows Azure Web Role hosted WCF service, but it can be any kind of JSONP supported WCF service. The holy grail in this case is to JSONP enable the WCF service.

    Watch this space for a continuation of similar posts...

  • Recap of the European SharePoint Conference 2011

    Tags: Windows 7, SharePoint 2010, Presentations, AppFabric

    European SharePoint Conference 2011Back home after a few days in Berlin for the European SharePoint Conference 2011. It was a great conference with good speakers and really nice attendees. It was three days full of sessions, expert panels, shoot-outs and SharePoint fun! Thanks to everyone who was there (especially those who came to my sessions :-) and the team behind the conference! And as always it great to meet up with the SharePoint MVP's, MCM's and now even MCA's!

    During the attendee dinner the conference team announced the dates for the next European SharePoint Conference, which is set to the first week in December 2012. This one will not be in Berlin, but more likely in Barcelona, Paris or Copenhagen (Barcelona is the one everyone cheered for, so my guess is that the other two are out of question :-)

    For this conference I did two development presentations. I've done similar sessions before but this time I changed them into be even more based on best practices and experiences from the field, since we're quite a bit into the product cycle. I got good feedback on it and in some of the sessions I attended I noticed the same approach from the speakers. For you who either didn't attend my sessions or didn't have time to write down all the code samples in your notebooks - you can find the presentations on the conference web site and you can find the code samples here:

    I'm planning (note planning - no promises) on doing a couple of follow up posts on specifics in the demos.

    Now it's only two more conferences this year; Singapore and Stockholm...

  • SharePoint Conference 2011 wrap-up

    Tags: SharePoint, SharePoint 2010

    I've now been home for about 48 hours since visiting Anaheim, California, for this years edition of the Microsoft SharePoint Conference. It has been a great week in California with colleagues, friends, clients and new acquaintances.

    Superman at Six FlagsThis year, eight people from my company, Connecta, travelled over for the conference. We all had a blast with some spare time before and after the conference, which included a visit to Six Flags - Magic Mountain and a drive along the Pacific coast. We also met up with a few old friends and colleagues and had a good time with our clients, who also attended the conference.

    Even though nothing new actually was shared during the conference (saving all the fireworks for next year in Las Vegas) it was a really great conference. I focused on the sessions where I knew the speakers would put on a great show, which I think was a clever choice - you can never experience that from the recordings or by downloading the decks. The keynote was pretty dull and just a big marketing show. The only highlights was the big fail-over demo and the MCA announcement. The MCA - Microsoft Certified Architect - is now available for SharePoint 2010 as well, read more on the Masters blog. Congrats to Spence and Kimmo - our two very first MCA's!

    I got a lot of questions regarding the MCA program and two essential things were not mentioned in the keynote. First; MCM is a pre-requisite for the MCA and secondly; you need to be MCM on the same version as you're trying for MCA on.

    Meet the Masters!?On Wednesday I sat in the Perficient booth for the Meet the Masters panel together with three MCM colleagues. I had a great time talking about my MCM experience and asking questions from the audience. It's great to see the that the recognition of the MCM program is increasing.

    SharePoint conferences are more than just attending sessions! Compared to a lot of other technical conferences the SharePoint conferences is very much about the social activities. There are multiple vendor activities and community activities going on 24/7, ranging from SharePints to early morning runs. The Monday night I had four parallel parties going on! These activities are in my opinion one of the most important aspects of the SharePoint conferences. You meet your old friends and make new ones and broaden your network. You'll learn who's an expert in what which makes it more easier for you to get help or reach out when in doubt. Know what you know and know what you don't know - and never confuse those two! 

    Now I'm looking forward to next week with a conference in Berlin, then Singapore a couple of weeks later...and of course - Las Vegas next year!

  • Changes in the SharePoint 2010 Cumulative Update packaging since August 2011

    Tags: SharePoint 2010

    A couple of days ago the SharePoint 2010 Cumulative Update for August 2011 was released. Always a good time to see some things fixed and some things break. Installing a Cumulative Update is always a risky business, and you should only install them if you any experience problems that the CU resolves and only when you thoroughly tested it.

    One CU to rule them all!

    Without going into details about the content and fixes in the August 2011 CU there is one other thing that is of real interest - and that is how MIcrosoft has changed the packaging process for the Cumulative Updates. Since the release of SharePoint 2010 there has been talk and discussions about über-packages. That is Server Cumulative Packages that contains both the Server hotfixes as well as the Foundation hotfixes, which makes the update process a bit easier and faster - you only need to install one package. Up until now there has been mixed messages on the über-packages and caused some confusion. The recommendation has been that you need to install both SPF and SPS CU's on a SPS installation and all three if you're using Project Server.

    Since yesterday (that's when I noticed it at least) the SharePoint Updates page on MSDN has been updated with new information regarding this packaging with this:

    The packaging of cumulative updates changed as of August 31, 2011. [...] As a result of the new packaging, it is no longer necessary to install the SharePoint Foundation cumulative update and then install the SharePoint Server cumulative update.

    It looks like we have a new guidance in town!This has been "promised" before and I hope that it will work as planned this time, only time will tell. For more history and information read Spencer Harbars post on the SP1 and June CU discussion.

    What this essentially comes down to is that you only need to download one of these patches (links to August 2011 CU within parenthesis) from now on...

    • SharePoint Foundation 2010, contains SPF CU (KB253050)
    • SharePoint Server 2010, contains SPF + SPS CU (KB253048)
    • SharePoint Server 2010 with Project Server 2010, contains SPF + SPS + Project Server CU (KB253049)

    This will save you a couple of minutes/hours downloading and you'll save a few minutes installing multiple CU's on each server.

    Note: The correct version of this CU should be 14.0.6109.5002, if you were really quick you might have downloaded the 14.0.6109.5000 build.

    But...there's always a but. Please, please, please test all CU's, SP's, patches, hotfixes, shoes and whatever very thoroughly!

  • Conference and presentation season - fall 2011

    Tags: SharePoint 2010, Presentations

    This fall is going to be pretty busy in terms of conferences and presentations and I'll have my fair share. Here's what I've planned for this fall, so far.

    Webinar: No Farm Solution in sight!

    On Tuesday the 6th of September I will do a webinar discussing SharePoint Online and Office 365 and how you can build solutions using SharePoint Online, Silverlight, Windows Azure and more without creating any farm solutions:

    When and where: 6th of September at 11:00 CET. The interwebz

    Register online at http://www.sharepointeurope.com/upcoming-webinars/webinar-week-no-farm-solutions-in-sight.aspx

    SharePoint in the cloud!? Does it work?

    This is a breakfast seminar that my company Connecta is arranging with Cornerstone where I will present Office 365 and SharePoint Online specifically. I will show you how SharePoint Online works and what you need to do to get it to work, and I will also share our experiences moving from an on-premise solution with SharePoint and Exchange to the Office 365 platform.

    When and where: 16th of September at 8:00 or 13:00. Stockholm at the Connecta office

    More information at http://cornerstone.se/sv/Event/Frukostseminarium-SharePoint-i-molnet-Funkar-det/

    European SharePoint Conference, Berlin

    European SharePoint ConferenceFor the European SharePoint Conference I will have two sessions, which I already written about.

    When and where: 17th - 20th October. Berlin, Germany

    More information: http://www.sharepointeurope.com/

    SharePoint Conference Southeast Asia, Singapore

    SharePoint Conference Southeast AsiaFor the second year I will go down to the beautiful Singapore for the SharePoint Conference in Southeast Asia. This year I will also have two sessions.

    • Mastering customizations of the SharePoint 2010 Ribbon Menu
    • Enhancing Office 365/SharePoint Online using Windows Azure

    I'm sure that the conference will be as great as last year!

    When and where: 8-9 November. Singapore.

    More information here: http://www.sharepointconference.asia/

    SharePoint and Exchange Forum 2011, Stockholm

    SEF 2011The SharePoint and Exchange Forum is the SharePoint and Exchange conference in Scandinavia and of course if you're in the vicinity you should head on over to Stockholm. This year Göran Husman and the crew has managed to get a really good line of presenters - it will be a blast! I will present one session at this conference, and it will not be a development topic, but instead a session about Service Application Federation - the good, the bad and the ugly!

    When and where: 14-15 November. Stockholm, Sweden

    More information here: http://www.seforum.se/

    I hope to see you on the road somewhere!

  • Yet another object to dispose correctly in SharePoint 2010 - SPUserSolution

    Tags: SharePoint 2010

    If you've been in the SharePoint business for a while (at least a couple of days) you should be aware of the SharePoint objects that needs to be properly disposed; SPSite and SPWeb in particular. Objects that need disposal inherits from the IDisposable interface and requires that you call the Dispose() method when you're done with the object  - this is to ensure that the object frees up resources that the .NET managed garbage collector cannot free up automatically. This includes objects such as non-managed SQL connections, resource handles, file handles etc. Disposing objects is nothing unique for SharePoint - all (real) .NET developers know how to dispose of a SQL connection. You can read more about the best practices around disposing SharePoint objects in the MSDN Disposing Objects article. Not doing this properly will eventually lead to application crashes, high memory usage and/or bad performance.

    The SPUserSolution object requires disposal

    If you are working with sandboxed or user solutions in code you've probably used the SPUserSolution object. This is another of these objects that needs your disposal-attention. A solution package (farm or user code) is essentially a cabinet file (compressed file) containing all the solution artifacts and assemblies. When activating a user code solution programmatically in the solution gallery you will get this SPUserSolution object which internally will contain a number of stream objects (also inheriting from IDisposable) and a non-managed file handle. These object must be disposed manually to avoid any resource or memory leaks. Here is a proper way to add and activate a user code solution

    byte[] bytes = ...;// grab the solution gallerySPDocumentLibrary solutions = (SPDocumentLibrary)newSite.GetCatalog(SPListTemplateType.SolutionCatalog);// add the solution to the gallerySPFile solutionFile = solutions.RootFolder.Files.Add("mysolution.wsp", bytes);// activate Solutionusing (SPUserSolution solution = newSite.Solutions.Add(solutionFile.Item.ID)) {    // do your thing...}

    Summary

    This was just a sample and a reminder that you need to be aware of what's happening when working with some of the SharePoint objects - make sure that you do your "Disposal dance" the correct way. The list goes long on what objects need to be disposed correctly - just check your objects if they inherit from IDisposable using Visual Studio or Reflector. Not all objects do any specific disposing though and some can be ignored - but better be safe than sorry.

    Tip: products such as CodeRush from DevExpress has some great built-in tools to directly identify objects inheriting from IDisposable and helps you make sure that they are properly disposed.

  • I'm on the SharePoint Pod Show talking about Web Parts

    Tags: Personal, Web Parts, SharePoint 2010

    The 65th SharePoint Pod Show is out featuring...tada...me :-)

    The SharePoint Pod ShowThe SharePoint Pod Show is THE podcast about SharePoint and is done by Rob Foster, Nick Swan and Brett Lonsdale and has featured a lot of great SharePointers from all around the world throughout the years. If you haven't already listened to the podcasts, then you got 65 episodes to catch up on! There are some epic ones, such as my favorite one #50 - which is about performance tuning. And make sure that you subscribe - you don't want to miss their SPC11 Road-trip...

    This episode was recorded at the MVP Summit earlier this year in Redmond between two sessions. It was my first time meeting most of the MVP's in real life and Rob was the one interviewing me. He's one heck of an interviewer asking questions like an ice-hockey radio commentator in some weird southern accent... It was great fun and we discussed SharePoint development and Web Parts development in particular. We talked through how to get started with SharePoint development, how to build Web Parts and why I wrote my book (SharePoint 2010 Web Parts in Action).

    Until next time.

  • Improve performance of your SharePoint 2010 applications using Windows Server AppFabric caching

    Tags: SharePoint 2010, AppFabric

    Besides SharePoint my very dear topics is performance optimizations and new technologies, so here's a post mixing all these together.

    Background

    Caching is one way to improve the performance of any application, there are several ways to do it in-memory, disk etc etc. SharePoint 2010 has a set of caching capabilities, most of them are in-memory caches and some involve disk or even SQL based. One problem with (especially) in-memory caching is that if you have a farm different servers may display different results, which is due to the fact that the different servers cached information at different times. Another problem with in-memory caching is that it's per process, that is that you have different caches for different web applications and application pools.

    Windows Server AppFabric is an extension to Windows Server. There's one cloud version of AppFabric in Windows Azure but there's also an on-premise installation of AppFabric that contains hosting and caching capabilities. AppFabric is a middle-tier service platform (the real middle-tier, not the other middle-tier :-) and can be used in all kinds of scenarios. The caching features of AppFabric is based on the Velocity project, which was one of my favorite acts for the PDC08 conference. It contains an easy to set up and configure distributed caching framework that can use SQL Server or disk as storage. In this post I will show you how to leverage the caching features of the on-premise version of AppFabric.

    Using a distributed cache such as AppFabric can solve many problems. I've already mentioned a few such as the problems with in-memory caching. Other interesting things is that you can easily set up cross farm caching or even cross domain caching. You can have the caching on separate servers in the application tier. You can share the cache between web applications and service applications. The cache isn't tied to the application pool so any recycles of that will not clear the cache and so on...

    Setting up and configuring AppFabric v1.1 CTP

    AppFabric v1.1 CTP is really easy to setup. You install the binaries (download 1.0 via Web Platform installer or 1.1 directly here) on the first machine to host the distributed cache and configure the cache. Then you add new servers to that cache cluster. Very much like you do when setting up a SharePoint farm. Follow these instructions on MSDN, you can't fail (which you can't say with SharePoint).

    Installing AppFabric

    Configuration is used either using the configuration application or using PowerShell (what else did you expect). In this case I configured it to use SQL Server as backend. Using the disk based would ideally be used in cross farm/domain scenarios (think about that - having data up to date cross farms, that's cool!). Once AppFabric is installed you need to start the AppFabric caching  using the following PowerShell commands. First use Use-CacheCluster to set the context and then just Start-CacheCluster to start the cache. There is one final configuration that is needed and that is to allow the application pool account to access the cache. This is done using the Grant-CacheAllowedClientAccount cmdlet. If you forget to set this you will see an ERRCA0017 error. AppFabric contains tons of configuration options. You could setup different clusters, named caches etc etc.

    Using the cache in a Web Part

    Now on to the SharePoint bits. In this scenario I'll build a Web Part that fetches quotes from Yahoo, that is doing an HTTP request to get a quote. This is a common scenario where you would build some kind of cache to avoid HTTP latencies. Another problem with HTTP requests is that they might time out or take a long time. You need to call it at least once so the poor bastard that's loading your page first might suffer from it. In this case we could actually create a timer job that makes the requests and put the data in the AppFabric cache before it's requested. But for this simple demo let's settle with a Web Part.

    Preparing your solution

    Before building the actual Web Part we need to set up the project to use the AppFabric cache. First two references must be added; Microsoft.ApplicationServer.Caching.Core and Microsoft.ApplicationServer.Caching.Client. They are found in the c:\Windows\System32\AppFabric\ folder (even though some documentation says otherwise). I could not directly add them as reference in Visual Studio, it could not find the directory, so I copied the file from that folder to a custom folder first.

    After adding the references we need to set up the configuration of our custom cache. Normally you do this using the application configuration file, but in SharePoint scenarios this doesn't work that well, so I'll do it all in code. In this sample I use hardcoded values for servers and ports - in a real world scenario you should of course make this configurable using for instance the P&P SharePoint Guidance Hierarchical Object Store. To access the cache we need to create a cache factory and retrieve our cache from that. Creating the cache factory object is an expensive operation so I'll implement this in a singleton thread-safe object to avoid creating the factory that many times. It looks as follows:

    sealed class CacheUtility {
        private static DataCacheFactory _factory;
        private static DataCache _cache;
        private static readonly object _lock = new object();
    
        CacheUtility() { }
    
        public static DataCache CurrentCache     {
            get {
                using (SPMonitoredScope scope = new SPMonitoredScope("DataCache.CurrentCache")) {
                    lock (_lock) {
                        if (_cache == null) {
                            List<DataCacheServerEndpoint> servers =                             new List<DataCacheServerEndpoint>();
                            servers.Add(new DataCacheServerEndpoint("SP2010", 22233));
                            DataCacheFactoryConfiguration config =                             new DataCacheFactoryConfiguration() {
                                Servers = servers
                            };
                            _factory = new DataCacheFactory(config);
                            _cache = _factory.GetDefaultCache();
                        }
                        return _cache;
                    }
                }
            }
        }
    }

    As you can see in this class I have the DataCacheFactory object and the actual cache object (DataCache) as static variables. They are only created on the first request to the CurrentCache property. The DataCacheFactory object is instantiated with a configuration, in this case I'll just add one AppFabric cache server using the server name and the cache port.

    Then let's add the Web Part to the project. In the Web Part class implement the function to get the stock quotes as follows:

    public class Quote {
        public string Name;
        public double LastTrade;
        public DateTime DateTime = DateTime.Now;
    }
    
    public Quote GetQuote(string ticker) {
        using (SPMonitoredScope scope = new SPMonitoredScope("GetQuote")) {
            using (WebClient client = new WebClient()) {
                string tmp = client.DownloadString(                String.Format("http://finance.yahoo.com/d/quotes.csv?s={0}&f=nl1", ticker));
                string[] arr = tmp.Split(new char[] { ',' });
                if (arr.Length == 2) {
                    return new Quote() {
                        Name = arr[0].Trim(new char[] { '"' }),
                        LastTrade = double.Parse(arr[1])
                    };
                }
            }
            return new Quote() {
                Name = "Not found"
            };
        }
    }

    It's a simple method, GetQuote(), that retrieves the stock quote using the Yahoo Finance API. If the quote is found it returns a Quote object with correct values and if not an "empty" Quote object.

    Also add a property to the Web Part so that we can turn on and off the caching:

    [Personalizable(PersonalizationScope.Shared)]
    [WebBrowsable]
    [WebDisplayName("Use Cache")]
    public bool UseCache { get; set; }

    Now it's time to implement the actual Web Part, and as always it's done in the CreateChildControls, like this:

    protected override void CreateChildControls() {
        using (SPMonitoredScope scope = new SPMonitoredScope("CachedWebPart.CreateChildControls")) {
            Quote quote = null;
            string ticker = "MSFT";
            if (UseCache) {
                DataCacheItem cacheItem = CacheUtility.CurrentCache.GetCacheItem("quote" + ticker);
                if (cacheItem != null) {
                    quote = (Quote)cacheItem.Value;
                }
            }
            if (quote == null) {
                quote = GetQuote(ticker);
                if (UseCache) {
                    CacheUtility.CurrentCache.Add("quote" + ticker, quote, new TimeSpan(0, 1, 0));
                }
            }
            this.Controls.Add(new LiteralControl(
                String.Format("Last trade for {0} is {1}, retrieved at {2}", 
                    quote.Name, quote.LastTrade, quote.DateTime)));
        }
    }

    This method is also pretty straight forward. It checks if the cache is enabled and if it is it tries to retrieve the quote from the cache using the GetCacheItem method. If it's not found it uses the GetQuote method to retrieve the quote and if the cache is enabled it stores the quote in the cache. Finally it just prints out the quote value. That's it!

    Test and evaluate

    So let's take a look at this Web Part now using the Developer Dashboard (notice the SPMonitoredScopes I added to the code). Here's how it looks without the cache enabled. The call to the Yahoo Finance API takes about half a second - a real performance killer.

    No caching

    Once we turn on the caching, the first call to the CacheUtility class will initialize the cache and for subsequent calls use that cached factory and cache. Notice how the first hit which creates the cache actually takes some time and in this case the HTTP request takes a really long time!

    Caching started

    Then once the cache is up and running, retrieving the quote takes almost no time.

    Caching in full effect

    Improve performance a little bit more...

    But it still takes about 10ms! This 10ms comes from that this is not an in-memory cache, it is actually stored in SQL Server. But hey, it's better than a couple of seconds. But I want to save an extra couple of cycles here. Ok, let's enable the client cache! Add the following row when configuring the cache factory and you will also have an in-memory cache that has a maximum number of object, a timeout and an invalidation policy.

    config.LocalCacheProperties = 
        new DataCacheLocalCacheProperties(
            100, 
            new TimeSpan(0, 3, 0), 
            DataCacheLocalCacheInvalidationPolicy.NotificationBased);

    In this case I set the invalidation policy to use notifications. To get this up and running you need to shut down the cache cluster and configure notifications for the cluster as follows:

    Stop-CacheCluster 
    Set-CacheConfig -CacheName "default" -NotificationsEnabled $true 
    Start-CacheCluster

    And now retry the Web Part and we'll see that this is more efficient:

    Client cache enabled

    Monitoring

    The AppFabric cache also contains a lot of features for monitoring and logging. The simplest command is the Get-CacheStatistics that show you stats of the cache:

    Cache stats

    Summary

    Next time you are thinking about caching in SharePoint (or any other .NET application for that matter) consider using AppFabric caching. It's a great and versatile middle-tier caching framework with near endless configuration possibilities. I know that this simple yet powerful framework can make a big difference in any of your projects. And why invent some own caching framework when we have something beautiful as this!

  • Stale Managed Metadata Databases in SharePoint 2010

    Tags: SharePoint 2010

    This is a short story about how you can get and resolve stale Managed Metadata Service (MMS) databases in SharePoint 2010. I've been working with Managed Metadata quite much and done some backup/restore juggling from production to test and to dev environments. Which by the way works really smooth. I've also recreated the MMS databases a couple of times.  After applying Service Pack and the re-released June 2011 CU I went into Central Administration to take a look at the databases and their upgrade status. This is what I found: four MMS databases, of which two didn't upgrade, and I only have two MMS service applications in this particular environment.

    Database status

    As you can see two of the databases reports "Database is in compatibility range and upgrade is recommended". There's no link to click to upgrade and there's no PowerShell command either to update them. These two databases were not connected to any MMS service application so it's no big deal, but who wants these kind of "warnings" in their CA.

    To create these stale MMS databases is an easy task; just go to Properties of the MMS SA and change the name of the database. This will provision a new and empty database for you, leaving the old database still registered in the configuration database of SharePoint. I don't know if this should be considered a bug or not, of course the database should not be deleted automatically, but should they remain registered as databases in the configuration database?

    So, in order to remove these databases, the easiest way is to fire up your favorite command line tool - PowerShell, and use a few lines of commands. This is how it's done:

    First of all the Get-SPDatabase command will return all registered in your farm.

    Get-SPDatabase

    By using the Id of the database it's easy to get one explicit database into a PowerShell variable like this:

    $db = Get-SPDatabase cb825c9d-8494-46fc-9ffc-3f81cffdfafc

    Now that we have one of our stale MMS databases we can use the Delete() method of the Database object to delete the actual reference in the configuration database, like this:

    $db.Delete()

    This will only delete the reference (the persisted object) and not the database. If you would like to remove the database as well, you can use the Unprovision() method prior to the deletion:

    $db.Unprovision()

    If you do just an Unprovision of the database, and don't delete the database, the database status in the upgrade status page will say "Not responding":

    Not Responding

    That was it, a quick and short post about stale Managed Metadata Service databases - how they become stale and how you remove them.

  • Deploying Web Parts Farm-wide using the WebPartAdderExtension element in SharePoint 2010

    Tags: Web Parts, SharePoint 2010

    Here goes another post using the WebPartAdderExtension Element. I previously wrote an introduction to custom Web Part Gallery sources and a second one on how to enhance the end-user experience when adding new Web Parts. Now I'm going to show you another trick that this technique can be used for.

    Introduction

    Deploying Web Parts are normally done by using the Module element in the Elements manifest and using that element uploading/deploying Web Part Controls Description files (.webpart or .dwp files) into the Web Part catalog. These Element manifests for Web Parts must be scoped to the Site Collection level, since it is there where the Web Part catalog lives (~/site/_catalogs/wp). So if you want do deploy a solution containing a set of Web Parts you need to activate that Feature on each and every Site Collection. You can do it in a number of ways such as Feature Stapling, code, scripting etc. Could be quite tedious work if you have a large farm with many site collections and web applications. Also when retracting solutions with Features that uses Modules we manually have to clean up the files provisioned.

    Enter WebPartAdderExtension!

    So once again our new acquaintance the WebPartAdderExtension can help us in the scenario where we want to deploy Web Parts in a more efficient manner. In the two previous posts I built both examples using Site Collection scoped features - that's the way we normally think when programming for Web Parts. But the good news is that the WebPartAdderExtension element that is used to deploy the custom Gallery Source can actually be scoped to the following scopes:

    • Site - a Site Collection
    • WebApplication - a Web Application
    • Farm - the whole Farm

    Did you see that! Using this simple technique you can easily deploy and maintain Web Parts for a specific Web Application or the whole Farm if you like!

    The WebPartAdderExtension element

    Just follow the previous two guides and change the Scope of your Feature and you're ready to go.

    A word of caution

    It's unsafe  - watch out for zombies!There is one caveat with this though. If you set your Feature to Farm and deploy the solution, but only deploy/install it to one ore more Web Applications. The Safe Controls will only be installed on those specific Web Applications - not on all Web Applications in the farm. But the custom Gallery Source is still visible in the whole farm. This results in that you will get Safe Control errors as soon as you add the Web Part to a page in an Web Application where the Solution is not deployed.

    Summary

    This was the third really cool thing about the Web Part Adder and it's friends. It's never been this easy deploying Web Parts in SharePoint 2010. There are still a few more parts to be disclosed about this little nugget!

  • Improve the experience using Modal Dialogs when adding Web Parts in SharePoint 2010

    Tags: Web Parts, SharePoint 2010

    This is a follow-up post on yesterdays introduction to the WebPartAdder (which lately has been one of my favorite features of SharePoint 2010). In that post I mentioned that you could invoke a JavaScript function when a Web Part is added using a custom Web Part Gallery source.

    The Silverlight Web Part

    The Silverlight Web PartIf you have been working with SharePoint as an end-user you've probably seen the nice modal dialog that pops up when you're adding a Silverlight Web Part to a page, see the image to the right. It allows you to very easily configure the Web Part with the appropriate XAP file without editing the Web Part properties. If more Web Parts were like this it would be a whole lot easier working with Web Parts.

    The good news is that you can do this for your Web Parts - using a custom Gallery Source, just as I showed yesterday. And I'll show you how.

    Create a custom Web Part with a default Modal Dialog property form

    In this sample we're basically building out the same structure as I showed yesterday. I'll show you a bit different approach though - which is a bit more compact. And we'll need to throw in some custom JavaScript and an Application Page as well.

    Create a new Visual Studio project

    The SPIFirst of all create a new empty SharePoint project in Visual Studio. Then add an Empty Element SPI, we'll skip adding a Web Part like yesterdays post showed. In this Empty Element SPI add three files; one for the Web Part, one for the Gallery Source and one for the Gallery Item.

    Make sure to change the Scope of the automatically added Feature to Site Collection, instead of the default Web value!

    Implement the Web Part

    We're completely manually creating the Web Part in this case (my favorite way to do it :-). Add a simple string property (in this case called Data), a default constructor, another constructor that takes the property value as parameter and finally make the UI in the CreateChildControls() method. In order to get it to work you need to manually add a reference to System.Web. It should look something like this:

    public class ScriptedAdderWebPart : WebPart {
    
        public ScriptedAdderWebPart() {
        }
    
        public ScriptedAdderWebPart(string data) {
            Data = data;
        }
    
        protected override void CreateChildControls() {
            this.Controls.Add(new LiteralControl(
                String.Format("You entered: {0}", this.Data)
                ));
            base.CreateChildControls();
        }
    
        [WebBrowsable]
        [Personalizable(PersonalizationScope.Shared)]
        public string Data { get; set; }
    }

    You also need to add the SafeControl entry for this Web Part on the SPI. Right-click the SPI and choose Properties. Click the ellipsis button on the Safe Controls row and click Add to add the Safe Control. Click OK when you're done.

    Create the custom Gallery Source

    The custom Gallery Source is very simple, in this case we only want it to return a single custom Gallery Item. So the implementation should look as follows:

    [Guid("f62379dd-8ec0-402e-8034-7a0bcaaf7a8a")]
    public class ScriptedAdderWebPartGallerySource : WebPartGallerySourceBase {
        public ScriptedAdderWebPartGallerySource(Page page)
            : base(page) {
        }
    
        protected override WebPartGalleryItemBase[] GetItemsCore() {
            return new WebPartGalleryItemBase[] {
                new ScriptedAdderWebPartGalleryItem(this, base.Page)
            };
        }
    }

    Create the custom Gallery Item

    It's in the custom Gallery the magic happens, it's where we tell the WebPartAdder to invoke a JavaScript before adding the Web Part to the page. The implementation is very similar to the one in yesterdays post, and I'll only show you the differences. First of all we need to override the OnClientAdd property, it is a string and should contain the name of the JavaScript method that should be invoked.

    public override string OnClientAdd {
        get {
            return "adderWithScriptDlg";
        }
    }

    Next we need to modify the Instantiate() method. We'll create our custom Web Part using the constructor that takes the data as argument and pass in the value of the WebPartContent property. The WebPartContent property is a property of the Gallery Item that is set during the post back after your JavaScript has been invoked.

    public override System.Web.UI.WebControls.WebParts.WebPart Instantiate() {
        return new ScriptedAdderWebPart(this.WebPartContent);
    }

    This property could basically contain anything, as long as it can be represented as a string. You can create JSON structures for instance if you need to pass more advanced data structures to your Web Part if you perhaps like to set several properties.

    Create the custom JavaScript

    Now it's time to implement the JavaScript that is invoked when the end-user clicks the Add button to add a Web Part. Add the "Layouts" mapped folder to your project and add a new JavaScript file. In this file create a new function with the name you entered in the OnClientAdd property. It is important that it takes three arguments; item, zoneNum and zoneIndex. In this case we would like to open a Modal Dialog and retrieve the Web Part property value, so we implement it as follows:

    function adderWithScriptDlg(item, zoneNum, zoneIndex) {
        var options = {
            url: SP.Utilities.Utility.getLayoutsPageUrl('Wictor.AdderWithScript/AddPage.aspx'),
            title: "Enter the data for the Web Part",
            width: 400,
            height: 300,
            dialogReturnValueCallback: 
                Function.createDelegate(null, function (dialogResult, returnValue) {
                if (dialogResult == 1) {
                    var wpVal = WPAdder._getHiddenField('wpVal');
                    if (wpVal) {
                        wpVal.value = returnValue;
                    }
                    WPAdder.addItemToPage(item, zoneNum, zoneIndex);
                }
            })
        }
        SP.UI.ModalDialog.showModalDialog(options);
    }

    First of all we create the options variable that contains all the options for the Modal Dialog and then show the dialog using the showModalDialog() method. The properties for the modal dialog is configured so that It's pointing to a custom Application Page (we'll create that one in a moment). Then we set some other properties and finally the callback function of the dialog. In the callback we do something interesting - we retrieve a hidden field called wpVal and set the value of that field to the value returned from the modal dialog. It is this property that then is posted back to the WebPartAdder and inserted into the WebPartContent property. And then to actually add the Web Part we need to call back into the WebPartAdder JavaScript API (WPAdder) using the addItemToPage() method.

    Create the custom Application Page

    Now it's time to create the custom Application Page. This is a standard procedure, so I'm not showing you all the details. But basically you add a new Application Page to the mapped Layouts folder and then create a UI. In this case a textbox and a button is sufficient. The server side code of the Application Page should handle the click of the button and return (using JavaScript) the value in the textbox to the callback method. This could be implemented as follows:

    protected void btn_Click(object sender, EventArgs e) {
        Response.Clear();
        Response.Write(
            String.Format(
            "<script type='text/javascript'>window.frameElement.commonModalDialogClose(1,'{0}');</script>",
            data.Text
            ));
        Response.End();
    }

    It's just closing the Dialog with an OK value (1) and then passing the value of the textbox as second argument.

    And finally some CAML!

    What would SharePoint development be without some CAML. We need to add our custom Gallery Source as a Web Part Adder extension and we need to make sure the JavaScript is loaded (for the sake of simplicity I add it to all pages). Modify the elements manifest of your SPI as below:

    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
        <WebPartAdderExtension
            Assembly="$SharePoint.Project.AssemblyFullName$"
            Class="$SharePoint.Type.f62379dd-8ec0-402e-8034-7a0bcaaf7a8a.FullName$"/>
        
        <CustomAction
            Location="ScriptLink"
            ScriptSrc="~site/_layouts/Wictor.AdderWithScript/AdderWithScript.js" />
    
    Elements>
    First I use the WebPartAdderExtension to register the custom Gallery Source and then a CustomAction with Location set to ScriptLink to load the JavaScript.

    Try it out!

    Time to take this baby out for a spin. Deploy the solution and edit a page. When you choose to add a Web Part you should see something that looks like this, depending on what categories etc you set for your custom Gallery Item:

    The Web Part Gallery

    Now when you click Add you should, instead of seeing the Web Part on the page, see a Modal Dialog popping up.

    The custom Modal Dialog

    If you close the dialog without clicking the button your Web Part is not added, but if you write something in the text box and click the button the Web Part should be added to the page with the custom property set as specified in the dialog.

    The awesome result!

    Summary

    Once again the WebPartAdder has proven to be very useful for end-user scenarios where you want to make it easier for users to add and configure Web Parts. Not only can we dynamically populate the Web Part Gallery, we can also force users to specify configuration/information for the Web Parts. Happy devving!

  • Dynamically populate the Web Part Gallery using the WebPartAdder in SharePoint 2010

    Tags: Web Parts, SharePoint 2010

    Writing this post has been on my agenda for some time, initially I intended to put it into my SharePoint 2010 Web Parts in Action book, but there was not enough time, you know how it is! This is an excellent new feature to SharePoint 2010 which allows you to dynamically populate the Web Part Gallery with Categories and Web Parts. So here we go.

    Introduction to the Web Part Adder and the Web Part Gallery

    Think of the List and Libraries category in the Web Part Gallery - it is dynamically populated with the lists and libraries available in the current web. This is all done using the WebPartAdder class which loads all the Web Parts available in the gallery from a number of different sources, see figure below. These source include the List and Libraries category, the local Web Part catalog, files in the wpcatalog, closed and uploaded Web Parts etc.

    WebPartAdder and sources

    The really cool thing with this is that you can actually create custom Gallery Sources! This is a new feature of SharePoint 2010 and is really simple to do. I'll show you how!

    Create a custom Web Part Gallery Source

    I've not yet seen any guide on how to create a custom Web Part Gallery Source, even though the classes and methods in MSDN are documented (the MSFT minimalistic way). To get this all working you need to use a new Feature element available in the Element manifest called WebPartAdderExtension. This element is referenced only once in MSDN, where it only says that the element is not documented!

    In this walkthrough I will use a very simple custom gallery source. It will dynamically populate the gallery with Product Web Parts that displays information about products. The product information is stored within a SharePoint list, in the local site, called Products.

    The product list

    From this list we'll create a new category in the gallery that lists all products, and when a product is added to the page it should add a new Web Part displaying that particular product information.

    Create a new SharePoint project

    imageStart by creating a new Empty SharePoint project. Make it a farm solution. Then add a new Web Part SPI - this will also add a Site Collection scoped feature to your project. In the Web Part SPI remove the .webpart file. We do not want to add this Web Part to the gallery - we only need the Web Part class. You can of course make the Web Part without an SPI if you want to.

    Next step is to build the Web Part user interface - and here you can get fancy if you like. If you feel for a copy and paste excursion you can copy and paste the code below.

    public class ProductWebPart : WebPart {
        public ProductWebPart() {
        }
        public ProductWebPart(SPListItem item) {
            ProductId = item.ID;
        }
        protected override void CreateChildControls() {
            SPList productList = SPContext.Current.Web.Lists.TryGetList("Products");
            if (productList != null) {
                try {                    
                    SPListItem item = productList.GetItemById(ProductId);
                    this.Title = "Product information:" + item.Title;
                    this.Controls.Add(new LiteralControl(
                        String.Format("Product: {0} costs ${1}", item.Title, item["Price"])));
                }
                catch (ArgumentException) {
                    this.Title = "Unknown product";
                    this.Controls.Add(new LiteralControl("Product not found"));
                }
            }
        }
    
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable]
        public int ProductId { get; set; }
    }

    As you can see it's a simple Web Part with one property ProductId that contains the id of the product to be listed. A specific constructor has been added which takes an SPListItem as argument - this one is used later by the custom source to instantiate the Web Part.

    The CreateChildControls is very simple and just writes the name of the product and its price, if the product is found - otherwise it shows an error.

    Create the Custom Web Part Gallery Source

    Next is to create the Custom Web Part Gallery Source. First add a new Empty Element SPI to your project - the SPI will automatically be associated with the feature that was created by the Web Part SPI (unless you installed Waldeks fancy Visual Studio extensions :-).

    In that SPI add two new classes; ProductsWebPartGallerySource and ProductsWebPartGalleryItem. The first one is the actual custom source and the second class represents the items in that source.

    The ProdcutsWebPartGallerySource is responsible for discovering and iterating the items for custom gallery extension. This class must derive from the WebPartGallerySource and implement one constructor as well as one method as follows:

    [Guid("01db1e81-5853-448e-b8c7-4b6564994ae3")]
    public class ProductsWebPartGallerySource : WebPartGallerySourceBase {
        public ProductsWebPartGallerySource(Page page)
            : base(page) {
        }
    
        protected override WebPartGalleryItemBase[] GetItemsCore() {
            List<WebPartGalleryItemBase> items = 
                new List<WebPartGalleryItemBase>();
            SPList list = SPContext.Current.Web.Lists["Products"];
            foreach (SPListItem item in list.Items) {
                items.Add(
                    new ProductsWebPartGalleryItem(this, base.Page, item));
            }
                
            return items.ToArray();
        }
       
    }

    The required constructor required only passes on to its base class. The overridden GetItemsCore() method is the method that is responsible for returning all Web Parts discovered by this source. So in this case the method simply iterates over all available items in the Products list and creates a ProductsWebPartGalleryItem object. Also notice that I added the Guid attribute to the class - we'll need that later.

    Now it's time to implement the gallery items. This is done in the second class file you created. The ProductsWebPartGalleryItem should be derived from the abstract class WebPartGalleryItemBase. It is implemented as follows:

    public class ProductsWebPartGalleryItem : WebPartGalleryItemBase {
    
        private readonly string title;
        private readonly SPListItem item;
    
        public ProductsWebPartGalleryItem(WebPartGallerySource source, Page page, SPListItem item)
            : base(source, page) {
            this.item = item;
            this.title = item.Title;
        }
    
        public override System.Web.UI.WebControls.WebParts.WebPart Instantiate() {
            return new ProductWebPart.ProductWebPart(item);
        }
    
        public override string Category {
            get { return "Products"; }
        }
    
        public override string Description {
            get { return "Show listing for product: " + title; }
        }
    
        public override string IconUrl {
            get { return "/_layouts/Wictor.Adder/product.png"; }
        }
    
        public override string Id {
            get { return item.ID.ToString(); }
        }
    
        public override bool IsRecommended {
            get { return false; }
        }
    
        public override string Title {
            get { return title; }
        }
    }

    This implementation has one constructor, taking the source, the current page and the specific list item as arguments. It stores some values locally in the class and passes the source and page to its base class. Before discussing the Instantiate() method let's take a look at the properties. These are the minimum properties required for the implementation to work, but there are several more that can be used to do some nifty stuff! Such as the ClientAdd method which allows you to specify a JavaScript method to execute when the Web Part is added or the RibbonCommand which allows you to execute a specific Ribbon command. What they do is pretty self explanatory! Interesting thing here is that you do not need to have the same category on all Web Parts in the source - you can populate several categories in the gallery, new or existing.

    The Instantiate() method is responsible for creating the Web Part with the correct properties and is called by the WebPartAdder and the custom source when a Web Part is added to the page. In this case we create the Web Part using the custom constructor and pass in the list item.

    So now all the code are done and it should compile fine. There is just one small thing left - the mysterious WebPartAdderExtension element. In your empty element SPI open the elements manifest file and make it look like the following:

    Elements xmlns="http://schemas.microsoft.com/sharepoint/">
        <WebPartAdderExtension 
            Assembly="$SharePoint.Project.AssemblyFullName$" 
            Class="$SharePoint.Type.01db1e81-5853-448e-b8c7-4b6564994ae3.FullName$"/>
    </Elements>

    As attribute values I use the Visual Studio replaceable tokens for the assembly full name and for the full name of the custom Web Part Gallery source class - here's the usefulness of the Guid attribute, no need to remember the class name and namespace and it allows for easier refactoring.

    As a final icing on the cake I also added a sweet little image to be used in the gallery. Your solution should look like this:

    image

    Ok, we're done!

    Test the custom Web Part Gallery Source!

    Now it is time to take this for a test drive. Deploy your solution, go to a page and edit it. Then click on Insert > Web Part. It should look something like this:

    SNAGHTML11b9c05

    The items in the Product list ends up as Web Parts in the Products category, with the sweet little icon. You can now choose a Web Part and insert into the page and see how it renders the correct information!

    Summary

    You've now seen how you can extend the Web Part Gallery with custom Web Part Gallery Sources. It is fairly simple and it can be very useful if you want to help the users by creating pre-configured Web Parts. I can see really many good use cases of this. Oh, I forgot - this does not work in the Sandbox.

  • The SharePoint 2010 4TB content database limit fine prints - just a warning!

    Tags: SQL Server, SharePoint 2010

    I guess by now we all seen or read about the new SharePoint 2010 guidance on scaling limits announced by the product group today. To sum it up it this is the new guidance on content database sizing:

    • up to 200GB - still the recommendation
    • 200GB to 4TB - yes, it's been done and can be done (with the help of a skilled professional architect :-)
    • 4TB or more - only for near read-only "record centers" with very sparse writing

    This looks good right, and it can be in some cases. But now on to the fine prints, which actually are written in the updated Software Boundaries and Limits article. If you read the announcement and the boundaries article you see that to be supported you need to follow a number of hard rules (such as IOPS per GB) and you must have governance rules (such as backup and restore plans) in place. Ok, if I got the IOPS needed, the best disaster recovery plans ever made and a skilled professional - should I go for the 4TB limit then? I think not, unless you really need the scale and have the hardware requirements.

    RBS: The content database size is the sum of all the data in the database and all other blobs stored on disk using RBS. So RBS does not get you around these limits!

    Size matters!

    First of all take a look at the file sizes of the content databases. Ok, you say, they are still taking the same amount of disk space whether I have a single content database or multiple content databases. Yes, the do occupy the same disk space, but you can't split them on separate physical medias (unless you go for multiple files for the database - which is another thing you should avoid), which might be necessary for performance, SLA and other reasons.

    Also consider moving really large files from your backup media, perhaps over the wire from a remote location, to restore something...

    Now think about your upgrades and patching. Remember that you update on a per content database basis, so an upgrade may take mighty long time. The SharePoint database schema is updated once in a while and if you're using really large content databases for collaboration sites (for instance) your users will be more than furious when the day of the upgrade comes along.

    Ok, I can live with all this you say. Then you need to take a look at all the other limits/thresholds/boundaries in the TechNet article - the Site Collection limits for instance. There is a strong recommendation for the size of a Site Collection to be less than 100GB, and it's there for a reason. Moving sites (using PowerShell) larger than this limit can fail or lock the database. And SharePoint (built-in) backup does only support backup of Site Collections less than 100GB.

    Exceeding the 4TB limit and aim for the sky for Records Centers?  It can be done (MS done it obviously) but also this under very explicit guidance. For instance you must base your sites on the Document or Records Center site definitions. Why? I'm not 100% sure since they are just site definitions, so it has to be some kind of "upgrade promise" from the product group that these site definitions will not have any rough upgrade paths in the future. The reason is to "reinforce the ask that the unlimited content database is for archive scenarios only".

    Summary

    This post is all about raising a finger of warning and tell you that you should not run away and tell your clients that they can now fill their content databases up to the new limits. Consider this really carefully and in most, if not all, cases use the 200GB limit when designing your SharePoint architectures. It's still good that there now is support for larger content databases when scale is needed and that we can pass the 200GB limit.

    Note: updated some parts to clarify my points.

  • Service Pack 1 for SharePoint 2010 is here

    Tags: SharePoint 2010

    SharePoint 2010About a year has passed since SharePoint 2010 RTM:ed and now the first Service Pack is released, Service Pack 1. A Service Pack is always a big deal for SharePoint. Service Packs contains all the previous cumulative updates and in most cases some new features. SP1 for SharePoint 2010 is all that.

    Before diving into some of the new stuff I want to raise a finger of warning. Plan and test your SP1 upgrade thoroughly! Even though Service Packs are tested more than CU's they are not tested in your environment and with your customizations. Read more on this topic.

    Update 1: Also read this known issues KB article before proceeding.

    Update 2: It is (by Microsoft) strongly recommended to immediately after patching with SP1 to apply the June 2011 Cumulative Update.

    Update 3: June CU has been re-released to fix some imminent issues. Read more by Stefan Gossner.

    Cumulative Updates in SP1

    Service Pack 1 for SharePoint 2010 contains all the Cumulative Updates up to the April 2011 CU. This means that you do not need to install any of the CU's prior to the SP1 or if you have already installed one or more of them you can just apply SP1. Depending on what CU level you are on your upgrade may take more or less time and require more or less testing (but there's nothing like "less testing"!). For instance if you're still on SP2010 RTM you really need to test your upgrade - so much has happened for the last 12 months.

    Other fixes

    Part from the CU's the Service Pack contains other fixes that improves the overall experience, performance, reliability etc. Some of these fixes have previously been released as hotfixes and some of them are new to the Service Pack.

    New features

    The new features is what most of us are looking for in Service Packs and this SP1 really comes with some nice enhancements. I'll briefly explain them here and give you my take on it (you'll see a gazillion other posts with more details).

    • Support for SQL Server codename "Denali": This is really cool and my favorite enhancement. SP1 introduces support for SQL Server "Denali". Denali will introduce some kick-ass BI/Insights features with "Crescent" that really will stir up the BI market and the new "AlwaysOn" HA/DR features will make your SQL Server more stable and reliable for less money! Did I mention Windows Core support!!!
    • Site Recycle Bin: This is one of the most awaited new features ever in SharePoint. Finally a solution that allows you and your admins to restore whole Site Collections without reverting to backups or custom solutions. The Site Recycle bin also has a set of PowerShell commands; Get-SPDeletedSite, Restore-SPDeletedSite and Remove-SPDeletedSite.
    • StorMan.aspx: A small but welcome new/old feature. The Storage Space Allocation page is back.
    • Shallow copy: This feature should not be a big deal since it is aimed for RBS - and you should not use that unless it's necessary. But if you do, then Shallow copy makes it easier and more reliable to move Site Collections using RBS.
    • Browser support: Yes, SP1 introduces IE9 support (in IE8 standards mode) and Chrome is now supported in SP2010 (not only in Office Web Apps). Native IE9 support in Office Web Apps (updated)
    • Office Web Apps: a whole bunch of new stuff such as charts in Excel, printing support, ODF support. Clip art support for PowerPoint (admin enables/disabled).  (updated)

    Summary and download!

    I just can't wait to get back to my customers and start the planning and testing for SP1. I know they will love the new features. So where do I get it then? Now! Just head on over to the SharePoint 2010 Updates portal on TechNet: http://technet.microsoft.com/en-us/sharepoint/ff800847 or the Office Update Center: http://technet.microsoft.com/en-US/office/ee748587.aspx or if you want to get it right now then these are the places:

    Have a nice summer!

  • Give your SharePoint 2010 custom Application Proxy Groups pretty names

    Tags: SharePoint 2010

    SharePoint 2010 allows you to configure your Service Application in Application Proxy Groups. By default all Service Applications ends up in the Default Proxy Group, named default. This Proxy Group is used by all Web Applications unless otherwise specified. Sometimes there is need to create specific Proxy Groups for different Web Applications, the reasons may vary but often it is a result of having different service offerings. For instance you would like to have different Managed Metadata Service Applications for different Web Applications.

    Service ConnectionsCustom Proxy Groups can be created in the user interface (Central Administration) and is automatically created once you customize the Service Connections for a Web Application. To create a Custom Proxy group for a Web Applications you go to Central Administration and select the Web Application you would like to configure and then choose Service Connections in the Ribbon. A modal dialog window with all available Service Applications appear, this dialog contains a drop down in the top where you choose Proxy Group. This drop down contains two values by default; default and [custom]. To create a custom Proxy Group for the Web Application you just select the [custom] option and then select the service applications to use.

    No pretty names

    When you start to create a number of custom Proxy Groups it might be hard to differentiate them from each other. The name [custom] doesn't mean anything, but that it's custom.

    Instead I prefer to name these custom Proxy Groups into something meaningful. Unfortunately you cannot create named Proxy Groups in the user interface and have to revert to PowerShell. But it's a really simple PowerShell cmdlet to do this:

    New-SPServiceApplicationProxyGroup -Name "Extranet Service Group"

    This simple command creates a named custom Application Proxy Group, in this case Extranet Service Group. Now when configuring Service Applications for a Web Application this new Proxy Group will appear in the drop down:

    Man, this is pretty!

    A far better alternative, don't you agree?

  • You cannot create property based search scopes in Office 365 (SharePoint Online)

    Tags: SharePoint 2010, Office 365

    Post is updated, see comments at the end of the post.

    We're really getting close to the go live of Office 365 and I am, and I guess a lot of you are as well, preparing to launch a couple of Intranets and sites. As you know by now there are some major differences between SharePoint 2010 on-premise and SharePoint Online in Office 365. And there are also some more subtle ones that jumps up right in your face.

    Today we were designing a topology for an intranet and we thought that we could use Search Scopes to search and aggregate data. Site Collection Search Scopes are available in SharePoint Online, but you cannot access the Search Service Application and create global Search Scopes. That's fine, we're in a megamulti-tenant environment here. Search Scopes are very convenient to use when you would like to do a search for a specific type of documents or information since you can create Property Query based Search Scopes. This is how it looks like in a standard on-premise SharePoint 2010:

    On Premise Search Scope

    So I tried to do the same thing in Office 365! And found out that a Property Query is not possible to create. You can only create Search Scopes based on the Web Address/URL! Sigh! I can't really see why this is disabled (see update below). Yes, I understand that they won't let us create Managed Properties, but this is to sneaky!

    Cloud Search Scope

    So back to the drawing board for me!

    Update!

    After some discussions on Twitter with SharePoint Master2 Mirjam van Olst the actual answer wasn't that far. She led me to the SharePoint Server 2010 capacity management: Software boundaries and limits document on TechNet (which I read a gazillion times lately when studying for the MCM). This document clearly states that the Threshold is "200 site scopes and 200 shared scopes per search service application" and "Exceeding this limit may reduce crawl efficiency and, if the scopes are added to the display group, affect end-user browser latency. Also, display of the scopes in the search administration interface degrades as the number of scopes passes the recommended limit.". This of course does not work in a multi-tenant environment. Notice that it's only a threshold.

    But! Why can we create URL based scopes? To find out I created two different scopes in an on-premise box and took a peek on the SSA admin database (I only looked, no hands!). All scopes global or site collection scoped are stored in the SSA admin database and compiled every 15 minutes. Both property query rules and URL rules are treated the same. That lead me to the lovely SharePoint protocol specifications, and specifically the MS-CIFO which describes the index files. This document describes how the scopes are handled in the index, using the Scope Index File format (.bsi files). My interpretation of the specs are that these files in the index are used when querying using a specific scope and therefore affecting the crawling since they are index files and behaves just like any index with merges etc. I didn't go any further...

    I still cannot tell for sure why URL rules are allowed, but my best guess is that they do not affect performance in the same way as property based rules are. So in Office 365 URL rules can be used. Also, since URL based rules are not that useful they will not be used as much anyways...

    /end update

    (Notice that I didn't mention "cloud" anywhere...dang, I just did...)

  • Microsoft Certified Master - SharePoint 2010, thoughts and reflections

    Tags: Personal, SharePoint 2010

    Now with the Microsoft Certified Master course two and a half weeks behind me and the great news that I accomplished all the exams, and might call myself a Microsoft Certified Master for SharePoint 2010, only a few days old I thought I should write something about the program, experience and value of it. Recent blog posts about the Microsoft certification programs also put some extra fuel onto the urge of writing about it.

    About the Microsoft Certified Master Program

    The Microsoft Certified Master Program is a high-end and exclusive training available for SQL Server, Active Directory, Lync Server, Exchange Server and SharePoint Server. The training is normally a three week course, held on site at the mothership in Redmond, tutored by the most skilled people on the respective product. It's the best training you can get! But it's not for everyone; first of all you need to pass several steps to even get into the program, then you need to pay the huge fee and then finally get out of the classroom with three exams and a qualification lab alive. If you need more information about the program, head on over to the MCM/MCA site.

    My rotation

    Ever since I first heard about the MCM program for SharePoint it has been a dream going over to Redmond and endure the pain. Last fall me and my company decided that I should go for it. So in December I started the application for the MCM training. The application is done in several steps. Before even starting it you have to pay the non-refundable application fee of about $1.000. Once this is cleared the application process starts; you need to send in samples of what you have done with the SharePoint products like specifications and designs and then you will be scheduled for an interview. The interview was horrible and at the same time fantastic. I had three people, current masters, interview me trying to find all my gaps and pain points. Once you couldn't answer properly or directly the drilled even further  until you almost had no idea what they were talking about. I was really impressed by the interview and the background research the interviewer had made - they even questioned me on details in my presentations that I had posted on my blog.

    Lab time in B40About a week after the interview I had a phone call where I was told that I was allowed into the program and schedule a rotation, after paying the huge fee. I also received very good feedback on what I needed to read up on and practice on. This was in January and I scheduled the next upcoming full rotation, which was in April/May. And now the hard work started. The pre-reading list is quite extensive and covers most of TechNet and MSDN and I finished that a couple of weeks prior to the rotation. I also did a lot of practice on my own using CloudShare where I could build me some virtual farms and experiment with different scenarios.

    When the actual rotation started I thought I was well prepared! But, the depth and level of details was far more than I expected. Each and every session had so much information that needed to be placed somewhere in your head and I found myself sometimes not finding room for it. I especially remember the Search session and the Upgrades sessions! During these three weeks every weekday had scheduled sessions daytime and evening/nights were spent on reading and doing hand-on-labs. A huge credit to the MCM team with Brett leading the crew, for all the labs and the amazing lab environment! The weekends were spent on reading, reading, reading and doing labs to prepare for the weekly exams. These are Prometric like exams but where almost any answer could be the correct one - extremely hard.

    The Qualification Lab

    The grand final of the MCM is the Qualification Lab. It's an 8 hour long lab where you get a number of tasks, ranging from IT-pro to dev stuff to governance and architecture. I was quite nervous about this one, but as soon as it started I enjoyed every single minute of it. I usually drink quite a lot of coffee - but I forgot about that and I almost skipped eating my lunch to try to get as much as possibly done. After the qual lab I was completely drained, and I guess most of my R8 mates was as well.

    MCM Summary

    After coming home I was so tired, should have taken vacation! Not only the jet lag but in fact that you have been receiving so much information and learnt so much over the past few weeks. A week and a half after getting home I got the fantastic news that I passed all written exams and the qualification lab. On my first attempt - hell yeah I'm proud!

    The network you build during the rotation with the class mates, tutors and product group are invaluable. I've already after a few days seen the benefit of this!

    MCM tips and tricks

    Here are some tips and tricks for you already scheduled for a rotation or planning on diving into the MCM:

    • Prepare and prepare well
    • Plan your rotation - plan the pre-reading and practice on the different topics
    • Read the pre-read list
    • Exercise before and during your rotation - sitting in those chairs for three weeks really takes its toll
    • If your used to a non-American keyboard - bring your own since you're going to write a lot of PowerShell and stuff and you don't want to waste time on mistyping for the qual lab. (I actually bought an American keyboard over there instead)
    • Enjoy!
    • It depends!

    So what about the other SharePoint certifications...

    I'm not talking about the MCA, that's for just a few brave ones. I'm talking about the four MCP exams. I've done them all, since it's a pre-requisite for MCM, and I've done the four for 2007 and one for 2003. I've previously wrote about them and I still stand by my post from last year. I do not think the exams are actually good - they have huge improvement potential.

    But I'm not, like some others, that refuses to take them just to stand out and look cool. They provide value for businesses that are Microsoft Partners and if you're a MCT. Also the clients are actually aware of these exams, compared to other non-Microsoft sanctioned exams, and they sometimes request that you have them. Also they can be of real value when your learning SharePoint - you can see what areas you need to improve on etc. So I do recommend you to go and get them!

    The problem with MCM though is that very few clients are aware of this certification. And that's what we/I are trying to change. And in fact I think this is changing right now, even before attending the training, I saw an increase in attention in my and my companies services.

    Now I'm going to enjoy this and soon have a nice vacation to catch up with lost time with the family.

  • How to do active authentication to Office 365 and SharePoint Online

    Tags: SharePoint 2010, Office 365

    This is a post detailing how you perform active authentication to SharePoint Online in Office 365. Active authentication is required when you need to authenticate in code to programmatically access SharePoint objects, using for instance Client Object Model, web services or WebDAV from outside of Office 365. When you are "in" SharePoint Online or using the web browser this is not needed since you are either already authenticated and the web browser handles the authentication using active authentication.

    Note: The active authentication "mechanism" have unfortunately changed a few times the last month without any notice. I had a really bad timing with one of these changes just a couple of days before demoing it on TechDays here in Sweden. With that said - I cannot guarantee that this method will work in the future. But if it changes I'll try to update the post or write a new one...

    SharePoint Online active AuthN basics

    Before digging into the actual code I think it is important to understand how it actually works and what the code does. This is easier done using a diagram.

    Passive claims AuthN

    What happens is that we need to request a token from the STS. In Office 365 the STS is located at https://login.microsoftonline.com/extSTS.srf. To request the token from the STS we pass the username and password using the SAML 1.1 protocol. If the authentication is successful the STS returns a security token. This security token is sent to SharePoint and if SharePoint successfully validates the token it will return two cookies (called FedAuth and rtFa). These two tokens must then be passed along with all requests to SharePoint.

    There are some other interesting things happening here  that you need to be aware of. For instance; you need to be aware of which Office 365 subscription you are targeting. P-subscriptions must use HTTP Url's when communicating and E-subscriptions must use HTTPS. Using HTTPS for P-subscriptions will create redirect responses that eventually will drive you crazy when trying to code around them (I got a solution for that though - but I can't get any worse anyways).

    How to use Client Object Model with Office 365 from a remote client

    To be able to remotely invoke methods on SharePoint Online using Client Object Model (CSOM), web services or WebDAV we need to authenticate first, according to above. Then we need to pass along the cookies for each request. And this is how we do it. Once you have the cookies (FedAuth and rtFA) you need to create a CookieContainer object in which you add the cookies. This CookieContainer must then be added to the request done by the Client Object Model before the request is done. The client runtime Context object has an event called ExecutingWebRequest that can be used for this. The code could look something like this:

    context.ExecutingWebRequest += (s,e) => {
        e.WebRequestExecutor.WebRequest.CookieContainer = 
            createCookieContainer();
        e.WebRequestExecutor.WebRequest.UserAgent = userAgent;
    };

    The createCookieContainer() method is the one responsible for creating the cookie container, more on this one later. Also note here that I set the UserAgent of the request to a new value. This is important! If you do not set any user agent of this request SharePoint Online will gently throw a 403 Forbidden error if you're on an E-subscription. It works fine without on P-subscriptions, but it doesn't harm to add it. So just do it all the time, for the sake of it! The user agent could be any normal browser - this is what I use:

    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)" 

    That's basically it! Use the same procedure when you're manually using WebRequest objects or when you're using the SharePoint web services. Just add the cookies and user agent and you're fine.

    Show me the code to get the cookies!

    Now to the core of this article. How does the code look like to get the actual cookies? As a good TV-chef I've prepared all the things you need to make it really easy for you. I've been using a number of helper classes for a couple of months now and first showed them during TechDays 2011. Chris Johnson, Microsoft, also made a version of them for his blog post on the topic. My helper class has an origin in posts from Steve "SharePoint Claims" Peschka. I've modified and tweaked his code samples so that they work with SharePoint Online.

    What I've done is a helper class called MsOnlineClaimsHelper. This class contains all you need to authenticate, retrieve and cache the cookies and piggyback the cookie container on the CSOM web requests. Let's see a very simple sample:

    MsOnlineClaimsHelper claimsHelper = new MsOnlineClaimsHelper(url, username, password);
    
    using (ClientContext context = new ClientContext(url)) {
    
        context.ExecutingWebRequest += claimsHelper.clientContext_ExecutingWebRequest;
    
        context.Load(context.Web);
                    
        context.ExecuteQuery();
    
        Console.WriteLine("Name of the web is: " + context.Web.Title);
                    
    }

    On the first line I create the helper object and pass in the URL, username and password. This class will once used do the active authentication for you and cache the cookies until they expire. It will handle the HTTP/HTTPS problem with the E/P-subscriptions mentioned earlier, the User Agent problem and everything else you need. Yes, you will be able to download the code later. After creating the client context I hook up a helper method of the MsOnlineClaimsHelper class called clientContext_ExecutingWebRequest. This method is the one adding the cookies and fixing the user agent. Then it's just to use the client object model as usual. Remember that when you are using P-subscriptions the URL's passed into the client object model must be HTTP (the helper class doesn't really care and can handle both) and use HTTPS for E-subscriptions.

    The helper class is made so that you can reuse it, so you don't have to re-authenticate all the time, since that will really slow your application down. If you need the CookieContainer to add to your own web requests it has a property called (surpise!) CookieContainer that you can use.

    To illustrate another use, that also is a very useful helper class, is a Office 365 claims aware WebClient derivative.

    public class ClaimsWebClient : WebClient {
        private readonly MsOnlineClaimsHelper claimsHelper;
    
        public ClaimsWebClient(Uri host, string username, string password) {
            claimsHelper = new MsOnlineClaimsHelper(host, username, password);
        }
        protected override WebRequest GetWebRequest(Uri address) {
            WebRequest request = base.GetWebRequest(address);
            if (request is HttpWebRequest) {
                (request as HttpWebRequest).CookieContainer = claimsHelper.CookieContainer;
            }
            return request;
        }
    }

    This is a class that can be used just as the normal WebClient class. Using this one you enable WebDAV fiddling with SharePoint Online. It's very useful to upload and retrieve documents using PUT and GET methods.

    The download

    I promised you to see the code how we actually retrieves the cookies. Sorry, I won't. I'll leave that to you. Download the code sample, including all helper classes, by clicking this link and experiment with it as you like.

    Happy coding!

    Updated: Sometimes you're tired - mixed up passive and active...

  • Speaking at the European SharePoint Conference in October

    Tags: SharePoint 2010, Presentations

    imageI'm proud to announce that I have been selected to speak at the European SharePoint Conference, held in Berlin 17-20 October 2011. This is the largest SharePoint conference in Europe this year and there are plenty of good speakers and sessions, so get your seat while they still are available.

    I will have two sessions:

    I will be bringing a few copies of my book, so make sure that you attend my sessions and have a chance to win one.

    Webinar on developing for Office 365 and SharePoint Online

    I will also have a webinar, next week on Wednesday, that you can join to get up to speed on developing for Office 365 and SharePoint Online. Make sure you don't miss out on it. Register online here.

  • CKSDev version 2.0 is released - includes Contextual Web Part SPI

    Tags: Visual Studio, SharePoint 2010

    Extension ManagerThe by far best utility for SharePoint 2010 developers is the CKSDev extension (Community Kit for SharePoint - Developer extensions). It's an extension to Visual Studio 2010, available through the built-in Extension Manager. To install it, just hit Tools > Extension Manager and then search for "CKSDEV" in the Online Gallery. Version 2.0 of CKSDev was released yesterday, and if you already have it installed you should have been notified about the update.

    CKSDev is a community effort involving several genius SharePoint developers that in a combined effort shares their best tools and extensions in one package. It includes everything from new project templates, project items, extensions to the built-in designers and explorers. It's just a project that you can't live or work without. You can read more about all the great features at: http://cksdev.codeplex.com. Where you also can find the source code if you're interested in building your own extensions and eventually contribute to the project.

    Contextual Web Part SPIThe version 2.0 release is a great update and contains new and better keyboard shortcuts, the WSPBuilder Conversion Tool and a set of new SPI's. My contribution, except for testing, is the Contextual Web Part SPI. This SPI allows you to easily create a Web Part with a contextual behavior, that is it has an accompanying Ribbon extension.

    To create a Web Part using this new SPI just add a Contextual Web Part (CKSDev) project item into your farm solution. Your project will get modified to include the necessary references for the Web Part and Ribbon extension to work and it will add a new SPI.

    The Contextual Web Part SPI dissected

    The SPI contains a set of files;

    • A .cs file - this is your actual Web Part class containing the necessary Ribbon plumbing
    • A .webpart file - the standard Web Part Control Description file
    • An Elements file - the element manifest for the Web Part
    • A CustomAction file - this is the Ribbon extension and it includes a new ContextualGroup with a Tab containing a Button and then necessary templates
    • A PageComponent JavaScript file - this is the Ribbon Page Component where you implement the logic for the Ribbon commands
    • A sprite image - this is a sample image containing the sprites for your Ribbon icons

    It's very easy to build your own Contextual Web Part using this. Just add the necessary business logic into the Web Part, modify the Ribbon in the CustomAction element manifest and hook up your actions into the Page Component. Don't forget to add your sprites into the composite image instead of creating tons of small images.

    This is how it (almost) looks out of the box.

    A custom Contextual Web Part

    If you find anything "funny" about this SPI - don't hesitate to get in contact with the team.

    Happy SharePointing!

  • Session Timer for Windows Phone 7

    Tags: Windows Phone 7

    Once in a while even a SharePoint addict does something else but SharePoint and so has I. I've been fiddling a bit with a Windows Phone 7 application. Actually the application has been available in the Windows Phone marketplace for two months now (thanks to those who downloaded it or even purchased it). But now it's up to version 2.0 where all my initial wanted features are in place, thanks to a huge delay when flying into Seattle this weekend.

    The application is called Session Timer. It's a WP7 app that allows you to plan your presentation sessions into segments and time them so that you can use your WP7 as a counter while presenting. Why you say, isn't that what PowerPoint presentation mode is for? Yea - if you're only using PowerPoint! I often do presentations where I have PowerPoint on the big screen and the outline on my laptop. But when it comes to doing demoes in virtual machines, Visual Studio or other non-presentation-mode aware applications you have to either stand looking over your shoulder on the big screen or flip back and forward between extended or duplicate screen. And this is where this application fits. Or when you're doing presentations without PowerPoint presentation mode - which in many cases is better (I remember the keynote from PDC08 where Chris Sells and Don Box did a command prompt and notepad only session - one of the best shows I've seen ever).

    So, in Session Timer version 2.0 you can create multiple sessions (trial limited to two) and each session has none or more segments (trial mode is limited to three). Each session has a running time and a title and each segment has a start time, title and color. The screen will always show your session and counting down the time for the whole session and for each segment individually. You can also see the title of the upcoming segment. Since each segment has a color that is reflected as the background color for the segment. This allows you to easy see what parts of your presentation you are in - for instance your demos might always have red background. You can also turn on vibration for each segment as an extra reminder.

    Here's some screenshots of the application.

     

    Do you think this sounds interesting, then download the trial on the Windows Phone Marketplace by clicking on the tile below:

    If you have any feature requests or find any anomalies - please head on over the the Session Timer Facebook page and discuss it.

  • Get rid of the annoying SPAN tags in SharePoint 2010 pages

    Tags: SharePoint 2010

    For quite some time I've been pretty annoyed (and that's an understatement) of the strange span-tags generated by the output of pages in SharePoint 2010. Not only are they annoying they also make the markup invalid, since the span tags are omitted after the closing html tag (duh!).

    Spans, spans, spans

    So in order to get to the bottom of this I decided to face my fears and entered debugging mode. It only took me a few minutes to find out what was going wrong, and I didn't even have to step (almost) through any SharePoint code to find it out. Here's what I found and how I found it...

    First I enabled the Developer Dashboard and turned on the ASP.NET page trace. I immediately noticed the following controls being added to the control tree at a suspicious location. The SPPageStateControl, a top-level control in the control tree, had 17 child controls - the exact same number as empty span tags being omitted. Probably not a coincidence.

    The mysterious controls...

    I checked the master page (v4.master) and could not find the SPPageStateControl. It must be inserted dynamically then, so I fired up Reflector and did an analysis of that control and found out that it's instantiated by the WikiEditPage during the OnLoad event. And the control is inserted directly as a child to the page object. Hence the rendering of the span-tags after the closing html tag. The SPPageStateControl inherits from SPControl (which inherits from Control) and produces no output - so this one was not the bad guy.

    I turned to the child controls (SaveCommandHandler etc) which all are inheriting from SPRibbonCommandHandler. And the SPRibbonCommandHandler inherits from the WebControl - if you know your ASP.NET basics then you know that a WebControl outputs a span tag, if nothing else is specified. Eureka!

    Get rid of 'em!

    So, how do we get rid of these span tags then? We can't just go into the SharePoint code and override the RenderBeginTag and RenderEndTag of the SPRibbonCommandHandlers, and we can't change the SPRibbonCommandHandler to inherit from something better; for instance a plain ol' Control (thanks Waldek). What do we have in our toolset then? ControlAdapters of course!

    After a quick analysis of the SPRibbonCommandHandlers (and the controls inheriting from it) I've found out that none of them requires to render anything (I've not tested every scenario available so I'm not giving guarantees here). I should be safe building a control adapter that makes the SPRibbonCommandHandler not rendering anything, not even a single pesky span. These controls are only present to handle different postback scenarios and handle server-side commands from the Ribbon, so they do not need to do this span-rendering-frenzia.

    Using the exact same technique that I use in my SharePoint 2010 Web Parts in Action book to register ControlAdapters (get the book if your looking for the details - or download the WSP linked to at the end of this article), I created a solution that completely removed the spans.

    First I created a control adapter like in the following snippet. We just override the Render method and make it do nothing.

    namespace Wictor.NoSpans {
        [Guid("78e05555-17b6-44b7-95ea-3db315058b1a")]
        public class RemoveTheSpansAdapter: ControlAdapter {
            protected override void Render(System.Web.UI.HtmlTextWriter writer) {
                //base.Render(writer);
            }
        }
    }

    This adapter must be registered using a Browser Definition File (.browser). This file contains the original control full name and the target control like this:

    <browsers>
      <browser refID="default">
        <controlAdapters>
          <adapter
            controlType="Microsoft.SharePoint.WebControls.SPRibbonCommandHandler,                     Microsoft.SharePoint, Version=14.0.0.0,                      Culture=neutral, PublicKeyToken=71e9bce111e9429c"
            adapterType="$SharePoint.Type.78e05555-17b6-44b7-95ea-3db315058b1a.FullName$,                     $SharePoint.Project.AssemblyFullName$"/>
        </controlAdapters>
      </browser>
    </browsers>

    The .browser file must be deployed to the App_Browsers folder of the respective web application. This is done by a timer job, that copies the file from the feature to the Web Application App_Browsers file. That is; we're creating a feature that targets a Web Application. [Commercial] Full code for this is available in the book[/Commercial].

    All we have to do next is deploy the control adapter, browser definition file using the WSP and start the timer job via the feature. Next time the page load we will not see the seventeen annoying empty span tags! Phew!

    No more spans

    Download the WSP file here to get rid of your spans...

  • Happy Birthday SharePoint - 10 amazing years!

    Tags: Personal, SharePoint, SharePoint 2010

    Earlier today Jeff Teper, Microsoft Corporate Vice President, wrote about the 10th birthday of SharePoint. This post made me lean back and close my eyes for a while and think back of what has happened during the last decade - and it is a lot of stuff! And I've playing with SharePoint more or less since then!

    iBizkitThe SharePoint story for me started back in 2000. I was running my own company, iBizkit, and we built a "SharePoint like" Intranet portal product. The product was modular based and very configurable. We hade something we called Modules based on COM+ components and XML output, that had a common interface and a single rendering engine which could translate the XML output to HTML, WML or whatever depending on the device and the users settings. I was, and am, still very proud of that architecture. Initially we looked at the Digital Dashboard, but came to the conclusion that it didn't fit our needs, so we built our own from scratch. It was built on top of Site Server (and then later on AD), IIS, ASP and COM+. We got a request from a customer that they would like a document management system for their Intranet. And what could be better than building it yourself - use a third party tool. And at that time I've been checking out the Tahoe project from Microsoft, that later became SharePoint Portal Server 2001SharePoint Portal Server 2001. What we did was build a more dynamic interface (way before AJAX was known as AJAX, and this is where Robert Nyman started his brilliant JavaScript career). than SPS 2001 had and incorporated that into a module in our portal solution. I dug up on old screenshot:

    SNAGHTML33c116e

    This gave me a great introduction to the SharePoint world. The document management module was a great success - and I think we were one of the companies in Sweden that actually managed to sell a few SPS 2001 licenses :-).

    SharePoint Portal Server 2003Then Microsoft Office SharePoint Portal Server 2003 and WSS 2.0 arrived! Based on .NET with all new API's and stuff - but the lack of real document versioning. We once again incorporated SharePoint into our portal - also now built on .NET. But since there was no real versioning our clients stayed on the SPS 2001 platform. I actually spent about six months trying to build decent versioning on top of SPS 2003 - without any good results. Microsoft Office SharePoint Server 2007And that project ended when the betas of Microsoft Office SharePoint Server 2007 and WSS 3.0 was released. And from that day I was totally hooked!

    For the last time we adapted our document management module to SharePoint and continued our portal product - but in parallel we started plain ol' SharePoint consulting. As time went the SharePoint consulting part took overhand for me and we could not longer compete with our small niche product. In 2009 I left my dear old company, which we sold a couple of years earlier, in chase of even greater SharePoint adventures.

    Microsoft SharePoint Server 2010In 2010 I was awarded SharePoint MVP, and now again in 2011. I just released my first book, about SharePoint of course, called SharePoint 2010 Web Parts in Action.

    Why is SharePoint so damn special then? First of all it's a great product - no doubt about it. Microsoft has sold a gazillion licenses, it's their fastest growing server product ever! But why am I still loving this so much? There are several reasons; first and foremost it's my will to build great things that the customers like. What can be better to base that of a great platform. Secondly is that it's quite a challenging product that gives you never ending obstacles and situations - which makes me learn more and grow more. Third is the amazing community - I do not think that there are many alike out there.

    I thought that I should end this with a link to a very, very old article, from back in February 1999. This is an article where Mary Jo Foley (who knows more about Microsoft than Microsoft themselves do) for the first time mentioned the product that we all love: MS readies next-generation software.

    Thank you all and thank you Microsoft. Looking forward to ten more great years!

  • Understand Top Browser statistics in SharePoint 2010 Web Analytics

    Tags: SharePoint 2010

    AnalyticsThe Web Analytics feature in SharePoint 2010 is a great new addition and allows you to get some insights on how your users behave whether it's an Intranet, Extranet or a public facing web site.

    One of the reports is called Top Browsers and shows which web browser that the users are using to access the site. For a public facing web site this report might make sense but for an Intranet the results may cause you a headache if you do not understand how to interpret the data.

    Let's assume that you have an Intranet with a standardized web browser platform with Internet Explorer 8. If you take a look at the statistics you will first notice that the most used browser is Internet Explorer 7, following that are most often Unknown and/or Netscape4. Internet Explorer 8 is coming later down (together with instances of Safari, Firefox, Chrome etc. - some people just have disobey the corporate rules :-).

    So why is Internet Explorer 7 the top used browser then - this is really easy to find out since on intranets IE8 and IE9 uses the Compatibility mode by default, that is it's acting as IE7 and sends that user agent string (see MS-IEDOCO 2.1.2.5). So the Web Analytics treats this session as an IE7 session. The default master page (v4.master) adds the X-UA-Compatible meta header which switches the document mode to IE8 though during runtime.

    What about Netscape4 and Unknown then? These requires us to understand a little bit more about how SharePoint is used on an Intranet. An Intranet is not just used by a web browser, people are requesting information using for instance the Office clients (Word, Excel etc.). When the Office clients talks to SharePoint through the WebDAV protocol it sends its own user agent string (for instance: Microsoft Office/14.0 (Windows NT 5.1; Microsoft Outlook 14.0.4734; Pro)). Web Analytics does not "recognize" this one and places it in the Unknown bucket. The Netscape4 browser comes from the same source but are used when detecting which version SharePoint has, when the Front Page Server Extensions requests the _vti_inf.html file.

    I hope that this gave you some insights in how the SharePoint 2010 Web Analytics interprets the user agent strings.

  • SharePoint MVP for another year

    Tags: Personal, SharePoint

    The 1st of April is one of those days when a fourth of all MVPs just waits for the renewal e-mail from Microsoft. Luckily I got mine this year, just before heading home from work this afternoon. This means that I will do my second term as a SharePoint MVP and I'm already looking forward to the paintball in a cold a rainy Seattle!

    Congrats to all other renewed and new MVPs all around this globe.

    image

  • Presentations and code for Office 365 and Windows Azure sessions from TechDays 2011

    Tags: Windows Azure, SharePoint 2010, Presentations, Office 365, AppFabric

    Back in the saddle from another TechDays event here in Sweden. This year it was all about the cloud! It was as always a great show and an awesome party. Thank you Microsoft, all presenters, all attendees and sponsors.

    I did two sessions - or actually one session divided into two segments about Office 365 and Windows Azure. I tried to squeeze in as much cloud technology as I could in a one big demo. For those who attended - I hope you enjoyed it. If you want to go back to the slides or take a look at the demo code you can find them below. The sessions were also recorded so you can enjoy them in full glory (keep an eye on the TechDays site for more information).

    Presentations and code

    Here's the code.

    Interview

    I was also interviewed after my sessions by Peter Nicks from Microsoft - and here's the video of that:

    TechDays 2011 Interview

    See ya next year...

  • Presenting at TechDays 2011 Sweden on Office 365 and Windows Azure

    Tags: Microsoft, SharePoint 2010, Presentations

    In less than a week Sweden's largest Microsoft conference will take place in Örebro - TechDays 2011, same place as last year. The conference is already fully booked with 1.700 participants, but there's a waiting list! The theme of the conference is "The Cloud Story".

    TechDays 2011This year I will do two sessions, or rather one long sessions split into two parts on Office 365 + Windows Azure. This will be over two hours full of great demoes and information. I've built one big demo that will combine the powers of Office 365 (SharePoint Online, Exchange Online, Lync Online) and Windows Azure (web and worker roles, SQL Azure, AppFabric). We'll also touch on technologies such as Silverlight, WPF, Open XML and WIF. So if you think this is interesting, if you're considering moving your stuff into the cloud or just want to have fun - then these are the sessions to attend.

    My sessions will require some interactivity from you - so if your coming bring your cell phone or laptop ready to browse the web. Participation will be rewarded!

    After each session I will hang out next to the session room to answer all your questions on these topics or any other things you have on your mind. You can also meet me in the Cloud Emergency Area (aka Ask the experts) or at the Connecta stand.

    See you there!

  • Calling a WCF Service using jQuery in SharePoint - the correct way

    Tags: SharePoint 2010

    Today an article was published on the SharePoint Developer Team Blog called Calling a WCF Service using jQuery. The content and purpose of the article is good and interesting but the way it is implemented can not be considered best practice and is definitely not the way we (I) teach SharePoint 2010 development. For instance this article manually registers assemblies in the Global Assembly Cache! Something that we never should do! It tells you to copy files to the virtual directory bin folder and into the Layouts folder! Ouch! Also, the article contains some plain ol' errors.

    Since the content of the article is relevant I will show you how to do it - the correct way. I'll be using exactly the same code and sample but using the SharePoint 2010 Visual Studio templates and a WSP package to deploy the solution. So let's get going doing it the correct way:

    1) Create the Visual Studio 2010 project

    Instead of splitting this up into several (non-SharePoint) projects we would like to make the whole solution deployable as a WSP file.

    We start this by creating a new Visual Studio 2010 project by using the Empty SharePoint project template. The project must be deployed as a Farm solution, since we're going to deploy stuff into the SharePoint Root.

    2) Create the Data Access Layer

    This is just as in the original article. Add a simple class to the project and implement the DAL. (You don't need to have a backing database, just make some objects when testing this solution).

    3) Create the WCF Service

    WCF ServiceTo create the WCF service we'll do it in a different way, compared to the original article. Add a new WCF Service project item to the project and name it ProductService.cs. This will add three files to the project; IProductService.cs, ProductService.cs and app.config. You can safely remove the app.config, we don't need it in this case.

    Then implement IProductService.cs and ProductService.cs just as in the original article. Add references to Microsoft.SharePoint.Client.ServerRuntime.dll (found in GAC) and System.ServiceModel.Web.

    The .svc file is added to the project by first adding a new SharePoint "Layouts" Mapped folder. Then add a simple text file project item to the layouts folder with the name ProductService.svc. We'll come back to this one in a bit. First we need to make sure that we can use the Visual Studio 2010 replaceable tokens in svc files. Unload the project file and add a new PropertyGroup to the project file like this:

    Replaceable tokens

    Load the project file once again and Visual Studio will during your next packaging parse the .svc files for replaceable tokens. Next go to the ProductService.cs file and add a Guid attribute to the ProductService class (don't forget to add the namespace System.Runtime.InteropServices). The class should look like this:

    Guid attribute

    Now head on over to the .svc file in the Layouts folder and edit the file so it contains the following (note that the code snippet below contains line breaks in the attributes which your code should not do):

    <%@ ServiceHost Language="C#" 
        Service="$SharePoint.Type.dc339fb8-7f69-4fdd-b2c6-d3586dfa6337.FullName$,
            $SharePoint.Project.AssemblyFullName$" 
        Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory, 
            Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0, Culture=neutral, 
            PublicKeyToken=71e9bce111e9429c"%> 

    As you can see the Service attribute consist of two replaceable tokens; the class name and the assembly full name.

    Tip: If you think that there is to much manual configurations going on here then just download the latest release of CKS:Dev -it has a project item template for just this: WCF Service (CKSDev).

    4) Create the JavaScript stuff

    The JavaScript file which contains the custom JavaScript functions and classes should be added to the Layouts folder. And while your there add the jQuery JavaScript file as well. The JavaScript should look like in the original article, except that there is a typo in the CallWCFService() method. The call to the jQuery ajax method should have the dataType property set to "json":

    typo

    5) Add a Web Part to test it

    The easiest way to test this solution is to add a Web Part to the project. Do that and implement the CreateChildControls method as follows:

    protected override void CreateChildControls() {
        ScriptLink.Register(this.Page, "jquery-1.4.2.min.js", false);
        ScriptLink.Register(this.Page, "ProductsService.js", false);
        string url = SPContext.Current.Web.Url + 
            this.ResolveUrl("~/_layouts/ProductService.svc/GetProducts");
        ScriptManager.RegisterStartupScript(this.Page, typeof(ProductsWebPart), 
            "ShowMeHeaven", 
            String.Format("CallWCFService('{0}')", url), true);
    }

    As you can see from the snippet above the jQuery and the custom JavaScript file is registered using the ScriptLink control and then we register a startup script which invokes the custom JavaScript method which calls the WCF service.

    6) Test it

    Your solution should now look like this:

    The correct project

    Now, just go ahead click F5 and watch the solution deploy. Then add the Web Part to a page and see the alerts popping up with the data from the WCF service.

    Summary

    What I wanted to show with this article is a best practice approach to building SharePoint 2010 solutions by using WSP files and avoid all manual configuration of the SharePoint Root, virtual directories and GAC. If you do that you will end up with an inconsistent farm and you have to pay sooner or later for that, and it will cost!

    Happy SharePointing!

  • About the Customer Experience Improvement Program in SharePoint 2010

    Tags: SharePoint 2010

    The other day I was setting up another SharePoint 2010 farm and got the usual question to participate in the Customer Experience Improvement Program (CEIP). As always I bailed out of this. Why? Sending information to a third party about my SharePoint farm doesn't appeal me, even if it's Microsoft. You know, they might check how I configure my farm, how I use it etc., and then sit back and laugh at me. Not really, but I think most of us prefer not to send that information to Microsoft. But, this is not my normal standing to the CEIP. I use to participate in it, like when I install new software and they have that little checkbox asking me to send info about my installation. Why not give Microsoft some help about any kind of troubles during the installation. But when it comes to SharePoint - nope.

    I did a quick Twitter Poll today to see if I was the only one bailing out of the CEIP. Currently 85% turns it off, while only 8% enables it. To make your voice heard - head on over here to the poll and I'll update this post in a few days.

    Do you enable Customer Experience Improvement Program (CEIP) on your SharePoint farms?

    At the same time when setting up this farm, and opting out of the CEIP, I also came to the conclusion that I really need to know what information is sent to Microsoft. Perhaps I should opt-in the next time?

    About the CEIP in SharePoint 2010

    When you are opting in to the Customer Experience Improvement Program in SharePoint 2010 you are enabling a daily timer job which inspects and collects information from your farm and sends it to the SharePoint mines in Redmond.

    CEIP Timer Job

    You enable the CEIP on the farm level through Central Administration > System Settings > Configure Privacy Options. Of course there is PowerShell cmdlets to do it as well - Get-SPBrowserCustomerExperienceImprovementProgram and Set-SPBrowserCustomerExperienceImprovementProgram.

    CEIP Settings

    There is also a setting at the Web Application level (General Settings) that allows you to specify if CEIP is enabled on the Web Application or not. When it's enabled on Web Application level the SPWebApplication.BrowserCEIPEnabled is set to true. The ScriptLink control uses this property to output the g_wsaEnabled JavaScript property.

    JavaScript CEIP stuff

    So what is actually collected and happening when CEIP is enabled?

    This was my big question and as always I'm quite curious and just had to find out! So here we go - let's check out exactly what the CEIP is sending over to Microsoft.

    The CEIP timer job

    The CEIP timer job, SPSqmTimerJobDefinition, runs every night and iterates over all you content Web Applications and their databases respectively and sends the details through some methods defined in the onetnative.dll. The timer job performs the following tasks:

    1. Performs write test to a few directories in the SharePoint Root.
    2. Collects the following on all content databases in the farm (all summed to a farm total - so no details about each database or site)
      1. Size of content db
      2. The number of lists
      3. The number of webs
      4. The number of sites
      5. Information about alerts
    3. Collects information about if recycle bin is enabled and the retention period (only average retention time is sent)
    4. Collects information about the list throttling
    5. Collects the number of solutions in the farm, just the number - no more info than that
    6. Checks the registry for information about the server; is it a stand-alone, WFE or application server
    7. Collects a hash value of your Farm Id (interesting!)
    8. Collects the build version
    9. Collects the number of servers in the farm
    10. Collects the number database servers in the farm
    11. Retrieves the install type from the registry (clean, repair, V2V inplace, V2V gradual, B2B upgrade, uninstall, SKU2SKU upgrade)
    12. Collects information from the configuration database
      1. Product version and edition
      2. SQL type (embedded, Express etc)
    13. Finally it collects information about the number of virtual servers (not virtual machines)
    14. Server language and version (actually through some API's marked as obsolete)

    That's it, it's a lot of information but nothing about content or anything that can identify or risk your data. The only thing that might identify you is the hashed code of you server farm id. But hashes are one-way and not guaranteed to by unique - so there's no risk there. It would be awesome to see some average values from the CEIP program.

    The browser CEIP

    If you enable the CEIP on the Web Application level I told you that a specific JavaScript variable is defined. And if this one is set to true - then the Ribbon makes some JavaScript magic (in SP.Ribbon.js). For every command that is executed in the fluent UI this is gathered by the CEIP JavaScript methods and sent to the local /_layouts/WsaUpload.ashx ASP.NET handler. The information gathered here includes:

    • Command Id of the command
    • Current Tab id
    • List and Page information
    • Time and duration

    This one surprised me - I did not actually know that this actually was recorded. Must be huge amounts of data recorded and sent to the Redmond data centers. Hopefully they get something useful from this! Also here, it would be really cool to see some data - for instance how much Ribbon customizations have been done!

    Summary

    This whole excursion actually this makes me very confident in opting in on this in the future! You don't give away any data or put your farm under any risk. And it's no performance killer as I see it either - except for the browser CEIP - this will impact your farm since it will constantly hit the wsaupload.ashx file.

  • Working with URLs in SharePoint 2010 JavaScripts

    Tags: Scripting, SharePoint 2010

    The SharePoint 2010 user interface relies heavily on JavaScripts, just take a look at the Ribbon which is completely generated by a bunch of JavaScripts. Often customizations of SharePoint also involve JavaScripts. You need it to open modal dialogs, add notifications, create Ribbon Page Components etc. etc.. JavaScript is just one of the programming languages you must know as a SharePoint developer - and you can do amazing stuff with it (just take a look at SPServices by Marc D Anderson).

    SharePoint 2010 JavaScript awesomeness

    In SharePoint 2010 the SharePoint product team (finally) spent some time making a nice and decent JavaScript API (not just the ECMAScript Client Object Model stuff). This API contains quite a few nuggets and gems that can be used to simplify the SharePoint JavaScript tasks. Unfortunately they are not well documented if at all, but fortunately they have me to do it for them. In this post I will show you some good scenarios where you can take advantage of using the SharePoint 2010 JavaScript API.

    Application Page links

    Many SharePoint solutions contains application pages (aka layout pages) that are used for different administrative tasks. A good approach is to open these application pages using the Modal Dialog Framework. To redirect the user to an application page using JavaScript or open a Modal Dialog box with an application page, you need to construct the URL in JavaScript. This is often done using string concatenation using the current site URL and application page URL - but here's a better way:

    You can use the SP.Utilities.Utility.getLayoutsPageUrl(pageName) method to get the correct URL to the application page. For instance like this.

    var layoutsUrl = SP.Utilities.Utility.getLayoutsPageUrl('DemoPage.aspx');
    var options = {
      title: "My Dialog",
      url: layoutsUrl
    }
    SP.UI.ModalDialog.showModalDialog(options);

    Using this method you will always get the correct application page URL to your page in the correct site. If you are using localized versions of the application page there is a localized equivalent of the method called SP.Utilities.Utility.getLocalizedLayoutsPageUrl(pageName) to use.

    Concatenating URLs

    Once you have the link to your application page you most often need to send parameters to it, such as the current list id or the item id. That's when you start concatenating strings again. Not that difficult, but you need to take care of encoding of the values.

    To build URLs you can use the SP.Utilities.UrlBuilder JavaScript object. This object contains quite a few useful methods. First of all it contains three"static" methods:

    • url = SP.Utilities.UrlBuilder.replaceOrAddQueryString(url, key, value): This method takes a URL as input and a query string key-value pair. It either appends the query string key-value pair or replaces the value of an existing key. It returns the modified URL as a string
    • url = SP.Utilities.UrlBuilder.removeQueryString(url, key): This method removes a query string key and value pair from a URL and returns the modified string.
    • url = SP.Utilities.UrlBuilder.urlCombine(url1, url2): Combines the two URLs, making sure that there are no redundant slashes when merging them.

    You can also use the UrlBuilder as an object. Take a look at this sample:

       1:  var layoutsUrl = SP.Utilities.Utility.getLayoutsPageUrl('DemoPage.aspx');
       2:  var urlBuilder = new SP.Utilities.UrlBuilder(layoutsUrl);
       3:  var listId = new SP.Guid(SP.ListOperation.Selection.getSelectedList());
       4:  urlBuilder.addKeyValueQueryString('list', listId.toString('B'));                
       5:  var options = {
       6:      title: "My Dialog",
       7:      url: urlBuilder.get_url()
       8:  }
       9:  SP.UI.ModalDialog.showModalDialog(options);

    It's the same sample as before but this time we add a parameter to the dialog URL with the currently selected List ID. On line 2) a UrlBuilder object is created from the application page URL. In line 3) I use another SharePoint JavaScript object called SP.Guid, which is very similar to the .NET System.Guid object, to store the currently selected list ID. The list ID is then added to the UrlBuilder object using the addKeyValueQueryString() method, on line 4). This method makes sure that both the key and value are correctly URL encoded. Finally in line 7) the URL is retrieved from the UrlBuilder object.

    Note: You must encode Guids when they are formatted with curly brackets. Curly brackets are according the the specification of URLs not allowed. If you're only been developing for IE previously that's not a problem, since IE can handle it anyways But better be safe than sorry...

    The UrlBuilder contains the following methods and properties:

    • combinePath(path): appends a path to the UrlBuilder path
    • addKeyValueQueryString(key, value): adds a key-value query string pair to the Url and correctly encodes the key and value
    • get_url() or toString(): returns the URL as a string

    With these tools in your hands you should be able to produce safe and correct URLs at all time when building JavaScripts for SharePoint 2010.

  • SharePoint 2010 Ribbon Controls - Part 8 - The Spinner Control

    Tags: SharePoint 2010

    Back again (sorry about the delay) with a new part in the SharePoint 2010 Ribbon Controls series (all parts available here). This time I'm going to show you an interesting control - the Spinner control.

    What is a Spinner control?

    The spinner is an up/down (increase/decrease) control with some smart abilities to handle different units. For instance it is used when setting image and table sizes in the default ribbon. The Spinner control has a value (number) and a unit (pixel, percent, points etc.) and three ways to modify the value; manual or using the up and down buttons.

    The Spinner control

    Sample Spinner control

    The following Server Ribbon XML can be used to define a Spinner control.

    Spinner Id="Wictor.RibbonControls.Tab.SpinnerGroup.Spinner1"
                Sequence="10"
                AccelerationInterval="500"
                AltDownArrow="Up"
                AltUpArrow="Down"
                Command="SpinnerCommand"
                DefaultUnit="meter"
                DefaultValue="100"
                MultiplierInterval="2"
                QueryCommand="SpinnerQueryCommand"
                TemplateAlias="section2">
        Unit Name="meter"
                DecimalDigits="2"
                Interval="1"
                MaximumValue="1000"
                MinimumValue="0">
            UnitAbbreviation Sequence="1" Value="m"/>
        Unit>
        Unit Name="feet"
                DecimalDigits="1"
                Interval="1"
                MaximumValue="3000"
                MinimumValue="0">
            UnitAbbreviation Sequence="1" Value="ft"/>
        Unit>
    Spinner>

    Spinner control properties

    Just as with the most of the other controls the Spinner controls shares some properties such as Id and Sequence. The control can have a tooltip which are used as in the TextBox control.

    Property TemplateAlias

    The TemplateAlias must match a group template with a display mode set to Medium.

    Property AltDownArrow and AltUpArrow

    The AltDownArrow and AltUpArrow properties are used as alternative texts for the down and up buttons in the control.

    Property AccelerationInterval

    The AccelerationInterval sets how many milliseconds it is between an increase or decrease of values when the up or down buttons are pressed.

    Property MultiplierInterval

    The MultiplierInterval specifies how fast the value increment/decrement is increased or decreased.

    Property DefaultValue

    The DefaultValue property specifies the default value of the Spinner control (not including the unit).

    Property DefaultUnit

    The DefaultUnit property specifies which unit is the default one. Units are defined as sub-elements to the Spinner control element (see example above). Each unit have a name and one or more abbreviations (the UnitAbbreviation sub-element), maximum and minimum values, the number of decimals and an increase/decrease interval.

    Property QueryCommand

    The QueryCommand property is used to specify the query command of the control. That is the command executed when the tab receives focus or when the Command UI is refreshed. The properties JavaScript object contains two properties Value and Unit, which can be used to set the default value. See later down for an example.

    Property Command

    The Command property declares the command that is called when the value changes either by manually entering a new value or when the up/down buttons are clicked. The properties JavaScript object has four different parameters:

    • ChangedByMouse: set to true if the command is invoked from a mouse-click on the up/down buttons, otherwise false
    • ChangeType: have three possible values: 'manual' - when a value is entered manually, 'increase' - the value is increased by the up button or pressing the up-arrow key and 'decrease' - click on down button or down-arrow key.
    • Unit: the name of the current unit
    • Value: the current value

    For a better understanding of how it works with units - take a look at this sample. You all know that metric system is a broadly used standard - but as with all standards some invent their own (opening up for a bunch of Open Xml discussion here...). I have no problem with this, so assume I need to input height in a Spinner control. Limiting users to enter the value in meters is probably not a good solution if I'd like to sell it on a global market. So why not let users enter the height in feet as well. This sample always present the value in meters but allows users to enter the value in feet and automatically convert it correctly.

    handleCommand: function (commandId, properties, sequence) {
        switch (commandId) {
            case 'SpinnerCommand':
                if (properties.ChangeType == "manual" && properties.Unit == "feet") {
                    this.newSpinnerValue = properties.Value * 0.3048;
                    this.newSpinnerUnit = "meter";
                    RefreshCommandUI();
                }
                return true;
            case 'SpinnerQueryCommand':
                if (this.newSpinnerValue != null) {
                    properties.Unit = this.newSpinnerUnit;
                    properties.Value = this.newSpinnerValue;
                    this.newSpinnerUnit = null;
                    this.newSpinnerValue = null;
                }
                return;
        }
        return false;
    },
    newSpinnerValue: null,
    newSpinnerUnit: null,

    When a user changes the value the SpinnerCommand command is sent to handleCommand. Here I check if it is a manual entry and if the Unit is set to feet. If so the routine converts the value to meters and stores that in two Page Component local variables before it refreshes the command UI. When the Command UI is refreshed the query command for the Spinner control is fired and in that routine I see that the local variable is set and then update the Spinner control with the new value and unit.

    Summary

    The Spinner control is a very handy control which also gives you a really good way to work with number values and optionally units. This was the last post of the "easy" controls. Next up is the DropDown control which is used to create drop-downs and menu controls.

  • Summary page of my recommended links and tools for SharePoint 2010 classes

    Tags: SharePoint 2010

    SNAGHTML130c0c5I've just published a page, which I plan to update regularly, containing links to web sites, tools, products, solutions, articles, posts, books etc. which I recommend and talk about during my SharePoint 2010 classes.

    You can find the page here: Class Links

    If I did promise you during my classes to add a link to it and have forgotten - drop me an e-mail and remind me.

  • SharePoint 2010 Ribbon Controls - Part 7 - The ToggleButton control

    Tags: SharePoint 2010

    Back with another SharePoint 2010 Server Ribbon Controls post, this time a shorter one, compared to previous posts. We'll take a look at the ToggleButton control.

    I know I said I'm going to talk about the DropDown in this post, but I'd reconsidered and take the easy ones first - since the DropDown control will be divided into several posts.

    What is a ToggleButton control?

    The ToggleButton control is very similar in behavior to the Button control with the difference that you can toggle the state of the button; it can either be on or off.

    The ToggleButton

    When the ToggleButton has the On state it has an alternate background color.

    Sample ToggleButton control

    This is how a ToggleButton can be implemented in a CustomAction:

    ToggleButton Id="Wictor.RibbonControls.Tab.ToggleButton1"
        TemplateAlias="section1"
        Alt="Alt Button text"
        Command="Wictor.RibbonControls.ToggleButtonCommand"
        QueryCommand="Wictor.RibbonControls.ToggleButtonQueryCommand"    
        Description="Description"
        LabelText="A ToggleButton"
        Sequence="10"
        Image16by16="/_layouts/Images/Wictor.RibbonControls/Wictor.RibbonControls.png"
        Image16by16Left="0"
        Image16by16Top="-32"
        Image16by16Class="ButtonClass16"
        Image32by32="/_layouts/Images/Wictor.RibbonControls/Wictor.RibbonControls.png"
        Image32by32Left="0"
        Image32by32Top="0"
        Image32by32Class="ButtonClass32"
        LabelCss="BtnLabelClass"
        ToolTipImage32by32="/_layouts/Images/Wictor.RibbonControls/Wictor.RibbonControls.png"
        ToolTipImage32by32Left="0"
        ToolTipImage32by32Top="0"
        ToolTipImage32by32Class="ButtonTTClass"
        ToolTipDescription="A nice and shiny ToggleButton"
        ToolTipHelpKeyWord="RibbonControls"
        ToolTipShortcutKey="ALT + B"
        ToolTipTitle="This is a ToggleButton"
        />

    ToggleButton control properties

    The ToggleButton is very similar to the Button control and also the properties are the same, so before proceeding read about the Button control. The properties documented below are only the ones differing from the Button control or not available for the Button control. The only property from the Button control that is not available in the Button control is the CommandType.

    Property Command

    Just as for a Button control the Command command is executed when someone clicks the ToggleButton. In the JavaScript method that handles the command the state (On or Off) can be retrieved for the ToggleButton. You check the value of the ToggleButton like this in a JavaScript Page Component:

    handleCommand: function (commandId, properties, sequence) {
        switch (commandId) {
            case 'Wictor.RibbonControls.ToggleButtonCommand':
                if(properties.On == true) {
                    alert('ToggleButton state is On');
                } 
                else {
                    alert('ToggleButton state is Off')
                }
                return true;
        }
    }

    Property QueryCommand

    The QueryCommand is invoked when the Tab is loaded and you can use it to set the initial state of the ToggleButton like this:

    handleCommand: function (commandId, properties, sequence) {
        switch (commandId) {
            case 'Wictor.RibbonControls.ToggleButtonQueryCommand':
                // set initial state to on
                properties.On = true;
                return true;
        }
    }

    Summary

    The ToggleButton is as you've seen very similar to the Ribbon control and it is a great alternative to the CheckBox control when you need to handle on/off states. Before diving into the advanced (menu) controls we'll take a look at the Spinner control in the next part.

  • SharePoint 2010 Ribbon Controls - Part 6 - The CheckBox control

    Tags: SharePoint 2010

    Welcome back to part 6 of my SharePoint 2010 Ribbon Controls series (full series index can be found here). This time we'll take a look at the CheckBox control.

    What is the CheckBox control?

    If you've not been hiding under a rock you should now what a CheckBox is - it's a box you can check. It can have two states - checked or not checked.

    CheckBoxes

    Sample CheckBox control

    A CheckBox can look like this when implemented in the Ribbon:

    CheckBox Id="Wictor.RibbonControls.CheckBoxes.CheckBox1"
        LabelText="Check here!"     Command="Wictor.RibbonControls.CheckBoxCommand"
        QueryCommand="Wictor.RibbonControls.CheckBoxQueryCommand"
        Sequence="10"
        TemplateAlias="section2"
        ToolTipDescription="To check or not to check, that's the question"
        ToolTipImage32by32="/_layouts/Images/Wictor.RibbonControls/Wictor.RibbonControls.png"
        ToolTipImage32by32Left="0"
        ToolTipImage32by32Top="0"
        ToolTipImage32by32Class="CBTTClass"
        ToolTipHelpKeyWord="RibbonControls"
        ToolTipShortcutKey="ALT + C"
        ToolTipTitle="Checkitycheck"/>

    CheckBox control properties

    The CheckBox is not that different than the previous controls I've shown you.

    Property TemplateAlias

    As earlier articles shown you it's important to specify a group template layout with a matching display mode for the TemplateAlias. A CheckBox can have DisplayModes set to only Medium or Small. Medium will show the CheckBox including the label (#1 in the image above) and small will only show the CheckBox with the label as tooltip (#2).

    Property LabelText

    This is the label of the CheckBox and written next to the CheckBox when Medium display mode is used.

    Property Alt

    Should be alternative text (never seen this one work though, and not found any trace of it in the generated source code...)

    Property ToolTip????

    See the TextBox control post for more information about tool tips.

    Property MenuItemId

    Used in menus (coming in later posts).

    Property Command

    As usual the Command indicates which command to run when any action is performed on the control - in this case when the CheckBox is clicked. To check if the CheckBox is checked you access the properties.On object which is a boolean (true for checked).

    Property QueryCommand

    The QueryCommand is executed when the tab is selected the first time and it is also fired directly after the Command command. You can use this to set the default value of the CheckBox using the properties.On object.

    A sample implementation of Command and QueryCommand could look like this in a Page Component:

    handleCommand: function (commandId, properties, sequence) {
        switch (commandId) {
            case 'Wictor.RibbonControls.CheckBoxCommand':
                if (properties.On) {
                    alert('Check!');
                }
                break;
            case 'Wictor.RibbonControls.CheckBoxQueryCommand':
                if (!this.checkBoxDefaultSet) {
                    properties.On = true;
                    this.checkBoxDefaultSet = true;
                }
                break;
        }
    },
    checkBoxDefaultSet: false,

    In this sample the QueryCommand uses a local (to the page component instance) variable to check if it is the first QueryCommand that is invoked, and not a QueryCommand succeeding a Command command. It always check the CheckBox when the tab is loaded. When a user checks the CheckBox an alert will be shown.

    Summary

    The CheckBox is a simple yet useful control when building Ribbon customizations. A similar control is the ToggleButton control, which will be discussed in later posts. Next post will be about the DropDown control. Until next time...

  • SharePoint 2010 Ribbon Controls - Part 5 - The Button control

    Tags: SharePoint 2010

    Now it's time for the SharePoint 2010 Ribbon Button Control in the Ribbon Control series (full series index can be found here),

    What is the Button control?

    The Button control needs no further description - it's a button on which the users can click to execute commands. Buttons can exist alone or in menus (which will be covered later in the series).

    Ribbon buttons

    Sample Button control

    A Button control could be implemented as follows:

    Button Id="Wictor.RibbonControls.Tab.Button1"
            TemplateAlias="section1"
            Alt="Alt Button text"
            Command="Wictor.RibbonControls.ButtonCommand"
            CommandType="General"
            LabelText="The Button"
            Sequence="10"
            Image16by16="/_layouts/Images/Wictor.RibbonControls/Wictor.RibbonControls.png"
            Image16by16Left="0"
            Image16by16Top="-32"
            Image16by16Class="ButtonClass16"
            Image32by32="/_layouts/Images/Wictor.RibbonControls/Wictor.RibbonControls.png"
            Image32by32Left="0"
            Image32by32Top="0"
            Image32by32Class="ButtonClass32"
            LabelCss="BtnLabelClass"
            ToolTipImage32by32="/_layouts/Images/Wictor.RibbonControls/Wictor.RibbonControls.png"
            ToolTipImage32by32Left="0"
            ToolTipImage32by32Top="0"
            ToolTipImage32by32Class="ButtonTTClass"
            ToolTipDescription="A nice and shiny button"
            ToolTipHelpKeyWord="RibbonControls"
            ToolTipShortcutKey="ALT + B"
            ToolTipTitle="This is a Button"
            />

    Button control properties

    As you can see from the code sample above the Button control allows for more customizations than the previous discussed controls.

    Property TemplateAlias

    As always with the Ribbon controls you have to make sure that you use a Group Template Layout with a DisplayMode that fits the control. The Button can have the Large, Medium and Small display modes, shown in the figure above as #1, #2 and #3 respectively. When a Button is used in menus, discussed later on in the series, more display modes can be used.

    Property LabelText

    This is the label of the Button and is shown in Large and Medium display modes.

    Property LabelCss

    Specifies a CSS selector class for the label of the Button control

    Property Alt

    Alternative text for the button.

    Property Image16by16????

    Used for Medium and Small display modes. See post about common control properties for more information.

    Property Image32by32????

    Used for the Large display mode. See post about common control properties for more information.

    Property ToolTip????

    See the TextBox control post for more information about tool tips.

    Property Command

    The Command specifies the command executed when the Button is clicked. You can use it as follows in the Page Component handleCommand method:

    handleCommand: function (commandId, properties, sequence) {
        switch (commandId) {
            case 'Wictor.RibbonControls.ButtonCommand':
                alert('Button: ' + properties['SourceControlId']);
                // Do some funky stuff here...
                return;
        }
    }

    The properties object contains three properties:

    • SourceControlId - The Id of the Button control clicked (good if you use the same command for several buttons)
    • MenuItemId - The MenuItemId (only used in Menus, see below)
    • CommandValue - The CommandValueId (only used in Menus, see below)

    Property Description

    This Description property is only used when the button is present in a menu and not in stand alone mode. The display mode must be set to Menu32 to show the Description.

    Property CommandType

    The CommandType can have the following values:

    • General - default value, if attribute is omitted - plain ol' button
    • OptionSelection - used in menus to create selectable options (now you're curious - but I've said menus later...)
    • IgnoredByMenu - also used in menus, a click on these does not close the menu

    Properties MenuItemId, CommandValueId

    A string identifier and a string command value only used in menus

    Summary

    That's all about Buttons - not that advanced but as you see they get more interesting in menus. Next post coming soon to a blog reader near you will be CheckBox control.

  • SharePoint 2010 Ribbon Controls - Part 4 - The TextBox Control

    Tags: SharePoint 2010

    Welcome back to another post in the SharePoint 2010 Ribbon Controls series (full series index available here). Now it is time to introduce the TextBox control, which can be used to allow users to enter text information in your Ribbon customzations.

    What is the TextBox control?

    If you're familiar with .NET development (WinForms or ASP.NET) then you already know what a TextBox is. It allows your users to enter and change text.

    Text boxes

    TextBoxes are often accompanied by Label controls which have the ForId set to the Id of the TextBox to enhance the user interface.

    Sample TextBox control

    A TextBox could be defined in XML like this:

    TextBox Id="Wictor.RibbonControls.Tab.TextBox"
        Command="Wictor.RibbonControls.TextBoxCommand"
        QueryCommand="Wictor.RibbonControls.QueryTextBoxCommand"
        TemplateAlias="section2"
        Width="100"
        MaxLength="20"
        Sequence="10"
        ToolTipImage32by32="/_layouts/Images/Wictor.RibbonControls/Wictor.RibbonControls.png"
        ToolTipImage32by32Left="0"
        ToolTipImage32by32Top="-48"
        ToolTipImage32by32Class="TextBoxTTClass"
        ToolTipDescription="A box where you can enter text"
        ToolTipHelpKeyWord="RibbonControls"
        ToolTipShortcutKey="J"
        ToolTipTitle="This is a textbox"
        ShowAsLabel="false"
        ImeEnabled="true"
        />

    TextBox control properties

    Part from the common properties such as Id and Sequence the following properties can be set:

    Property TemplateAlias

    As for most of the controls you have to know which DisplayModes a control can use. The TemplateAlias for the TextBox must be connected to a Layout row/section with a DisplayMode that has the Medium value.

    Property Width

    The Width property does exactly what it says - it sets the width of the TextBox (in pixels).

    Property MaxLength

    The MaxLength property sets the maximum number of characters allowed in the TextBox.

    Property ShowAsLabel

    ShowAsLabel is a boolean that controls if the TextBox should be rendered as a text box or just a Label. In the image above #1 is a standard TexBox but #2 is a TextBox with ShowAsLabel set to true. Kinda weird - you could use a Label control instead.

    Property ImeEnabled

    If the ImeEnabled is set to true then the Input Method Editor (IME) is set to an active state. Useful when working with Asian languages.

    Property QueryCommand

    The QueryCommand is invoked when Tab is getting focus or after a Command command. It is normally used to set the default value of the TextBox. You also need to use the QueryCommand to set the value in the text box if the ShowAsLabel property is set to true. This is how to set it using the handleCommand Page Component method:

    handleCommand: function (commandId, properties, sequence) {
        switch (commandId) {
            case 'Wictor.RibbonControls.QueryTextBoxCommand':
                if(null == properties['Value']) properties['Value'] = 'Default value';
                return;
        }
    }

    Property Command

    The Command is invoked when the control looses focus (such as selecting another control or pressing a button). You can use this to do calculations or directly store values. Directly after the Command invocation the QueryCommand is invoked. Here is a snippet that converts the value of a text box to upper case:

    handleCommand: function (commandId, properties, sequence) {
        switch (commandId) {
            case 'Wictor.RibbonControls.TextBoxCommand':
                properties['Value'] = properties['Value'].toUpperCase();
                return;
        }
    }

    Property ToolTipTitle

    The ToolTipTitle contains a string value for the tooltip of the TextBox. The image below show how tooltips looks like in the Ribbon. The ToolTipTitle is #1.

    Tooltip

    Property ToolTipDescription

    The ToolTipDescription represents the description of the tooltip. It's #2 in the image above.

    Property ToolTipImage32by32, ToolTipImage32by32Left, ToolTipImage32by32Top, ToolTipImage32by32Class

    These properties represents the icon shown in the tooltip (#3 in the image above). It must be a 32x32 pixel icon and works as icons previously described in the series.

    Property ToolTipShortcutKey

    The ToolTipShortcutKey (#4) represents the character/key for keyboard shortcuts.

    Property ToolTipHelpKeyword

    If you need to include help for your TextBox that takes more than a title or description, then you can use the built-in context sensitive help in SharePoint, which is a really cool feature, see #5 in the image above. Read more about how to configure context sensitive or custom help collections in SharePoint 2010 in the Customizing SharePoint 2010 Help post by the Microsoft SharePoint End-User Content Team. The value in this property must correspond to the Product property of the Help Collection in the custom help.

    Custom help

    Summary

    Using TextBox controls allows you to easily allow users to write input text in your Ribbon customizations; for example in a contextual aware Web Part Ribbon customization. In the next post I'll show you the Button control

  • SharePoint 2010 Ribbon Controls - Part 3 - The Label Control

    Tags: SharePoint 2010

    The first control in the SharePoint 2010 Ribbon Controls series (full series index available here) will be about the Label control.

    What is the Label control?

    The Label control is a simple control that allows you to add a Label to any of your Ribbon groups. Labels are most often used in combination with other controls such as text boxes and drop downs. You can using a label target another control so that if you click on the label then the other control gets focus. A Label can be a text, an icon or both.

    Label Controls

    As the image above shows Labels can have three forms:

    1. Just a text label
    2. A text label with an icon
    3. Just an icon

    Sample Label control

    This is how a Label control could be defined:

    Label 
      Id="Wictor.RibbonControls.Tab.Label"
      LabelText="Label Text"
      Image16by16="/_layouts/Images/Wictor.RibbonControls/Wictor.RibbonControls.png"
      Image16by16Left="0"
      Image16by16Top="-32"
      Image16by16Class="LabelClass"    
      TemplateAlias="section2"
      ForId="Wictor.RibbonControls.Tab.TextBox"
      Command="Wictor.RibbonControls.LabelComand"
      QueryCommand="Wictor.RibbonControls.LabelQueryCommand"
      Sequence="10"/>

    Label control properties

    The Label control have a few properties worth noticing, except the common ones.

    Property: LabelText

    The LabelText property is the text that is displayed in the label.

    Property: Image16by16, Image16by16Top, Image16by16Left, Image16by16Class

    A Label can have one16x16 pixel sized icon and/or CSS class.

    Property: TemplateAlias

    The TemplateAlias (one of the common properties) must be configured so that is connected to a section in the Group Template that has the DisplayMode of either Medium or Small. Any other Display Modes will cause your Ribbon customization to fail. The LabelText, TemplateAlias and icon determines the layout of the Label:

    • A Small DisplayMode must have an icon and will only show the icon (only text on a small Label will cause an error). Label #3 in the image above
    • A Medium sized icon must have a LabelText and optionally an icon. Label #1 and #2 in the image above.

    Property: ForId

    The ForId property is the Id of another Ribbon control. When the Label is selected the control specified by the ForId will get focus.

    Property: Command

    The Command property is never used by the Label control.

    Property: QueryCommand

    The QueryCommand property invokes the command when the Tab containing the control receives focus. This can be used to dynamically update the value of the LabelText. In a JavaScript Page Component you update the LabelText as follows, if the QueryCommand has the value of 'Wictor.RibbonControls.LabelQueryCommand':

    handleCommand: function (commandId, properties, sequence) {
        switch (commandId) {
            case 'Wictor.RibbonControls.LabelQueryCommand':
                properties['Value'] = 'Label changed';
                return;
        }
    }

    When the Tab receives focus the Label will change its LabelText to the value specified in the JavaScript.

    Summary

    That was the first one - the Label control. Next time we'll add a TextBox which will be connected to the Label using the ForId property.

  • SharePoint 2010 Ribbon Controls - Part 2 - Common Control Properties

    Tags: SharePoint 2010

    This first real post in the SharePoint 2010 Ribbon Controls series (full series index available here) will be about some of the common properties that most or all of the Ribbon controls shares. I assume that you have some basic knowledge of SharePoint 2010 Ribbon customization, if not check out one of my previous posts.

    What is a Ribbon control?

    A SharePoint 2010 Ribbon Control is the interactive parts of the Ribbon. Controls exits within a Group (B) within a Tab (A). The controls can be labels, buttons, drop downs, menus, galleries and more. You can add, remove or change default Ribbon controls or add completely new Tabs and Groups.

    Ribbon controls

    The default Ribbon interface is defined in CMDUI.xml which is located in the {SharePoint Root}\TEMPLATE\GLOBAL\XML. A good tip is to take a look at the default Ribbon configuration before making your own Tabs and Groups - but never ever change the CMDUI.xml file!

    In the image above you see some common controls;

    1. This is a MRUSplitButton control, which contains a submenu with different items
    2. This is a SplitButton, also with a submenu
    3. This is a ComboBox
    4. This is a ToggleButton

    In this series we will take a look at each one of those controls, to be exact I'll show you all available controls in the Ribbon.

    All SharePoint 2010 Ribbon customization is done through XML, there are a couple of ways to add them - statically or dynamically, but the XML are the same. The controls must be children of a Controls element within a CommandUIDefinition, Group or MenuSection element (all defined in the Server Ribbon Schema). Some are are more advanced than others.

    Common control properties

    All controls have a set of properties that works basically the same. Instead of repeating them for all posts in this series I will walk you through them once and for all before I go in to the specific control properties. Some of these properties will be repeated to discuss specifics for the respectively controls.

    Property: Id (required)

    The Id property of a control is one important and sensitive little guy. It's a string value and must be unique within your Ribbon customization. Not specifying it or not making it unique can make your whole customization fail without any good error messages.

    I prefer using a "namespace" style of control Id's so that I easily can find out where the control belongs. Preferably prepend the control id with the id of the Tab or Group.

    What's your Id?

    Property: Sequence

    The Sequence property states in what order the controls should appear in overflow sections. It's not required but if present it must be an integer.

    Property: TemplateAlias

    The TemplateAlias property is used to specify which template alias to use from the Group Template Layout. That is how the control is positioned, which section or row. This property must be a string value corresponding to one of the aliases defined in the group template layout.

    TemplateAlias

    Important here is to make sure that your control can handle the DisplayMode of the specified TemplateAlias.

    NOTE: Make sure that you always create your own Group Templates. Read AC's post about it here: http://www.andrewconnell.com/blog/archive/2010/10/10/always-create-your-own-group-templates-with-sharepoint-ribbon-customizations.aspx

    Property: ImageXXbyXX, ImageXXbyXXTop, ImageXXbyXXLeft, ImageXXbyXXClass

    These properties are used to specify an image/icon for a control, it is not used by all control types but you can expect them to be used on Labels and Buttons. Different controls use different sizes (the XX's in the header) - it's either 16x16 or 32x32. Which one used is defined by the DisplayMode of the template alias. The ImageXXbyXX specifies a URL to an image. ImageXXbyXXTop and ImageXXbyXXLeft is used when you use CSS sprites to select the position of the icon from the composite image (example below). The ImageXXbyXXClass is used to set a specific CSS class to the control - for instance if you prefer to use CSS to create the image layout.

    Stylish control

    Property: Command

    All controls have a Command property which specifies the command to run when for instance a button is pressed. This is a string defining the command. If you use declarative commands, that is defined in the XML using CommandUIHandler elements, then the CommandUIHandler with the corresponding Command attribute will be invoked. If you instead use page components then Command value is handled by the handleCommand JavaScript function of the page component. I will show you more about this in upcoming samples.

    Property: QueryCommand

    The QueryCommand works just the same as the Command property with the difference that it is invoked when the Tab is getting focus. The function is also invoked directly after the Command command. You can use this one to set values of the controls.

    Summary

    So now we've started this series for real. Keep on reading, next post will come shortly, and that one is about the Label control.

  • SharePoint 2010 Ribbon Controls - Part 1 - Summary

    Tags: SharePoint 2010

    Welcome to 2011, this will for sure be an exciting year! I thought I start this year off with a series of blog posts about the different controls that can be used in the SharePoint 2010 Ribbon. Hopefully a bit better than the current MSDN documentation.

    The series will discuss each control that are available for usage in the SharePoint 2010 Ribbon and show you through examples and code how to use them. I will even throw in one or more tips and tricks along the road.

    SNAGHTML173f702

    So if you're interested - watch my Twitter account (http://twitter.com/wictor) and/or follow my RSS feed (http://feeds2.feedburner.com/WictorWilen) for new posts in the series.

    Parts

    This post is a summary post that I will update with the correct links as the series progress.

    I don't know yet, but it will possibly be some follow-ups depending on your comments and questions. If you have them already - then don't hesitate to fire them away. Also expect some changes to the outline above...

About Wictor...

Wictor Wilén is the Nordic Digital Workplace Lead working at Avanade. Wictor has achieved the Microsoft Certified Architect (MCA) - SharePoint 2010, Microsoft Certified Solutions Master (MCSM) - SharePoint  and Microsoft Certified Master (MCM) - SharePoint 2010 certifications. He has also been awarded Microsoft Most Valuable Professional (MVP) for seven consecutive years.

And a word from our sponsors...