Archives

Archives / 2011 / February
  • 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.

AWS Tracker

About Wictor...

Wictor Wilén is a Director and SharePoint Architect working at Connecta AB. 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 four consecutive years.

And a word from our sponsors...

SharePoint 2010 Web Parts in Action