Johan Leino

// TODO: Add clever comment about the focus of this blog…

Avoiding serialization issues in SharePoint property bags by using JSON

Storing application settings in a SharePoint solution can be done in numerous ways. One of the more robust solutions is to use the property bags that exist all throughout the hierarchy of the SharePoint object model.

The only real issue that we have in all of these property bags are that we can store any value of any type as long as it can be serialized. “…as long as it can be serialized…”

SharePoint property bags provide an easy-to-use storage mechanism, but developers risk corrupting the configuration database or the content database if they attempt to persist non-serializable types.

One excellent way to get around some of these issues is to use PnP’s SharePoint Guidance (SPG) framework. Even though you do you might still have issues serializing types. Especially when you use it from the sandbox where you have to get around some of these issues by providing serialization assemblies to go with your sandbox settings (C# classes) that you want to store. Not so straight forward I would say.

One thing you can be sure of though is that you can always store a string without getting into these serialization issues. And what notation that can work as classes but internally is just a string??

That’s right…Json

So, despite if you use SPG (which you can and probably should combine with the following solution) or not…if you store values as Json (strings) you’ll never get into serialization issues.

JSON.NET to the rescue

I’ll start with a little utilities C# project (SP.Utilities) that will later serve as the repository for reading and writing settings. Now, I will start off by including JSON.NET by James Newton-King via the NuGet package manager.

image

image

No, once that is installed let’s implement a simple solution for storing and retrieving settings in SharePoint.

Basic Architecture

image

Here’s the basic rundown on how I’m going to solve this issue.

  1. In the SP.Utilities project I’m constructing an extension method, Settings(), on the SPWeb class that returns
  2. A local, internal, implementation of the ISettingCollection interface which has all the CRUD operations (GET, SET, etc).
  3. SPWebSettingsCollection is the internal class that does all the magic and that we will look at next.

SPWebSettingsCollection

You will use the extension method called Settings on the SPWeb object which look like this:

image

You can see that from the “outside” you’re just using an interface, ISettingCollection, but internally the actual implementation of that interface is called SPWebSettingsCollection. The SPWeb object is passed along to the SPWebSettingsCollection class in the constructor.

You could potentially make any number of implementations of this interface, and expose them via extension methods, this is just showing you how to make one of them:

    internal class SPWebSettingsCollection : ISettingCollection
    {
        SPWeb m_Web;

        public SPWebSettingsCollection(SPWeb web)
        {
            this.m_Web = web;
        }

        public ISettingCollection Set<TSetting>(string key, TSetting setting) 
            where TSetting : ISetting
        {
            string value = JsonConvert.SerializeObject(setting);
            this[key] = value;

            return this;
        }


        public bool TryGet<TSetting>(string key, out TSetting setting) 
            where TSetting : ISetting
        {
            bool output = false;
            setting = default(TSetting);

            if (this.Contains(key))
            {
                try
                {
                    setting = this.Get<TSetting>(key);
                    output = true;
                }
                catch (Exception e)
                {
                    // TODO: add logging
                }
            }

            return output;

        }




        public TSetting Get<TSetting>(string key) where TSetting : ISetting
        {
            string value = this[key];
            return JsonConvert.DeserializeObject<TSetting>(value);
        }

        public string this[string key]
        {
            get
            {
                return this.m_Web.AllProperties[key] as string;
            }

            set
            {
                if (this.Contains(key))
                {
                    this.m_Web.SetProperty(key, value);
                }
                else
                {
                    this.m_Web.AddProperty(key, value);
                }
                Update();
            }
        }

        public bool Contains(string key)
        {
            bool exists = false;
            if (this.m_Web.AllProperties.Contains(key))
            {
                exists = this.m_Web.AllProperties[key] != null;
            }
            return exists;
        }

        private void Update()
        {
            this.m_Web.Update();
        }


        public ISettingCollection Delete(string key)
        {
            if (this.Contains(key))
            {
                this.m_Web.DeleteProperty(key);
                Update();
            }

            return this;
        }
    }

Have a look at the highlighted lines (13 and 49).

On line 13, when an object comes in to be stored I’ll start by serializing it into Json (a string that is) before storing it in the SPWeb’s property collection.

And on line 49, deserialize it back from a Json string into the actual C# object. All of this made possible by using JSON.NET

I’m not going to go through all the methods by I think you get the idea right?

Make a quick test with a console application

Let’s make a quick console application to see if the concept works then.

First of all there is a class, ColorSetting, that we’ll use to store a color (simple enough test). It implements a “marker” interface, ISetting, simply because want I to be able to enforce things on settings later on. (optional of course)

    class ColorSetting : ISetting
    {
        public string DefaultColor { get; set; }
    }

    class Program
    {
        const string ColorSettingKey = "johanleino.com.ColorSetting";

        static void Main(string[] args)
        {
            using (SPSite sitecollection = new SPSite("http://www.johanleino.com"))
            {
                SPWeb web = sitecollection.RootWeb;

                web
                    .Settings()
                    .Set<ColorSetting>(ColorSettingKey, new ColorSetting
                    {
                        DefaultColor = "#000000"
                    });

                var color = web
                     .Settings()
                     .Get<ColorSetting>(ColorSettingKey);

                System.Console.WriteLine("The default color of johanleino.com is: {0}", color.DefaultColor);


                color.DefaultColor = "#333333";

                web
                    .Settings()
                    .Set<ColorSetting>(ColorSettingKey, color);

                var updatedColor = web
                                    .Settings()
                                    .Get<ColorSetting>(ColorSettingKey);

                System.Console.WriteLine("The new default color of johanleino.com is: {0}", updatedColor.DefaultColor);
            }

            System.Console.Read();
        }
    }

The code does in short:

Store setting with value #000000 –> get the setting and print the value –> update the setting with value #333333 –> store the updated setting –> get the setting again and print the new value

image

How about the Sandbox?

You could leave it as it is now and it will work in a farm solution situation.

But I’m taking it one step further though and making this work from a sandbox solution since (as a stated at the beginning of this post) that’s usually where you’ll have serialization issues.

So, from the sandbox you basically have two options. One of them is to construct a proxy (but if you do that you you to make some changes to the extension method…maybe another post). The second option is to deploy the SP.Utilities dll via a farm solution and use it from the sandbox code. I’m showing the second option here.

In short: Add SP.Utilities + Json.NET to GAC via a farm scoped WSP.

From a new sandbox project I have a feature which will store a setting in the feature activating event:

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {               

            SPWeb web = properties.UserCodeSite.RootWeb;

            web
                .Settings()
                .Set<SiteSetting>("johanleino.com.SiteSetting", new SiteSetting
                {
                    Creator = "Johan Leino"
                });
        }

Same idea as before (in the console) but this time I’m storing a setting called SiteSetting which have a property for Creator. Now if you run this code you will see:

“Error occurred in deployment step ‘Activate Features’: Unhandled exception was thrown by the sandboxed code wrapper’s Execute method in the partial trust app domain: An unexpected error has occurred”

That’s because a sandbox solution is a partial trust caller. So to SP.Utilities you have to add this:

image

To test the setting once it has been added via the feature I’ll add a simple web part to display the value of the setting:

image

Build –> Deploy –> Add web part to a page and…:

image

TADA!!

Easy right!?

Inconvenient: Files inside mapped folder which links to existing items

Problem

You’re working on a SharePoint site for company x in Visual Studio 2010. Your boss tells you that company x uses a graphical profile (css + images) and some javascript files that you “must” include in the new site. The boss also informs you that if you make any changes to these files they have to stay in sync with the originals.

Finally:
“And I don’t want to see any copy/paste action between these files…keep them in sync with each other OK?!”…the boss tells you.

The main issue is that these files are not included in “your” part of the source control, hence they reside somewhere else in the file structure and you have to find a way to seamlessly include them in your SP solution before you can deploy it.

Hey, I can use “..add existing item” you say and add the files as links to the actual files. Then if I update the files (or someone else does) it will update the original ones also since we’re just adding links to the original ones.

OK, so let’s try that approach then and see what happens then.

Expect to see problems…

Mapped Folders

image

So here’s an example on how this setup might look from a source file (windows explorer) perspective.
You have one folder called JSLib which holds the company.js file which is the file that we will try to include into the other folder johanleino.com which is the actual VS SharePoint project.

What comes to mind here is to use a mapped folder synced to “Layouts” and add the company.js file in there.

image

So, there is a mapped folder in the project already. I’m adding the company JSLib files into that folder (subfolder actually that’s called company-x under johanleino.com…please note that screenshot doesn’t show exactly that though).

image

So, here I’m picking the company.js file from the JSLib folder from the “root” of the source file structure. It’s added as a link into my SP project’s mapped folder named Layouts/johanleino.com/company-x

image

You can see that VS “marks” that file with an icon telling me that the file is linked (the original is not actually in that place…it’s just a link).

So, are we finished now??

Let’s look in the WSP package explorer designer:

image

All files that are in mapped folders (at least a mapped folder that deploys to layouts) are so-called template files (deployment type = templatefile in VS SP tools).
This means that they are deployed somewhere beneath the TEMPLATE directory in the SharePoint root files. This is however not something you can see from the package explorer in VS (as you can see from the image above).

To see the actual deployment location we have to look at the properties for the file (company.js) or package and look in the WSP:

image

As you can see it looks kind of weird (Layouts\..\..\JSLib) and you can’t change that value.
That’s the inconvenience!!

And you guessed right…trying to deploy the file will result in:

image

…no trace of the company.js file or the subfolder I placed it in.

Solution: How to trick Visual Studio

OK, so mapped folders are normally great since we can hook it up directly to a folder in SP root files and it displays like a folder in the VS IDE, it syncs the files, etc etc…

But in this case where we need more control over the deployment we’ll use a “regular” SPI.

image

…add new item on so on (I’ll go with empty element type).

image

I’ve named the SPI JSLib and I’ve completed all the same steps as for the mapped folder approach (add existing item, browse to the file, add as links…etc) so that company.js is included as a link in the SPI.

The next step is to tell VS SP tools that we want to deploy that file as a template file, like:

image

Oops…you might get an exception (just ignore it though).

image

As a result of that exception (or so) you have to “handcraft” the path beneath the TEMPLATE directory where you want this file to end up (which you couldn’t do with the mapped folder files):

image

The final step is to use the package explorer to include the SPI in the packaged output (WSP).
“Move from the left side to the right side…”

image

Package –> Deploy …and:

image

TADA!!

A plus is that the CKS:Dev tools extensions for VS 2010 will also pick this up (hence, you can still use the “copy to SharePoint root command” or “Auto copy on save”)

Enjoy and hope the MS fixes this until VS11 releases…right!?

Getting to know your SharePoint 2010 packaging options

image

Have a look at the image above.

If you’re familiar with working with SharePoint 2010 projects in VS2010 you should know that when you add a new SPI (SharePoint Project Item), like a module|content type|empty item|etc, it’s by default added to a feature of the “correct” scope.
Waldek Mastykarz has more information about this, and a way around it, if you’re interested.

The image below tries to illustrate what happens to your items (in this example an element file) if the feature is removed from the package (if the feature is removed, the SPI is removed from the package…by default that is):

image

So who cares you might say. When will I ever need to pay attention to this?

Well, have a look at the following scenario then…

Issue: adding a root file

What I want to accomplish now is to add a configuration file to the 14/CONFIG folder upon deploying the WSP.
This will be accomplished by adding the configuration file to an empty SPI and setting the deployment type to root file (like shown below).

image

Note that I also needed to change the “default” Path property value to CONFIG (+ subdir if you want one) to make the file end up in the correct place among the 14” folders.

But hey wait a minute now!!

…you might say. You could just use a mapped folder right?

Well, yes you could but there are two reasons why I can’t do that:

  1. I want to make a point that you have to look out in these kinds of situations.
  2. I’m (in an upcoming post I’m working on) using a configuration transformation on this file and I don’t want my CONFIG directory cluttered with configuration files (I’ll show you what I mean in an upcoming post) since you can’t control which files under a mapped folder that are actually included in the WSP ouput. (only code files C#+VB are removed by default)

OK, back on track. If you now package this project up as WSP (without including the SPI in a feature as the default option is) there will be no trace of the configuration file in the WSP (as the packing explorer below shows):

image

Solution: you basically have two options

  1. Include the SPI inside a feature (as shown before)
  2. Use the package manager UI to add it to the WSP (shown below)

image

Now, look at the packing explorer again and you should see this:

image

And subsequently after deploying your package the file appears at the correct place in the root files directory on the server/s.

image

To summarize

Two basic things to take away from this post are:

  1. Get to know your deployment type options (i.e. how does the type of SPI affect your package)
  2. Get to know the packaging explorer and the management UI (it might be useful to alter the VS packaging system sometimes)

2011 in review

One more year has passed and looking at the stats from past year two things to notice are that I blogged less (18 compared to 26) times in 2011 compared to 2010. This is not OK and I have a couple of posts in the making but haven’t really found the time to complete them yet. Hoping to improve during 2012 though…

My blog was viewed 10,000 times more though than in 2011 which is quite nice…!!

Here’s the stats for 2011 and happy new 2012 to you all!!
The WordPress.com stats helper monkeys prepared a 2011 annual report for this blog.

Here’s an excerpt:

The concert hall at the Syndey Opera House holds 2,700 people. This blog was viewed about 37,000 times in 2011. If it were a concert at Sydney Opera House, it would take about 14 sold-out performances for that many people to see it.

Click here to see the complete report.

Using a different master page for authenticated users in SharePoint

So, let’s say you’re building a public facing internet site using SharePoint and you want to conditionally hide content from anonymous users viewing your site from the internet.

Traditionally, you would use either a SPSecurityTrimmedControl or a LoginView.

In this post I’m going to show you yet another way to accomplish sort of the same thing (or something that you could combine with the above mentioned approaches to achieve the desired effect).

One of the things that you’ll probably want to “hide”, or in practice not render at all, from anonymous users is the ribbon. So from my point of view that shouldn’t even have to be in the master page for anonymous users and thereby reducing the complexity of that master page markup (also for the developer).
This will require me to use an alternative master page that is rendered for users who are authenticated to show them the ribbon so that they can work with page (edit, check-in, publish, and such).

 

 

The authenticated Master Page approach

What you’ll need:

  • Custom Master Page/s
  • Custom Page Layout/s

But since this is public facing internet site I’ll assume that you’ll want that anyway.

Public.com

image_thumb4

So for the purpose of demoing this I’ve setup a web application called public.com

public.com is hosted on an internal url (http://private.public.com) which is setup to not allow anonymous users. I’ve created an extended web application (http://www.public.com) that allows anonymous users (or should I say enabled for anonymous access since the actual allowing of anonymous users is configured on the site collection)

image_thumb8

So OOB both these “sites” (yes, same site but with different urls and authentication) show the ribbon, although the anonymous one only shows a “sign in” option. Well, we don’t want www.public.com to show any ribbon at all.

Master Pages

image_thumb12

You’ll need two master pages. We’ll look at how these master pages look in short but for now a feature provisions two modules with a master page in each of these modules.

Module Element

image_thumb15

The only difference between these modules is that “private.master” is instructed to be hidden (PublishingHidden=true). So as you can see, after activating the feature, only public.master shows up as an option in the SharePoint picker. That’s by purpose.

public vs. private

So, what’s difference between these master pages then?
Well, I’m not going to go through all of the markup but the basic idea is that public.master has as little of the SharePoint stuff as possible and private.master will include that so the admins can work with the site in a normal way.

Here’s a brief look a the public.master:

image_thumb19

So things to notice:

  • Head tag doesn’t include any CustomJsUrl or ScriptLinks or any of that stuff.
  • It still includes the placeholders that we are used to (notice PlaceHolderAdditionalPageHeadfor example)
  • Body content is also pretty clear, no ribbon.
  • Body content includes two custom placeholders (PlaceHolderBeforeMain and PlaceHolderAfterMain). We will use these shortly.

Now let’s look a private.master:

image_thumb22

private.master inherits from (or uses public.master) using the MasterPageFile attribute.

image_thumb28

We start by overriding PlaceHolderAdditionalPageHead from public.master and start to insert a bunch of SharePoint stuff. Important thing to notice is that we repeat the placeholder again as a last option to enable page layouts to insert their custom stuff into the head tag.

image_thumb31

Next up is to insert the ribbon. We’ll do that before the PlaceHolderMain so using the PlaceHolderBeforeMain from public.master is the place to do that.

Next up is to repeat the PlaceHolderMain placeholder (important) since we’ll want content from page layouts here.

And finally add some things after the page content like the developer dashboard using the PlaceHolderAfterMain placeholder.

Page Layout

So, I briefly mentioned that you’ll need custom page layouts to make this work. Here’s why.

image_thumb36

In order to alter the master page based on whether or not the user is authenticated we’ll need a custom page layout. In the image above you can see that I’ve created a page layout (welcome-default.aspx) which is a custom page layout that can be used for welcome pages (the content type).

In the page directive for that page you can see that it inherits (code behind) from PageLayoutBase (normally a page layout would inherit from PublishingLayoutPage which is a SharePoint class).

That’s actually a class that I’ve created and that’s the class that does all the magic. Now let’s have a look at it:

namespace Public.SharePoint.PageLayouts
{
    public class PageLayoutBase : PublishingLayoutPage
    {

        protected override void OnPreInit(EventArgs e)
        {
            // this sets the MasterPageFile to public.master (if the web has been setup to use that)
            base.OnPreInit(e);

            try
            {
                if (SPContext.Current.Web.CurrentUser != null && this.MasterPageFile.EndsWith("public.master", StringComparison.OrdinalIgnoreCase))
                {
                    //the user is logged in and the site uses the public.master

                    // change it to private.master
                    this.MasterPageFile = SPUrlUtility.CombineUrl(SPContext.Current.Site.ServerRelativeUrl, string.Concat("_catalogs/masterpage/", "private.master"));

                }

            }
            catch { } // this is an error trap, don't do anything
        }
    }
}

So, if you want to set the master page for a page (asp.net) using code you’ll need to override OnPreInit. This is actually what SharePoint does internally and reads the value from the SPWeb.CustomMasterUrl property.

What I’m doing is just checking if we have a user (i.e. if the user has authenticated) plus if the page uses the public.master, then I’ll change it to use private.master

This is just an example of how you could accomplish this. There’s of course a couple of hardcodings in there that could be abstracted an such.

Also, now it checks if the user is authenticated. Another option could be to check if the IIS settings instead…like this:

image_thumb38

And the end result?

image

Here’s how the same page looks viewed with the public.master and with the private.master (which changes dynamically)

And in summary

You could still combine this approach with login views and SPSecurityTrimming if you’d want that. For me at least, this is a bit cleaner approach than just “hiding” content from anonymous users. The markup looks better using this approach.

Enjoy!!

Download source code from here.

Using PowerShell to list all features with Title and ID

Ever wanted to list all the features installed in the farm with their id and Title (not the name of the folder)??

Here’s the PS script to run then:

Get-SPFeature | Sort @{Expression={$_.GetTitle(1033)}} -Descending:$false | ft @{Label='ID';Width=40;Expression={$_.Id}}, @{Label='Title';Width=250;Expression={$_.GetTitle(1033)}} | Out-File -Width 350 "c:\TEMP\features.txt"

It will sort all the features based on title (remember to add another language if you don’t want 1033 which is US English).
Then it will expand the title property and output the whole thing into a text file.

Like this:

image

What does SPSolution.ContainsWebApplicationResource really mean?

If you look at the documentation for this property on MSDN it says “Gets a value indicating whether the solution contains any web application-specific resources to deploy.”

So, at least to me, it wasn’t totally super clear what a web application specific resource really resource meant.
Let’s see an example to get a better understanding:

The WSP.ContainsWebApplicationResource SharePoint Project

I’ve created a basic SP project in VS 2010 and deployed it, without adding anything to it, to the local farm.
Let’s first see what that gives us:

image

::false

OK, but that was excepted right.

Let’s add a web application scoped feature to it. That should be web application specific…or?

::false

No, a web application scoped feature isn’t web application specific. It can be activated on a web application but it isn’t specific to a specific web application.

How about a site collection scoped feature then? Let’s add site scoped feature (but not include anything in it…emtpy feature).

::false

Strange…? An empty site collection (or site scoped) feature still returns false.

Let’s try adding a web part (or any SPI) to the feature then.

::true

Summary

So it turns out that the ContainsWebApplicationResource really means that the WSP contains elements (in VS those are called SPIs) that are included in a feature that is scoped to either SPSite or SPWeb.

When would you use this property then?

Well, it’s very common to use when you’re writing a PS script that deploys your WSP to the farm…like this little example (sorry about the formatting):

if($SPSolution.ContainsWebApplicationResource) {

$SPSolution | Install-SPSolution -GACDeployment:$ContainsGlobalAssembly
-CASPolicies:$ContainsCasPolicy
-WebApplication $WebApplicationUrl -Confirm:$false -Force -ErrorAction:SilentlyContinue
-ErrorVariable e | Out-Null

}

} else {
$SPSolution | Install-Solution -GACDeployment:$ContainsGlobalAssembly
-CASPolicies:$ContainsCasPolicy
-AllWebApplications:$true -Confirm:$false -Force -ErrorAction:SilentlyContinue -ErrorVariable e | Out-Null

}

If the SPSolution object has web application resources you have the ability to deploy it to one or more web applications, hence I don’t have to deploy it globally across the farm.

jQuery: implementing custom selectors for jQuery Templates plugin

I’ve been working a lot over the last couple of months with jQuery and the Templates plugin written by Microsoft (wondering if that will ever leave the beta phase??).
What I’ve come to love about it is the flexibility and nice separation of concerns it introduces.
However, I still felt that it was a little bit “ugly” to write the actual code that connects a JSON result with a template rendering stage.
Luckily, jQuery has some great extension points that can make this easier and I found some great articles by James Podolsey and from  jQuery HowTo that really helped my write my own extensions. So here goes…

Custom Selector Templates

Before going into actually implementing the custom selectors we want for the jQuery Template Plugin we’ll first have a look at how a custom selector works by providing a little example.

Similar to the built-in custom selectors that extend jQuery’s CSS selectors like :contains and :even you can write your own custom selectors using a predefined template model that looks like this (below are two examples of implementing the exact same selector which is called :test):

image

Note: that a custom selector can take up to four arguments (current, index, metadata, and elements) which we will have a look at shortly.

The two approaches (marked with red and blue) for extending jQuery with custom selectors are equal though I prefer the second approach (which is also better if you want more that one selector in the same self calling function).

Example usages:

  • $(:test)
  • $(:test(‘one’))
  • $(p:test)
  • $(:test, div)

Now let’s test the selector by using $(p:test(‘one’)) and see what happens, remember that the :test selector will log its arguments to the console window for now so we can have a look at them.

This is the html that the selector will execute on (three p-tags):

image

So jQuery will actually first select all P-tags, using the element selector, and then execute the :test selector on the result so we would expect three calls to be seen in the console window.
As a side note it’s always good to limit the selector calls as much as possible or should I say narrow them, perhaps by using a context so the search doesn’t need to look at the entire DOM tree. We’ll come back to that later on.

The arguments

Remember that I said that the selector function can take up to four arguments (test: function (current, index, metadata, elements))

image

As you can see we get four arguments from the call $(p:test(‘one’)):

  1. the currentDOM element (the p-tag in the example)
  2. the indexof the current DOM element (within all the elements to execute the selector on)
  3. some metadataabout the selector (well look more into detail on this array in a bit)
  4. finally, an array containing all the elements to run the selector on (since we executed it on p-tags we’ll get all three p-tags)

The metadata argument

This is the interesting part. Remember the call, $(p:test(‘one’))

image

So looking at the metadata argument (which is an array) we can see that also contains four elements:

  1. the complete selector
  2. the name of the selector
  3. the quote symbol used around the arguments, if used
  4. the arguments used by the selector (in the example ‘one’)

Let’s just try to call the selector without any arguments just to see the difference:

image

image

You can see that the quote symbol and arguments are undefined.

Lastly, keep in mind that a selector should always return true or false depending on whether you want the current element to be included in the result. In this example $(p:test).size() will return 0 since we always return false from the selector, just saying.

Now I think we are ready to implement the custom selectors for the jQuery Templates Plugin.

jQuery Templates Plugin Selectors

Let’s first briefly see how we would use the template plugin OOB  (so to say) to see what improvement can be made.
Consider this template:

image

We have a DIV that works as the target for the rendered content that will be executed on the SCRIPT tag that has the template information. Let’s see how that is rendered now.

image

From a JSON result we’ll start by finding the container (or target) using the ID selector.
Then render the template (and here we can see an example of specifying the context, hence when looking for the SCRIPT tag we’ll limit the scope to search in by telling jQuery to look in our container since that was where we placed it).

Finally, append the html that was rendered to the container (DIV) to see the result on the screen.
Problems? No, it works.
Can we make it simpler and more readable? I hope so.

It would be great if we could find containers and templates be just saying something like this:

$(:container(books)) and $(:template(books))

Thus changing the javascript code to look like this instead:

image

To make that work we have a couple of choices. We can make an assumption that the ID tag of a container and/or template will always have an ID prefix of container-{ID} and/or template-{ID} just like we had in the example.
Another solution is to use the data attribute that jQuery is good at working with. I’ll use that method in my example.

Using the data attribute

By using the data- (dash) syntax to identify my containers and templates I now have altered the html to look like this:

image

…and now here is the code for the actual selectors:

(function ($, undefined) {

    if ($ === undefined) {
        throw "Dependency: JQuery is not defined. Please check javascript imports.";
    }

    $.extend($.expr[':'],
    {

        // :template(name)
        template: function (current, index, metadata, elements) {

            var arg = metadata[3],
                d = $(current).data("template-for");

            if (d === undefined) {
                return false;
            }

            return arg ? arg === d : true;

        },

        // :container(name)
        container: function (current, index, metadata, elements) {

            var arg = metadata[3],
                d = $(current).data("container-for");

            if (d === undefined) {
                return false;
            }

            return arg ? arg === d : true;

        }

    });

} (jQuery));

So the selector/s first check that we have found an element with the data-container-for and/or data-template-for attribute and then optionally compares that to the name of the container and/or template.

Summing up

So by including this javascript we can now find all “container” elements (yeah, I’ll call them that) and make some changes to them (like putting everything in bold text).

image

image

yeah…that’s pretty!!

More interesting though, is that the OnSuccess javascript method now looks like this instead:

image

Of course, you can optimize and change this a lot more but the basic idea was to show how easy it is to write these custom selectors.

Introducing the jQuery CRUD extension

I’ve been getting my hands dirty with some jQuery/JavaScript, WCF, JSON, and REST lately doing a backend domain layer exposed via WCF as RESTful service operations that communicate via JSON.

On the client I’ve used jQuery as means for communicating with the WCF endpoints to get data and create/update/delete data…aka CRUD.

What I’ve come to learn is that it’s sometimes very cumbersome and time-consuming to create these $.ajax(…{}) calls via jQuery, specifying a bunch of settings every time, so I decided to create a plugin/extension that would make things easier for me when I communicated with these RESTful operations.

For the purpose of demonstrating this extension I’m going to use a small scenario and throughout it explain what the extension does. The entire code for it is at the end of this post.

Update: I’ve also made a NuGet package of the extension so you can also get it from VS 2010

The services

For this purpose of this post I’ve created a tiny domain consisting of books and authors. Consequently I have two endpoints, books and authors with these available operations:

Book Service Operations

image

  • Read Operations (3): all books OR all books within a genre OR one book with a specified id
  • Create Operations (1):create a new book
  • Update Operations (1):update a book with a specified id
  • Delete Operations (1): delete a book with a specified id

Author Service Operations

image

  • Read Operations (2): all authors OR all books by one author with a specified id

These endpoints are exposed via WCF via routes but since this post’s topic isn’t about WCF we’ll leave the services now knowing that they respond via JSON and subsequently expect JSON input when using PUT or POST.

The client

As I previously stated when using jQuery for communicating with a service that exposes RESTful endpoints it’s sometimes a bit cumbersome to work with jQuery’s $.ajax function. On the contrary, the $.getJSON is a bit to simple for me sometimes so what I did was to look around the web for what was available when working with REST and JSON with jQuery.
I found this plugin by Nathan Bubna but somehow I didn’t get it to work and there wasn’t any samples included. But I took Nathan’s excellent code and decided to change some things and add some other things.

The jQuery extension

Disclaimer: I’ve created this extension for the purpose of using it myself, hence it works like I want it to. I may not suit all needs for every application. But, feel free to change the code anyway you like it…

  • $.Create(uri, data, callback, options) – POST
  • $.Read(uri, data, callback, options) – GET
  • $.Update(uri, data, callback, options) – PUT
  • $.Delete(uri, data, callback, options) – DELETE

Those are the methods that this extension/plugin adds to jQuery. They are added to jQuery/$ itself and therefore will not work together with the $() selectors. Again…that’s what I wanted, easy enough to change if you’d like that.

image

Each of the methods take at most four parameters; URI, DATA, CALLBACK, and OPTIONS

  • URI: the uri/url to the RESTful operation. e.g. “books”. Can also be used with placeholders such as
    “books/{id}”. This parameter is required
  • DATA: optional data to send. If data contains an object like {id:1} then the id placeholder in the uri will be replaced (i.e. “books/1”). If it’s a create or update call (i.e. POST/PUT) the data: {JSON obj}within object will be JSON serialized ( e.g. {data: {Id:1, Title: “The title”}} ), after the replacement has taken place (which removes all the replacement parameters from the data parameter), and sent as JSONto the service endpoint.The data parameter can also be replaced by the callback function (if there is no data to send), e.g.
    $.Read(“books”, OnSuccess).
  • CALLBACK: optional callback function to execute with the response (i.e. the success function of jQuery’s $.ajax method).The callback parameter can also be replaced by the options object, e.g.
    $.Read(“books”, OnSuccess, {cache:true, error: OnError}).
  • OPTIONS: optional options object that corresponds to jQuery’s $.ajax settings object. Use this to change any default settings or add something that wasn’t added by the extension.

Each of the methods call an internal function called execute and passes in the result from another internal function called prepare.
Prepare, in turn, is called via apply which is just a fancy way of calling a function when you don’t know the exact number of parameters you’ll pass…and yes, the first parameter is the this pointer (which we’ll come back to in a bit).

Let’s have a look at execute and prepare next:

image

Execute doesn’t need that much explaining, it simple calls the underling $.ajax method with the options that prepare will do for us. So prepare then:

image

I’m just showing parts of the prepare function that I find interesting to highlight. For instance, the first thing that happens is that I merge the default settings with the settings for the current operation. These look like:

image

Here’s where the THIS pointer comes into play. Since I call operations[this], this will be one of the values of $create, $read, $update, or $delete depending on which method was called. So what I’ll get is a combination of the default settings combined with the settings for the current operation. All of which can be altered by using the options parameter.

Prepare will then go on and parse, merge, replace etc the parameters that was sent to it…have a look in the code if you’re interested.

So, now that you know how the extension works…let’s take it out for a spin.

Note: the OnSuccess method used in the following examples looks like this

function OnSuccess(response) {
// do stuff with response which is a
JSON object
}

READ: all books

$.Read(“books”, OnSuccess);

returns:

image

READ: book by id

$.Read(“books/{id}”, { id: “bk101″ }, OnSuccess);

returns:

image

READ: books in a specific genre

$.Read(“books?genre={genre}”, { genre:”Romance” }, OnSuccess);

returns:

image

CREATE: book

var book = {
Id: “bk113″,
Title: “The new book”,
Genre: “NewAge”,
Description: “This is the newest book on the shelf”
};
$.Create(“books”, book, OnSuccess);

returns:

image

UPDATE: book

var book = {
Id: “bk113″,
Title: “The new book”,
Genre: “Romance”,
Description: “This is the newest book on the shelf”
};
$.Update(“books/{id}”, {id: “bk113″, data: book}, OnSuccess);

returns:

image

DELETE: book

$.Delete(“books/{id}”, { id: “bk113″ });

READ: books by an author

$.Read(“authors/{author}/books”, { author: “Corets, Eva” }, OnSuccess);

returns:

image

The final code

(function ($, undefined) {

    if (!$) {
        throw "Dependency: jQuery is not defined. Check javascript file imports.";
    }

    var defaults = {
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        cache: false,
        data: null
    },
    // CRUD
        operations = {
            $create: {
                type: "POST",
                processData: true
            },
            $read: {
                type: "GET",
                processData: false
            },
            $update: {
                type: "PUT",
                processData: true
            },
            $delete: {
                type: "DELETE",
                processData: false
            }
        };

    function prepareUri(url, data) {

        // replaces tokens with their actual values and removes the replaced values from the data array
        // e.g. url: "service/{route}?tag={tag}", data: {route:"bookmarks", tag:"public"} => service/bookmarks?tag=public
        var k,
            v,
            u;

        for (k in data) {
            v = data[k];
            u = url.replace('{' + k + '}', v);

            if (u !== url) {
                url = u;
                delete data[k];
            }
        }

        return url;

    }

    function prepareData() {

        // handle JSON serialization from Object
        if (this.data && typeof this.data !== "string") {

            if ($.isEmptyObject(this.data)) {
                this.data = null;
            } else {
                this.data = JSON.stringify(this.data);
            }
        }
    }

    function prepare(uri, data, callback, options) {

        if (typeof uri !== "string" || !uri) {
            throw "Parameter: 'uri' must be of type string";
        }

        if (options && $.isPlainObject(options) === false) {
            throw "Parameter: 'options' must be of type object";
        }

        options = options || {};

        // merge default settings and the current operation (crud operation) settings
        var o = $.extend({}, defaults, operations[this]);

        // determine if data is a function or an object
        // 1. function - $.Read("uri", OnSuccess)
        // 2. object - $.Read("uri", {} )
        if ($.isFunction(data)) {

            // determine if the callback is an object
            // 1. object - $.Read("uri", OnSuccess, {} )
            if ($.isPlainObject(callback)) {
                options = callback;
            }

            callback = data;
            data = null;
        } else {

            uri = prepareUri(uri, data);
            options.data = data.data || data;

            // determine if callback is a function or an object
            // 1. object - $.Read("uri", {}, {} )
            // 2. function - $.Read("uri", {}, OnSuccess )
            if ($.isPlainObject(callback)) {
                options = callback;
                callback = null;
            }
        }

        o.url = uri;

        if (callback) {
            o.success = callback;
        }
        if (options) {
            prepareData.apply(options);
            $.extend(o, options);
        }

        return o;

    }

    function execute(options) {
        return $.ajax(options);
    }

    // extend jQuery
    $.extend({

        Create: function (uri, data, callback, options) {
            ///
<summary>Create operation (uses POST by default)</summary>
            ///[String] the uri template (required)
            ///[Object|Function] token replacements and/or JSON object OR the $.ajax success callback (optional)
            ///[Object|Function] the $.ajax success callback OR the $.ajax settings (optional)
            ///[Object] the $.ajax settings (optional)
            return execute(prepare.apply("$create", arguments));
        },
        Read: function (uri, data, callback, options) {
            ///
<summary>Read operation (uses GET by default)</summary>
            ///[String] the uri template (required)
            ///[Object|Function] token replacements and/or JSON object OR the $.ajax success callback (optional)
            ///[Object|Function] the $.ajax success callback OR the $.ajax settings (optional)
            ///[Object] the $.ajax settings (optional)
            return execute(prepare.apply("$read", arguments));
        },
        Update: function (uri, data, callback, options) {
            ///
<summary>Update operation (uses PUT by default)</summary>
            ///[String] the uri template (required)
            ///[Object|Function] token replacements and/or JSON object OR the $.ajax success callback (optional)
            ///[Object|Function] the $.ajax success callback OR the $.ajax settings (optional)
            ///[Object] the $.ajax settings (optional)
            return execute(prepare.apply("$update", arguments));
        },
        Delete: function (uri, data, callback, options) {
            ///
<summary>Delete operation (uses DELETE by default)</summary>
            ///[String] the uri template (required)
            ///[Object|Function] token replacements and/or JSON object OR the $.ajax success callback (optional)
            ///[Object|Function] the $.ajax success callback OR the $.ajax settings (optional)
            ///[Object] the $.ajax settings (optional)
            return execute(prepare.apply("$delete", arguments));
        }
    });

} (jQuery));

Notifications not showing when displayed in dialogs

I love working with the new dialog framework and notifications in SharePoint 2010. The other day though I ran into an issue with the notifications that somehow wouldn’t show up when I tried to use them in an application page I’ve built that was displayed through the dialog framework.

In my application page I wanted to use display a notification to the user. My code looked something like this:  

        var notifier = {
            _nid: null,
            ShowMessage: function (msg) {
                notifier._nid = SP.UI.Notify.addNotification("This is a message...", true);
            },
            HideMessage: function () {
                SP.UI.Notify.removeNotification(notifier._nid);
                notifier._nid = null;
            }

        }

And for the purpose of this post let’s use two buttons, one to show the notification and one to hide it:

    <input type="button" 
        value="Show Notification" 
        onclick="notifier.ShowMessage();" 
        style="width:150px" />
    <input type="button" 
        value="Remove Notification" 
        onclick="notifier.HideMessage();" 
        style="width:150px" />

Opening the page in the browser (not through a dialog) and clicking the “show” button displays this:

image

…as expected.

 

But what happens if I open this application page in a dialog?

image

To “simulate” that behavior I added the IsDlg=1 query string parameter which is what the dialog framework will do for us if we where to open this page in a dialog. 

The first thing to notice is that the ribbon disappears completely from the page and secondly when I click the button again nothing happens.

image

 

So why is this happening?

I searched the internet to find an answer for this and yes I did find a solution for the problem (which is at the end of this post) but I always like to know why this happens and not only how to solve it. So my investigation starts…

image

If I use firebug to inspect the html I can see that the ribbon (the div in the screenshot that is highlighted) is in fact rendered on the page but a style rule is hiding it. That style rule resides in some style sheet called dlgframe.css which I’ve tried to illustrate above.

Using firebug I tried to remove that line (display:none) and the ribbon row appeared again and the notification was displayed like before. You can see it from the image below that the page now has that dark blue ribbon row.

image 

 

How do the notifications work?

In order to fully understand the problem I now looked at the JavaScript used to display the notifications. 

image

Deep inside the core.js file I found that the notifications are finally shown using an element with id notificationArea.
AHA!!
That element resides inside the ribbon (which you an see from the screenshot above). So if that element isn’t visible the notifications simply will not be shown to the user.

 

The dlgframe.css style sheet

Going forward in my investigation I found that the dlgframe.css style sheet has been added to the head tag of the page (hmmm who did that?)

image

If we have a look inside that style sheet one of the rules read:

image

Or in plain English if you don´t speak fluent CSS:
”set display equals none to the element with id s4-ribbonrow that is a child of a body tag and if that body tag is also a child of an element with a class name that reads ms-dialog-nr 

OK, so we know that s4-ribbonrow is that div that is the starting point of the Ribbon from what we saw earlier. That div is a child of the body tag (duh?).
Furthermore, if we inspect the html that is outputted when IsDlg=1 is added to the query strings, the html tag apparently has a class named ms-dialog-nr…hey that is what that style rule says!!

image

That is exactly what we saw earlier in firebug and that is the rule that hides the ribbon and ultimately what causes the problem with the notification to being hidden. OK, so now that we know why the notification won´t display we’ll now continue with the how is that possible?

Which control outputs these style rules then?

It turns out that the CssLink control is the culprit. From the OnLoad method a call is made to the SeupDialogCSS method that looks like this:

image

Looking at the code with ILSpy you can see that if the current SPContext is a dialog (e.g. IsDlg=1) the dlgframe.css is registered (among some other thing that I have omitted for now). 

The CssLink control is added to the html via the applicationv4.master that the application page uses (if we haven´t overridden that with a custom one…chances that it uses the CssLink are still there though).  

 

So what options does this present us with?

One option is to use JQuery to forcefully show the ribbon row, something like:

image

Somehow, that doesn’t seem quite right though.

 

Another option

image

That is a screenshot of some more code from the CssLink class that I omitted before.
From it we can see that the code uses the SPRibbon to determine if the command UI is not set to show (by default) and if so the ms-dialog-nr css class is added to some HtmlGenericControl which is in fact the html tag (that can bee seen from looking at the whole code).

This presents us with an option though.
Change that behavior in the code behind used by our application page, thus forcing the CssLink not adding that css class.

        protected override void OnPreRender(EventArgs e)
        {
            if (SPContext.Current != null && SPContext.Current.IsPopUI)
            {
                var ribbon = SPRibbon.GetCurrent(this.Page);
                if (ribbon != null)
                {
                    ribbon.CommandUIVisible = true;
                }
            }
            base.OnPreRender(e);
        }

Build, Deploy and…

 

image

 

…it’s showing!!!

Follow

Get every new post delivered to your Inbox.

Join 49 other followers