Latest Posts

<< >>

Loading JS files in a SharePoint Online Environment

For any of you that don’t follow Wouter van Vugt, he had a great session at the Dutch SPC a while ago about loading JavaScript files in an On Premise SharePoint 2010 Environment. Very cool solutions were discussed however none of them are applicable when having a SharePoint Online environment. It’s true the possibilities are [...]

Get User Information from Client OM (JS)

When I was exploring the possibilities to read from a User Profile in a SharePoint Online environment I realized there are lots of properties that are being synced back to the UserInfoList, but only when they are filled in the User Profile. User Info List We know by now it’s impossible from a Sandboxed Solution [...]

Inconvenient (Sandboxed) Custom ListDefinitions

Building custom SharePoint Online solution a List Definition is likely to be a SPI you would like to use. Sandboxed Solution look like a good way of deploying these definitions to your SharePoint Online environment, but are they? LanguageWhen we deployed custom List Definitions we came across strange behavior accessing these lists. Suddenly the language [...]

Inconvenient Recurrence Data from a SharePoint Calendar using Client OM (JS)

The CAML to get SharePoint items from lists has a nice feature when it comes to Calendar data. Using the <DateRangesOverlap/> it is possible to check if a given date is within a range of dates and when passing the ExpandRecurrence property it even takes the Recurrence Data into account. Using Sandboxed Solutions to do [...]

Loading JS files in a SharePoint Online Environment

For any of you that don’t follow Wouter van Vugt, he had a great session at the Dutch SPC a while ago about loading JavaScript files in an On Premise SharePoint 2010 Environment. Very cool solutions were discussed however none of them are applicable when having a SharePoint Online environment. It’s true the possibilities are very limited but still some cool techniques can be used to keep amount of scripts loading down to an acceptable level.

ScriptLink

The easiest way to add script to your page from a feature is to use the ScriptLink. By default this control is on every SharePoint Masterpage and by using a <CustomAction> a script can easily be added to the page without the need of changing the MasterPage or Page Layout. The Custom Action to do this can look like this:

<CustomActionLocation=”ScriptLink” ScriptSrc=”~SiteCollection/Scripts/jquery-1.6.min.js” Sequence=”105″ />

This example loads the jQuery library to the page. This approach is a nice one to load Shared Libraries (like jQuery) on every page. Even on the system pages based on the default v4.master the jQuery library is loaded because of this Custom Action. That is an important consideration whether to use this in your solution or not.

ScriptTag

Using the HTML tag <script/> is a good way to always load a script. Actually the SharePoint ScriptLink also renders a <script/> tag eventually. However for this approach the MasterPage needs to be updated and if you want your script to load on system pages (Forms, Views etc.) you also have to edit the default MasterPage which is not a best practice.

 

Script On Demand

A good way of loading scripts is only load them when you are actually gonna use them. The SharePoint Client OM accommodate you with the SP.SOD (Script On Demand) class. With a few steps we implement this:

1) Deploy your script using a Module (i.e. to the folder ‘/Scripts/MyFile.js’)

2) In the MyFile.js file at the bottom add “SP.SOD.notifyScriptLoaded(‘MyFile.js’);”

3) On the page where the call to this script is made add “SP.SOD.registerSod(‘MyFile.js’, ‘/Scripts/MyFile.js’);”

4) When the script is needed make a function call like this “SP.SOD.execute(MyFunc, ‘MyFile.js’);”

Now the SP.SOD.execute will make sure the Function is execute after the MyFile.js is loaded. At PageLoad this script is not loaded this way.

Script Storage

Because SharePoint Online is bound to SiteCollection level and because we are not able to write to the _layouts folder on the server, the storage of all Script files is important to think about. The logical place after _layouts would be in the Style Library, but there the possibility exist that user are going to mess up your code. In a SharePoint Online environment we can never cover this entirely but a more secure location to store your script would be just in a Folder of the RootWeb. Then people can only touch your code using SP Designer which is more difficult to most users.

Minify your scripts

In order to keep the JS files to a minimum, don’t create too much different JS files and remember to Minify them. The nice VS add-on from Mavention is a very powerful tool to get this done. http://visualstudiogallery.msdn.microsoft.com/04ef7cbc-23dd-49f8-b4a2-ab87885ad065

Get User Information from Client OM (JS)

When I was exploring the possibilities to read from a User Profile in a SharePoint Online environment I realized there are lots of properties that are being synced back to the UserInfoList, but only when they are filled in the User Profile.

User Info List

We know by now it’s impossible from a Sandboxed Solution (or Client Side OM Solution) to access a Users Profile directly as you would in a On-Premise environment. Our scope is the SiteCollection that runs our custom code. In that scope there is one important resource we can use to get information about a User, the UserInfoList. The list contains some Properties that are populated by the SharePoint Profile. So somehow this is synced.

Synced Properties

The synchronization process is done (On-Premise) by a TimerJob called: “User Profile Service Application – User Profile to SharePoint Full Synchronization”. This TimerJob normally runs “Hourly”. I didn’t test this out but my guess is that this will be the case with SharePoint Online too. The important part being that there is a delay in this procedure. That being said, which properties of the User Profile are being synced by this TimerJob?

Property StaticName (Client OM) Returns
Account name Name domain\ierselca or claim
User name UserName ierselca
Name (DisplayName) Title Cas van Iersel
First name FirstName Cas
Last name LastName van Iersel
Title JobTitle SP Consultant
Email EMail cas@rapidcircle.com
Work phone WorkPhone 0123456789
Mobile phone MobilePhone 0123456789
Picture Picture http://linktoimage *
Department Department R&D
About me Notes Inner HTML of About field as a string
Web site WebSite http://mywebsite.com *
SIP SipAddress sip format string
Office Office Rapid Circle
Ask me about SPSResponsibility SharePoint, C#, ASP
If User Is Site Admin IsSiteAdmin true | false

* You’ll need to do .get_url() on the return object

This is an example on how to get the information based on the UserID in the Context of the current web (You can obtain this from the SPUser object or use javascript to get from a people link “person.aspx?ID={UserID}”:

    //Get the Context, Web and SiteUserInfoList for User Info
    var clientContext = SP.ClientContext.get_current();
    var web = clientContext.get_web();
    var collListItem = web.get_siteUserInfoList().getItemById(userID);

        //Load the objects async
    clientContext.load(collListItem);
    clientContext.executeQueryAsync(
    Function.createDelegate(this, function(){
          //Read all properties from the Item
                 var userName = collListItem.get_item(‘Name’);
                 var website = collListItem.get_item(‘WebSite’).get_url();
     }), Function.createDelegate(this, function(){
         //On Fail
    }));

Note: When the field is empty in your profile the get_item() Method will return null on the property.

Profile Picture

On property that can be slightly inconvenient is the Profile Picture. The URL is stored in the UserInfoList so that will be returned perfectly. But with SharePoint Online the Picture is most definitely stored in the MySite Host webapp. This means the user is challenged for credentials when this URL is used in an <img /> tag for instance.

Summary

There is a lot of User Information we can work with using the Client OM. It’s very easy to obtain the information using Javascript and to do cool stuff with it. Just keep in mind that the syncing process can take some time and no custom properties are being synced.

Inconvenient (Sandboxed) Custom ListDefinitions

Building custom SharePoint Online solution a List Definition is likely to be a SPI you would like to use. Sandboxed Solution look like a good way of deploying these definitions to your SharePoint Online environment, but are they?

Language
When we deployed custom List Definitions we came across strange behavior accessing these lists. Suddenly the language changed from Dutch (nl-NL) to the default language (en-EN). Together with the help of MS we found some interesting information in the Logs. SharePoint was trying to access a resource file we didn’t deploy.

Localized Strings
A SharePoint Feature comes with the property DefaultResourceFile. This property can be set with the Feature Properties. When empty SharePoint will try to get the resource from “%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATES\FEATURES\FeatureName\Resources\Resources. Culture.resx” when a resource is requested by a Localized string. When you create a ListDefinition in Visual Studio the Schema.xml is being generated for you. The <List /> element contains an Attribute called Direction which is a localized string. Direction=”$Resources:Direction;”

The Localized string doesn’t refer to a default Resource file but instead it tries to get the Resource from the DefaultResourceFile. This results in an error when you are not deploying a Resource File to this location containing “Direction”.

Solutions
This blogpost states that with SP1 the problem is resolved. http://www.mysticslayer.com/?p=211 However together with MS we found out that the error in the Log files still occurs in SharePoint Online. The easiest way to fix this is to replace the localized string in your schema.xml for a hardcoded value. MSDN explains what values can be used (http://msdn.microsoft.com/en-us/library/ms415091.aspx).

If you don’t want to choose this option for some reason, according to MS you can also choose to reference the Core Resource file Direction=”$Resources:core,Direction;”. This didn’t give me the error on premise, but obviously I couldn’t test it in Office 365 because I’m not able to check the Log files. I didn’t experience the language change as before so I assume this is a good option. Still the value in the core resource file for Direction is 0 which is not given as an option according to MSDN. My guess is that SharePoint sees this as “none”.

Inconvenient Recurrence Data from a SharePoint Calendar using Client OM (JS)

The CAML to get SharePoint items from lists has a nice feature when it comes to Calendar data. Using the <DateRangesOverlap/> it is possible to check if a given date is within a range of dates and when passing the ExpandRecurrence property it even takes the Recurrence Data into account. Using Sandboxed Solutions to do so we can easily set this property SPQuery.ExpandRecurrence = true; However when it comes to the JavaScript Client OM we cannot use this property.

WebServices

The only way to query SharePoint for Recurrence Data using Client OM is by using the GetListItems Method from the List WebService (/_vti_bin/lists.asmx). The XML passed into the WebService can handle QueryOptions and we can use this to specify if ExpandRecurrence should be true. The Soap XML looks like this:

<soapenv:Envelopexmlns: soapenv=’http://schemas.xmlsoap.org/soap/envelope/’>
  <soapenv:Body>
   <GetListItemsxmlns =’http://schemas.microsoft.com/sharepoint/soap/’>
      <listName>[MyListName]</listName>
      <query>
        <Query>
          <Where>
            <DateRangesOverlap>
              <FieldRefName=’EventDate’ />
              <FieldRefName=’EndDate’ />
              <FieldRefName=’RecurrenceID’ />
              <ValueType=’DateTime’>
                <Today />
              </Value>
            </DateRangesOverlap>
          </Where>
        </Query>
      </query>
      <queryOptions>
        <QueryOptions>
          <ExpandRecurrence>TRUE</ExpandRecurrence>
          <CalendarDate>
            <Today />
          </CalendarDate>
          <ViewAttributesScope=’RecursiveAll’ />
        </QueryOptions>
      </queryOptions>
      <viewFields>
        <ViewFields>
          <FieldRefName=’EventDate’ />
          <FieldRefName=’EndDate’ />
          <FieldRefName=’fAllDayEvent’ />
          <FieldRefName=’fRecurrence’ />
          <FieldRefName=’Title’ />
        </ViewFields>
      </viewFields>
      <RowLimit>10</RowLimit>
    </GetListItems>
  </soapenv:Body>
</soapenv:Envelope>

This example checks if there are events overlapping with <Today />. I found that it’s best to check with tags like <Today/>. <Week/>, <Month/> and <Year/> instead of using UTC Dates. Notice the <queryOptions/> wrapper passing the Options. Building regular CAML XML using the inner <QueryOptions/> tag didn’t work unfortunately. Both <ExpandRecurrence/> as <CalendarDate/> are mandatory in order for this query to work.

Tip: When using Client OM to process SharePoint data requests it’s best practice to specify as much properties as possible. Specifying <ViewFields/> will only return these fields instead of all possible fields that come with an Item. If you know the maximum amount of results specifying <RowLimit/> also helps to improve the performance on your Query.

Handling DateTime in Office 365 Sandboxed Solutions

When developing custom solutions on the SharePoint platform we don’t really think about using DateTime objects anymore. We just build solutions using server-side DateTime.Now or DateTime.Today to check Date and Time and to check that with the values we get back from SharePoint. Because we have full control over our On-Premise environment we can be sure that the Server Date and Time is correct. However moving this principal to the Cloud we loose that bit of control. We have to make sure again we get the right Date and Time from the server to do accurate checks.

Timezone of a Office 365 Server

As soon as I was testing a solution using a DateTime.Now object to get Calendar Items I came across some strange behavior when testing before 09:00 (GMT +1). I came across this article http://onlinehelp.microsoft.com/en-us/office365-enterprises/hh531509.aspx to get all Applications in the right TimeZone. It seemed that the Office 365 servers were all set to the TimeZone GMT -8 (Which is the Redmond TimeZone). So there was a 9 hour difference (I’m in Amsterdam TimeZone GMT +1).

Regional settings

Because programming it like DateTime.Now.AddHours(9); didn’t seem the right thing to do, I found a good solution to get the right DateTime.Now based on our local TimeZone. First step is to set the Regional Settings for your Office 365 SharePoint Site Collection (https://MySharePointSite/_layouts/regionalsetng.aspx) to the correct TimeZone. With this Regional Settings we can use the SPRegionalSettings object to calculated the local time at the moment of need using the following code.

       SPRegionalSettings reg = SPContext.Current.Site.RootWeb.RegionalSettings;
        SPTimeZone tz = reg.TimeZone;
        DateTime utc = DateTime.Now.ToUniversalTime();
        DateTime utcLocal = tz.UTCToLocalTime(utc);

The utc represents DateTime.Now at GMT. With the UTCToLocalTime() method we will get the current DateTime based on our TimeZone. Now we can use utcLocal instead of DateTime.Now to get the accurate Date and Time when doing Server Side (Sandboxed) calculation with DateTime. The picture illustrates the DateTime.Now, the TimeZone ID set for the Current Site, GMT time and our LocalTime.

BlogPost-DateTimeO365