another technical blog...technically

Monday, December 8, 2014

Azure SPFarm Manager 1.1 released

You're asking yourself, why in the world, Varro is writing articles as fast as hell?
I got the flu and lots of drafts.
So here's a good new one, the new version of Azure SPFarm Manager.
Here's the changes.
  • No more BuildEnvironment.ps1 command, now it's named Build.ps1
  •  Deprovision.ps1 command: so now you can save you money deallocating and removing your VMs whenever you want (config are saved in the export folder)
  • Reprovision.ps1: so you can spend your money whenever you wake up your farm
  • No more Config.xml file needed: if you have more than one farm, you can create more config files (e.g.: development.xml, integration.xml), if you don't select an existing file, the old Config.xml would be used for you


Do you wanna more?
Mmm.. sorry thats'it for today.
Download the code from here

Howto to deal with workflow manager when it refuses to install

This is what happens when you come back from a vacancy week:
  • Your (personal) mobile phone rings (yep i don't have a enterprise one) and customer asks why workflow manager installer for SP2013 farm, literally, "doesn't work" 
  • You take tube and bus (with 30° C) to reach customer office
  • You skip launch to discover the problem
  • You came back to the office and you continue your work till late
  • You start thinking about opening a bar in Copacabana
As usual /mode joke off
Today i will talk about safest installation procedure of workflow manager on SP2013 farm. Customers, very often configure farm server doing stuffs as block incoming connections or setting locale in such strange ways.
This could cause Web Platform installer strange behaviours and mainly Service Bus installation failure with this error (which is related to Windows Fabric, a Service Bus dependency)
Error
When i tried to install Workflow Manager stuffs i got this error:
Event ID 11722 Product: Windows Fabric — Error 1722. There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. Action DoFabricSetup, location: C:Program FilesWindows abricbinFabricFabric.Code.1.0MSIHiddenAppLauncher.exe, command:FabricSetup /operation:install /gac
Like you can read on this blog post (a real life-saving one: http://blog.riccardocelesti.it/workflow-manager-setup-issue/) this is due to locale settings. Service Bus and its dependencies can be installed only with locale settings en-us, but the check will let you install this piece of sotware it's only on this registry key.

Solution
So i built this little script, which is helpful to install workflow manager flawlessy.
Write-Host "Getting sTimeFormat RegEx value ... " -NoNewLine;
$regVal =  Get-ItemProperty -Path "Microsoft.PowerShell.Core\Registry::HKEY_USERS\.DEFAULT\Control Panel\International" -Name "sTimeFormat"
Write-Host "DONE" -ForeGroundColor GREEN;

$oldFormat = $regVal.sTimeFormat;
Write-Host "Old time format was: $oldFormat" -BackgroundColor YELLOW -ForeGroundColor BLACK;

Write-Host "Setting sTimeFormat RegEx value ... " -NoNewLine;
Set-ItemProperty -Path "Microsoft.PowerShell.Core\Registry::HKEY_USERS\.DEFAULT\Control Panel\International" -Name "sTimeFormat" -value "h:mm:ss tt";
Write-Host "DONE" -ForeGroundColor GREEN;

Write-Host "Download web platform installer ... " -NoNewLine;
$source = "http://download.microsoft.com/download/7/0/4/704CEB4C-9F42-4962-A2B0-5C84B0682C7A/WebPlatformInstaller_amd64_en-US.msi";
$destination = "c:\WebPlatformInstaller_amd64_en-US.msi";
Invoke-WebRequest $source -OutFile $destination;
Write-Host "DONE" -ForeGroundColor GREEN;

Write-Host "Installing web platform installer ... " -NoNewLine;
Start-Process c:\WebPlatformInstaller_amd64_en-US.msi -Wait;
Write-Host "DONE" -ForeGroundColor GREEN;

Write-Host "Refreshing WebPI products ... " -NoNewLine;
Start-Process "C:\Program Files\Microsoft\Web Platform Installer\webpicmd" -ArgumentList '/offline','/Products:WorkflowManagerRefresh','/Path:c:/WorkflowManagerFiles' -Wait;
Write-Host "DONE" -ForeGroundColor GREEN;

Write-Host "Installing workflow manager software ... " -NoNewLine;
Start-Process "C:\Program Files\Microsoft\Web Platform Installer\WebpiCmd.exe" -ArgumentList '/Install','/Products:WorkflowManagerRefresh','/XML:c:/WorkflowManagerFiles/feeds/latest/webproductlist.xml' -Wait;
Write-Host "DONE" -ForeGroundColor GREEN;

Write-Host "Starting workflow manager configurator ... " -NoNewLine;
Start-Process "C:\Program Files\Workflow Manager\1.0\Microsoft.Workflow.Deployment.ConfigWizard.exe" -Wait;
Write-Host "DONE" -ForeGroundColor GREEN;

Write-Host "Resetting sTimeFormat RegEx value to $oldFormat ... " -NoNewLine;
Set-ItemProperty -Path "Microsoft.PowerShell.Core\Registry::HKEY_USERS\.DEFAULT\Control Panel\International" -Name "sTimeFormat" -value $oldFormat;
Write-Host "DONE" -ForeGroundColor GREEN;

Write-Host "Cleaning files ... " -NoNewLine;
Remove-Item $destination;
Remove-Item "c:/WorkflowManagerFiles";
Write-Host "DONE" -ForeGroundColor GREEN;

Read-Host "Press any key to exit";
It could be done better, for example using powershell also for workflow manager configuration, maybe i'll do something similat for Azure SPFarm Manager.
Once you run the script, at first the sTimeFormat will be forced in the registry key, so installation could proceed on any locale configured SharePoint farm.



At the end the original value will be restored.
 And that's all, you can also download the code from here. Enjoy.

A simple script to log to verbose mode

Hi, this will be a quick post, just to show you a little PowerShell script (yeah, lately i'm in love with PowerShell) could be very helpful during bug hunting sessions.
When you run the script, the log level is raised to Verbose and a new SPLog file is created for this verbose log.
When you press a key, the log level is resetted to the default one, and a new SPLog file is created, so the penultimate log file is the one you need to examine.
This is the script: enjoy
$ver = $host | select version
if ($ver.Version.Major -gt 1) {$host.Runspace.ThreadOptions = "ReuseThread"} 
if ((Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) 
{
    Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}

Write-Host "Setting TraceSeverity and EventSeverity to Verbose"
Set-SPLogLevel -TraceSeverity Verbose -EventSeverity Verbose

Write-Host "Creating a new Log file"
New-SPLogFile

Read-Host "Press ENTER key to reset default log level"

Write-Host "Resetting TraceSeverity and EventSeverity"
clear-sploglevel

Write-Host "Creating a new Log file for resetted log"
new-splogfile

Read-Host "Press any key to exit ..."
Or maybe download it from here.
Share:

SharePoint 2013 workflow task related item field

Another day spent with SP2013 workflows.
Do you remember when you had a task on SP2010 and you could get the workflow related item easily?
Good, it was something like that
taskItem["WorkflowItemId"]
Today, the game has changed.
Let's see this task view screenshot, everything lets you think you only have to do something like this
taskItem[SPBuiltInFieldId.RelatedItems]
to get a SPListItem, unfortunally you have to do more than this.
This field contains a JSON string containing web, list and item id, so you have to adapt this field value in order to do some work from code behind...

RelatedItem is one of the new site column SP2013 available for developers and can be used for other purposes, not only in workflows; so i decided to write this little helper in VLibs which lets you to read/write this field easily from server side, since CSOM supports this field.
[Serializable]
public class RelatedItemFieldValue
{
 #region Properties
 public int ItemId { get; set; }
 public Guid WebId { get; set; }
 public Guid ListId { get; set; }
 #endregion
} 
Then using this helper you can read and update this field value.
Related item field value is not assigned to the field when the task is created, so pay attention using event receivers events ItemAdding and ItemAdded for related item field read, use ItemUpdated or ItemUpdating instead.
I wrote this little piece of code you can find in Example 08, which overwrites the task related field item with the first item of the workflow items list in a event receiver.
string jsonString = properties.ListItem[SPBuiltInFieldId.RelatedItems].ToString();
List relatedItems = RelatedItemFieldHelper.GetItems(jsonString);
RelatedItemFieldValue r = relatedItems[0];
SPList l = properties.Web.Lists.TryGetList("WorkflowsItemsList");
SPQuery query = new SPQuery();
query.RowLimit = 1;
query.Query = "";
SPListItem first = l.GetItems(query)[0];
int itemId = first.ID;
r.ItemId = itemId;

// Safety... never enough
this.EventFiringEnabled = false;
properties.ListItem[SPBuiltInFieldId.RelatedItems] = RelatedItemFieldHelper.GetItems(relatedItems);
properties.ListItem.SystemUpdate();
// Rollbacking safety setting
this.EventFiringEnabled = true;
And here's the demonstration i'm telling the truth :-)


 Even if i'm confident you know it, here's the link to VLibs code :-) .

Sunday, December 7, 2014

Get user in SharePoint 2013 workflows

Today i'll present you a resolution of a common question when dealing with SharePoint 2013 workflows:
How the hell i get the user login name from a type user field?
The answer should be straighforward, unfortunally it isn't: it depends from the user field xml parameters.
Site columns
It is possible to declare a user field in defferent ways, so, reusing Example 01 code, i have extended the workflow item content type, so i can make some tests with those three different fields:
  1. Approvers (Type = UserMulti): used for multiple users
  2. Type User - Mult False: used for single user
  3. Type User - Mult True: used for multiple users too
<Field
       ID="{c55e296e-e0bf-4574-b266-a421781b5081}"
       Name="Approvers"
       DisplayName="Approvers"
       Type="UserMulti"
       Required="FALSE"
       Group="VLibs SP2013 Examples site columns"
       EnforceUniqueValues="FALSE"
       UserSelectionMode="PeopleOnly"
       UserSelectionScope="0"
       Mult="TRUE"
       Sortable="FALSE"/> 
<Field
       ID="{C4AC8A6C-F65C-4BC1-BE36-F83919EE9886}"
       Name="ItemUser"
       DisplayName="Type User - Mult False"
       Type="User"
       Required="FALSE"
       Group="VLibs SP2013 Examples site columns"
       EnforceUniqueValues="FALSE"
       UserSelectionMode="PeopleOnly"
       UserSelectionScope="0"
       Mult="FALSE"
       Sortable="FALSE"
       Overwrite="TRUE"/> 
<Field
       ID="{9af230e5-cdff-40ac-ae13-f2a6928dd1d1}"
       Name="ItemUsers"
       DisplayName="Type User - Mult True"
       Type="User"
       Required="FALSE"
       Group="VLibs SP2013 Examples site columns"
       EnforceUniqueValues="FALSE"
       UserSelectionMode="PeopleOnly"
       UserSelectionScope="0"
       Mult="TRUE"
       Sortable="FALSE"
       Overwrite="TRUE"/>
Workflow
 I have created a stupid workflow (named stupid workflow for real) which prints fields value in history
i added this item to the list, launched the workflow
 
and this was the result

As you can see, for the first field i obtained a list of user id, for the second field a single id: those int numbers can be used to make a user lookup, but what about the third field?

Resolution
For this particular example you need a custom activity in order to read the field value from results property in a collection string object.
This custom activity needs as input value, the user field dynamic value, and a collection string variable to save che user ids.

  
Placing the activity and configuring the output was this.
To play with this workflow and custom activity, you have to download latest version of VLibs from here, and enable features 01, 07a and 07b. Have fun.

Friday, November 21, 2014

Provision a SharePoint 2013 farm with Azure and PowerShell

I begun to work on Azure one year ago in order to have a dev SharePoint 2013 to build some code since i don't have a powerful PC.
Reading below articles, i was able to create my personal farm
Step-by-Step: Build a FREE SharePoint 2013 Dev/Test Lab in the Cloud with Windows Azure Infrastructure Services - Part 1
Step-by-Step: Build a FREE SharePoint 2013 Dev/Test Lab in the Cloud with Windows Azure Infrastructure Services - Part 2
A colleague (codename Roller) asked me if it was possible to build the farm automagically using PowerShell, since there were amazing PowerShell Azure cmdlets.
<< Varro, why don't you do something like that? it would be so useful >>
<< Ok Roller, but it will take a lot of my free time, you'll give me money for this? >>
<< No >>
<< Ok Roller, i'll do it for you ... someday... in the future >>
That day is arrived.
/mode joke off
Since i need something simple and smart to build a SP2013 farm, i started surfing the web studying (and also stealing code) creating this wonderful script you can download clicking here.

Requirements
Once you downloaded the script on you PC you have to read the README (do it).
It explains what do you need to make script execution smooth (maybe).
  1. Enable PSRemoting on your PC: this will be useful to use CredSSP to invoke remote PowerShell script execution on Azure machine (it will avoid the double hop problem); since you have to allow PSRemoting to *.cloudapp.net you are future-powershell-experiments proof.
  2. Download Azure cmdlets
  3. Download your Azure account publish settings (have you got a Azure account uh?).
  4. Configure XML file
The zip contains a Config - example.xml

 
 
 
  
  
 
 
 
  
 
 
  
   
  
  
   
  
  
   
   
  
 

If you don't want to waste you time, simply change "MSDN subscription name" with your MSDN subscription name, passwords (substitute Password01 with your preferred one) and substitute "sharepointLab01" prefix with something else (please note that resulting vm name length must be less than 15 characters).
Note that if you are behind proxyes, firewall and other stuffs, you could have troubles.
Please take some minutes to read the FAQ below, since you'll need it, after thas warm-up phase, simply run BuildEnvironment.ps1

FAQ.
Q1: What is the average execution time of the batch script?
A1: The farm will be provisioned approximately in 1 hour, i could make it quicker, better, safer... but you have the code, make it better :) .

Q2: The script is someway interactive?
A2: No, you will be prompted to proceed to WinRM quick configuration just one time, when provisioning SharePoint VM, click y and everything will be fine


Q3: I noticed the script sometimes stop itself and give me some error, what i have to do?
A3: Simply solve the errors and re-run the script: already done steps will be bybassed if possible

Q4: I received this error: "Connecting to remote server failed with the following message: The client cannot connect to the destination specified in the request blablabla" what i have to do?
A4: Just keep calm and re-run the script. This error means the script is unable to connect to the VM, so if you're ok with firewall, proxyes and other security stuffs, the connection simply failed, try again.
If the problem persists, try something more rude, delete the VM giving problems and re-run the scipt.

Q5: Are there some built-in users?
A5: Yes sir, SPFarm, which is also the farm admin and SPServiceApp

Q6:What about the service application?
A6: The script provisions User Profile, Managed Metadata and Search service applications, but you can do che quick wizard whenever you want if you need more

Happy ending (hope so)
Download the code from here and have fun. 

Remember, this is not production software, it's something i use for me, myself and i, so i cannot ensure you everything is gonna be fine, even if i provisioned some farm with this, but if i'll save you time with this... come on offer me a beer ;) .

In loving memory of Roller

Sunday, November 2, 2014

OpenMap to JTS and JTS to OpenMap

Yesterday i received a newsletter about OpenMap, and i remembered university times.
I also remembered i developed a small piece of code which helped me to convert OpenMap geomertries in JTS geometries.
This was useful because Oracle DBMS uses WKT format to define spatial data, but at that time, there weren't UI components able to render directly WKT.
Therefore, it was possible to convert WKT to JTS standard format, and then use JTS to map OpenMap objects. The code is below, i hope it could be still useful :-) .

OpenMapToJTS JTSToOpenMap
package presentationLevel.converters;


import java.util.List;

import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.omGraphics.OMGraphic;
import com.bbn.openmap.omGraphics.OMGraphicList;
import com.bbn.openmap.omGraphics.OMPoint;
import com.bbn.openmap.omGraphics.OMPoly;
import com.bbn.openmap.proj.Ellipsoid;
import com.bbn.openmap.proj.coords.UTMPoint;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;

public class JTSToOpenMap {

 public static OMGraphicList createOMGraphicList(List l){
  OMGraphicList oml = new OMGraphicList();
  for (Geometry g : l)
   oml.add(createOMGraphic(g));
  return oml;
 }

 public static OMGraphic createOMGraphic(Geometry g){
  if (g instanceof Point)
   return createPoint((Point) g);
  else if (g instanceof LineString)
   return createLine((LineString) g);
  else if (g instanceof Polygon)
   return createPolygon((Polygon) g);
  else
   return null;
 }

 private static OMPoint createPoint(Point p){
  float[] coordinates = coordinatesConverter(p.getCoordinates());
  OMPoint omp = new OMPoint(coordinates[0], coordinates[1]);
  return omp;
 }

 private static OMPoly createLine(LineString l){
  OMPoly omp = new OMPoly(coordinatesConverter(l.getCoordinates()), OMGraphic.DECIMAL_DEGREES, OMGraphic.LINETYPE_STRAIGHT);
  return omp;
 }

 private static OMPoly createPolygon(Polygon p){
  OMPoly omp = new OMPoly(coordinatesConverter(p.getCoordinates()), OMGraphic.DECIMAL_DEGREES, OMGraphic.LINETYPE_STRAIGHT);
  omp.setIsPolygon(true);
  return omp;
 }

 private static float[] coordinatesConverter(Coordinate[] c){
  float[] coordinates = new float[(c.length)*2];
  for (int i = 0, j = 0; i < c.length; i++, j = j+2){
   LatLonPoint lp = UTMPoint.UTMtoLL(Ellipsoid.WGS_84, (float) c[i].y, (float) c[i].x, 19, false, null);
            coordinates[j] = lp.getLatitude();
            coordinates[j+1] = lp.getLongitude();
  }
  return coordinates;
 }

}
Share:

Tuesday, September 23, 2014

Restrict content types and related page layouts on list pages new button

This is one of the most recurrent tasks... dealing with pages list.
You created your pages list content types, associated page layouts to those content types, and customers want to use only those content type and page layouts or simply.
Ok, let's assume you have Example 04 deployed (if  it's your first time on this blog, download VLibs here), this is what you see in Pages list.

The key to accomplish this task is divide-et-impera, so what about the new page menu?
Work on this property
IList<SPContentType> contentTypeInstances2Show = ...
pagesList.RootFolder.UniqueContentTypeOrder = contentTypeInstances2Show;
pagesList.RootFolder.Update();
Assigning a  SPContentType list to UniqueContentTypeOrder, we give the order of the content type available for creating, and we can also exclude some of them from the menu.

The second step is to make a selection of page layouts available, the method is:
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web); 
PageLayout[] pageLayouts = publishingWeb.GetAvailablePageLayouts();

PageLayout[] pageLayouts2Show = ...
publishingWeb.SetAvailablePageLayouts(pageLayouts2Show .ToArray(), false);
So you have first to select content type related page layouts, just querying the publish website.
And this is what we will get
New document menu

Available page layouts

If you need the code, as usual this is the link. Go get it! and have a look at Example 06 ;) .

Monday, September 8, 2014

OnTaskCreated and DelayActivity epic fail: a inconsistent farm story

Some weeks ago a SP2010 workflow was driving me mad. I got a parallel activity and i need to wait the OnTaskCreated event on every task i was creating.
Workflow started having some strange behaviours:
  • Workflow suspended states;
  • OnTaskCreated never firing on created tasks;
I was trying to figure out what to do, and i start thinking about a porkaround, why don't simulate tha bugged OnTaskCreated with a while and a DelayActivity?
A while condition checks if task id has a value, if not, wait 5 seconds and re-check until condition is met.
Why not? It's not so elegant but it works... don't laugh please, i almost save a workflow project with this workaround.
In Italy we say: "Misfortunes always come in twos"
Delay activity seemed not to work because it put the workflow to sleep... forever. This leads me to think there were problems on customer server... and so it was (http://support.microsoft.com/kb/2553031/en-us) , in other words: update to the most recent cumulative update and cross your fingers.
In my case, i continued to have issues, so i have to develop a parachute solution to make my PM happy. When we switched to pre-production environment everything works without parachutes.
What can i say? Two subsequential MS bugs in a row... Murphy's law rulez.
P.S.:
Who laughed reading this workaround?
Read this: http://support.microsoft.com/kb/970548
No more laughs ah?

Monday, September 1, 2014

Device channel panels and web parts walktrough: the JS and content search query BUG

Let's continue from the first episode, haven't you read it? Check this link, download the code and load Example 04... Here we are and here is a smal recap from the last article...
A long time ago in a galaxy far, far away... A young SharePoint padawan was trying to use device channel panels to contitionally load web parts and app parts...
He discovers some unexpected behaviours and he found workarounds, and he was able to accomplish this task, but then he had to add javascript to the web parts and a new challenge begun...
/mode joke off
Why JS in web parts? Do you know content search query web part (we are dealing one of the new feature of SP2013) ? Well, it uses JS a lot. It means that, if you want to load content search query web part, choosing what to load according with the device channel, you are in a big trouble.

Problem repro steps
Let's use the DeviceChannelArticle_OOB page layouts i developed in Example 04 (i prefer the OOB workaround in order not to introduce unsupported code in this demo).
Let's simplify the problem and, starting from the Example 04, write a stupid alert JS script in every web part.
alert('This is the Internet Explorer web part script');
alert('This is the Mozilla Firefox web part script');
Now display the page (it's up to you to use Internet Exlorer or Mozilla Firefox).

What's happening? Even if you load the web part using device channel panels, you see alerts for both web parts... again, not a expected behaviour. The risk is to load extra data, extra scripts and extra stuffs... not so good.
Solutions
The first solution is to load JS detecting user agent from JS itself... yeah that's quite simple but... why use device channels? Rework web parts in order to use just server side code? It can be done, but you lose functionalities. I got an idea, why don't use a HttpModule to cut all the code of the wrong device channel panel? Since we are talking about a SP2013 recognized BUG (so it will be solved), we can think about HttpModule we can just plug'n'play until official fix will be realeased.

First, change page layout, switch to DeviceChannelArticle_JS, what's different from DeviceChannelArticle_OOB?

No more display/edit panel, just fields wrapped with HTML comment tags and no more device channel panels.

HttpModule will recognize user agent, understand what HTML code to cut according to tags above... yes i am reinventing the wheel.
Let's load the HttpModule using Example 05 feature to see the code in action, please be aware you need to run these powershell commands otherwise you have to edit web.config with your hands.
$contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$contentService.RemoteAdministratorAccessDenied = $false
$contentService.Update()
You can see i created a abstract class named DeviceChannelPanelHttpModule in VLibs project i've realized with DeviceChannelArticleJSHttpModule in VLibs.Examples, in order to make the module aware about device channels, inclusion rules and wrapping tags.
Let's have a look to the astract class...
public abstract class DeviceChannelPanelHttpModule : IHttpModule
{
 #region Public methods
 public void Init(HttpApplication application)
 {
  application.PostRequestHandlerExecute += new EventHandler(ApplicationPostRequestHandlerExecute);
 }

 public void Dispose()
 {
 }
 #endregion 

 #region Protected methods
 protected void ApplicationPostRequestHandlerExecute(object sender, EventArgs e)
 {
  HttpContext httpContext = HttpContext.Current;

  if (httpContext.Response.ContentType == "text/html" && BrowserRequestNeedsToBeFiltered(httpContext.Request))
  {
   httpContext.Response.Filter = LoadFilter(httpContext);                
  }
 }

 protected abstract bool BrowserRequestNeedsToBeFiltered(HttpRequest httpRequest);

 protected abstract Stream LoadFilter(HttpContext httpContext);
 #endregion
}
  • Init: just attaches handler;
  • ApplicationPostRequestHandlerExecute: it decides if page has to be filtered, it calls BrowserRequestNeedsToBeFiltered to understand what to do, and if the request has to be filtered, instantiates the filter;
  • BrowserRequestNeedsToBeFiltered: abtract method, you implement this one in order to make the module aware of the filtering rules;
  • LoadFilter: abstract method, you implement this one to decide what filter to instantiate;
Follow the code example i developed and everything will become clear.
P.S.: May thanks to Sam Betts and Stefano Merotta, they helped me with this project of doom!

Monday, August 25, 2014

Device channel panels and web parts walktrough

Hi guys, this an article i wanted to write one year ago about device channel panels in SharePoint 2013. I think you know what a device channel is, don't you?
"NO"
It's a new "exciting" SP2013 feature which could be considered as responsive web design alternative (or complement). It offers the possibility of defining different master pages, page layouts and (more important) site contents for different devices, mantaining the same website URL.
"Cool"
Wanna read more? Read official doc
http://msdn.microsoft.com/en-us/library/office/jj862343%28v=office.15%29.aspx ...and why don't read also this?
http://blog.mastykarz.nl/device-channels-sharepoint-2013/ If you wanna know more Google/Bing is your friend. I'm here to solve problems my dear.
 Problems? Have you found a problematic case?
Yeah.
If we want to load web parts as site content for different devices we have little problems. Let me show you this little bug .

A pratical example
Let's head Example 04 on the usual project (download latest version clicking here or from Download page), deploy and activate the feature Example 04. I created three device channels, but we will use just two of them during this little demo, named IE and FF: the first is a device channel for Internet Explorer browser, the second one is a device channel for Firefox browser.
I have used those device channel in order to keep it simple the most, in the real world you can detect devices using lots of user agent string combinations.
Let's create a DeviceChannelsArticlePage page with DeviceChannelArticle_Demo layout.
The content type extends Article page and has two fields: Internet Explorer field and Mozilla Firefox field.
In order to show contents conditionally, it's necessary to create fields that will be conditionally loaded. Fields will be wrapped in device channel panels, so it's like to say: "When you intercept this device, load those fields" and the page layouts become something like this
Now if we try to add HTML content using page layout everything works fine, let's try to do the same thing adding content editor webparts... so follow these steps

  1. Edit page using Internet Explorer
  2. Add a content editor web part and Save
  3. Edit the same page using Mozilla Firefox
  4. Add another content editor web part and Save
  5. View page using Internet Explorer 
Step 1 & Step 2

Step 3 & Step 4

Step 5
And, even if Internet Explorer content is here with us, web part disappeared and... this is not properly the expected behaviour, yeah?
This is because even if you add several HTML fields in order to simulate web part zones, web parts are loaded in just one web part zone called WPZ. When you edit fields you are overwriting WPZ.
Let me explain the process better:
  1. Edit page using Internet Explorer
  2. Add a content editor web part and Save >> Web part is added to WPZ
  3. Edit the same page using Mozilla Firefox >> Device channel panel don't let you see the previously added web part, this is a correct behaviour, since you don't see the previously added web part, WPZ thinks you have removed that one
  4. Add another content editor web part and Save >> It's like adding a new web part to a empty WPZ
  5. View page using Internet Explorer >> I think it's clear why you don't see anything in Internet Explorer
Solution(s)
Oh oh, and now? You have two possible solutions, the first one use OOB controls, the second one is a custom one.
OOB approach
Simply create a new page layout with this schema


Wrap device channel panels in a display mode panel, and duplicate the same fields placeholder (without device channel panels) in a edit mode panel.
This will let device channels to be used only for conditional web part display, instead fields editing will be done at single time, so WPZ will be erased no more.
 VLibs approach (applause)
Why use OOB device channel panel when you can use my overriden VLibs device channel panel?
The advantage is to keep page layout simple.

How it works?
Simply the control understand if you are editing or displaying the page and, if in edit mode, it ignores device channel recognition and shows the entire content.

For more code please download the VLibs source here.

P.S.
I sense a disturbance in the force... a new question...
"What if content editor web part contains javascript?"
Well, stay tuned... this is the content of the next article.

Wednesday, July 30, 2014

Howto solve Workflow suspended with HTTP 401 and survive to a demo

Today... demo day...
Objectives:
  •     Show the customer what he/she is paying for
  •     Satisfy customer
  •     Sell change requests
  •     Earn project bonus
So, basically, let's take another demo roundtrip and let's test all the process.
Wow everything works fine, why don't we start the workflow?
Wow... Why execution failed?

RequestorId: dbaf8233-b7f4-cc8e-0000-000000000000. Details: An unhandled exception occurred during the execution of the workflow instance. Exception details: System.ApplicationException: HTTP 401 {"error":{"code":"-2147024891, System.UnauthorizedAccessException","message":{"lang":"en-US","value":"Access denied. You do not have permission to perform this action or access this resource."}}} {"Transfer-Encoding":["chunked"],"X-SharePointHealthScore":["2"],"SPRequestGuid":["dbaf8233-b7f4-cc8e-84d2-34863a603d9b"],"request-id":["dbaf8233-b7f4-cc8e-84d2-34863a603d9b"],"X-FRAME-OPTIONS":["SAMEORIGIN"],"MicrosoftSharePointTeamServices":["15.0.0.4551"],"X-Content-Type-Options":["nosniff"],"X-MS-InvokeApp":["1; RequireReadOnly"],"Cache-Control":["max-age=0, private"],"Date":["Fri, 25 Jul 2014 14:01:50 GMT"],"Server":["Microsoft-IIS\/8.0"],"WWW-Authenticate":["NTLM"],"X-AspNet-Version":["4.0.30319"],"X-Powered-By":["ASP.NET"]} at Microsoft.Activities.Hosting.Runtime.Subroutine.SubroutineChild.Execute(CodeActivityContext context) at System.Activities.CodeActivity.InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager) at System.Activities.Runtime.ActivityExecutor.ExecuteActivityWorkItem.ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)

Wow... Why my bonus it's flying away?
Don't worry about it, the solution it's simple, even if the situation is frustrating.
The problem can be solved using central admin, look for Refresh trusted security token services metadata feed and run it now. Then make an iisreset.
If you are a lazy one use this small PowerShell
Get-SPTimerJob "RefreshMetadataFeed" | Start-SPTimerJob
And now, let's go on with demo, and with the bonus :) .

Monday, July 21, 2014

Some small (personal) updates

Hi guys, just few words.
I really want to thank you for visiting this blog, i've received lots of views and it's very important for me.
Dear visitors, i'd really like to interact more with you, so feel free to comment, ask, whatever... don't be shy :-) .
I wanna to tell you i've prepared lot of drafts during this week, and i'm going to talk about:
  • SharePoint 2013: Device channel panel and web parts
  • SharePoint 2013: Device channel panel BUG (Yes i've found it and MS is currently working to solve that!)
  • SharePoint 2013: Device channel panel BUG mitigation (Yes i've found it!)
  • SharePoint 2013: Other velocity considerations about quering objects
  • SharePoint 2010: Workflow OnTaskCreated action issue!
  • Restricting page layout and content type on SharePoint pages list
  • Security groups informations extraction via Powershell
  • Azure farm creation... with a script
"Ok, that's fine, you told us you have these draft, why don't you publish them"
Dear friends, work projects are becoming really challenging, and, meantime, i'm getting SharePoint 2013 certified... friends say i'm SharePoint addicted :-p and my head is focused on vacancies :-p ....so be patient.
BTW, first exam passed: 70-480: Microsoft said i'm expert in CSS3, Javascript, HTML 5 and so on :), and right now i'm studying MVC... really intersting technology.
If you're interested in one of these posts, please let me know, so i will focus on writing following your interests.
Please use comments below ;-) .
Share:

Wednesday, July 9, 2014

SharePoint 2013 Workflows task permission workaround

Hi there, I'm Troy McClure, maybe you remind me for the wonderful tutorial Visual studio SharePoint 2013 workflow walktrough
/mode joke off
Everyone noticed users can view/edit tasks but this is not a customer wish 99/100 times.
Someone asked me how to change task permissions so only assigned user can watch/edit/whatever task item. Unfortunally you cannot do this using Visual Studio in the OOB way and you need to create a custom Visual Studio activity, definitely not a developer-friendly task. I sense you are smiling because you think i'm gonna deliver you a custom activity you can just plug'n'play right now.
Sorry but today i'm just gonna show you a porkaround (no it's not a misprint).
I'm talking about event receivers.
Someone is saying: i already tried to do a event receiver, but it's not possible to make it run on a workflow task list. The key it's simply to change the event receiver list template n. 171.
Now use this simple piece of code you can find in example 03.
I also created a little helper method which helps you to restrict permissions without any useless roundtrip.
public static void SetPermissions(SPListItem item, List readers, List editors)
{
    SPSecurity.RunWithElevatedPrivileges(() => {
        using (SPSite site = new SPSite(item.Web.Site.ID))
        {
            using (SPWeb web = site.OpenWeb(item.Web.ID))
            {
                item = web.GetListItem(item.Url);

                item.BreakRoleInheritance(false, true);

                if (readers != null)
                { 
                    foreach (SPUser u in readers)
                    {
                        item.RoleAssignments.Add(CreateRoleAssignment(item, u, SPRoleType.Reader));
                    }
                }

                if (editors != null)
                { 
                    foreach (SPUser u in editors)
                    {
                        item.RoleAssignments.Add(CreateRoleAssignment(item, u, SPRoleType.Editor));
                    }
                }
            }
        }
    });
}

private static SPRoleAssignment CreateRoleAssignment(SPListItem item, SPUser user, SPRoleType roleType)
{
    SPRoleAssignment roleAssignment = new SPRoleAssignment(user);
    SPWeb web = item.Web;
    roleAssignment.RoleDefinitionBindings.Add(web.RoleDefinitions.GetByType(roleType));
    return roleAssignment;
}
As you can see, now young Skywalker must use the force to discover other users tasks.


Anyway, you can download the source here, and yes this is the first post of the brand new post category tips'n'tricks.Enjoy.

Tuesday, July 1, 2014

Is FAST query a data retrieval silver bullet?

Yesterday, a customer asked me pros and cons of Search in SharePoint 2013 and how it can help with FASTer queries.
I already used it on another project and i was able to make some cross site collections and cross web applications queries using just one statement, so i told him about the benefits this can imply.
Then, the customer asked me also: "And what about cross lists queries? It's better to use CAML or FAST?"
"Ehm... uhm.. sorry i have another call on hold, i'll call you back later" was the answer.
/jokes mode off
Everybody knows there are many ways to query contents across multiple SharePoint lists and, that's clear, writing code is a "depends on" work, but i started asking myself if FAST query could rule them all and be the best query method also for a simple task like cross list query (which is the CAML query dark reign).
I compared pure LINQ queries, SPSiteDataQuery, CrossListQueryInfo and KeywordQuery on the same battlefield (cross lists query), so expects some strong assumptions (borrowed from the project business case i'm following right now):
  • 1 Content Type containing 10 columns;
  • 3 List instances containing the same number of items (which are randomly generated) and the same content type;
  • Query will select all content type fields;
  • Usage of SharePoint like a DB (wrong usage, but some customers seems to love this scenario anyway);
  • Whenever it's possible, use just one query to extract data using date range;
I compared queries execution times populating lists with 2.000, 5.000, 10.000, 20.000, 50.000, 100.000, 500.000, 1.000.000 random items and i queryed just 1 list, then all 3 lists.

If you want to test on your own, as usual, download the last source code and deploy example 2.
Please note you have to follow steps below to enable your farm to support query on many items per lists:
1.  Allow object model override in web application's resource throttling options (Central administration > Manage web applications > <Your web application> > General settings > Resource throttling)
This will avoid CAML query to explode

2.  Using powershell, raise search service application max row limit.
$searchApp = Get-SPEnterpriseSearchServiceApplication
$searchApp.MaxRowLimit = 10000
$searchApp.Update()
iisreset
This will avoid KeywordQuery to extract less results than expected.

After that you can use my web part to populate list instances, launch crawler (you have to launch crawlers everytime you add new items if you haven't enabled continous crawling).
Please launch full crawl from the web part UI  the first time you add items on lists since it's necessary to install also managed property on search service application.

This is your example 02 dashboard, really fine uh? For sure, i made it.
Yes, i know you are thinking a script or a console application would be the best option to make massive import process, but i preferred to use a webpart in order to create a dummy-proof test dashboard for this example.
And now, last but not least, the numbers:

Query on single list
List items Retrieved items LINQ SPSite DataQuery CrossList QueryInfo Keyword Query
2.000 60 44ms 31ms 1ms 236ms
5.000 140 77ms 68ms 2ms 415ms
10.000 270 144ms 117ms 6ms 749ms
20.000 550 283ms 247ms 18ms 1436ms
50.000 1.370 708ms 322ms 32ms 5220ms
100.000 2.740 1387ms 747ms 70ms 10579ms
500.000 N/A N/A N/A N/A N/A
1.000.000 N/A N/A N/A N/A N/A

 

Query on 3 lists 
Items per list Retrieved items LINQ SPSite DataQuery CrossList QueryInfo Keyword Query
2.000 180 115ms 84ms 3ms 375ms
5.000 420 225ms 206ms 8ms 1123ms
10.000 810 438ms 375ms 16ms 1736ms
20.000 1.650 824ms 776ms 47ms 4084ms
50.000 4.110 1953ms 941ms 103ms 15042ms
100.000 8.220 3980ms 2635ms 198ms 29487ms
500.000 N/A N/A N/A N/A N/A
1.000.000 N/A N/A N/A N/A N/A



Results
I haven't done any tests for 500.000 and 1.000.000 items per list, this is due to the KeywordQuery boundary of 10.000 max results rows and the execution time that must be under 60 seconds per query.
The data i'm showing you are the average queries execution times, i excluded the first query because it represents the warm up (and slowest) execution time.
Well, despite my hopes, KeywordQuery doesn't seem to be the silver bullet i was waiting for. This doesn't mean it isn't a good technology, on the contrary i think it comes with a lot of advantages, but, simply, in some old-fashioned scenarios, could be better to use the old-fashioned CrossListQueryInfo way.
Download the source code

Sunday, June 22, 2014

Visual studio SharePoint 2013 workflow walktrough

In this article i will show a brief (hopefully complete) example about workflow development in SharePoint 2013. If you have developed sharepoint workflows in visual studio, you could find this article useful.

Before developing any workflow, it's necessary to link SharePoint web application to the workflow web application, so they can talk to each other.
Register-SPWorkflowService -SPSite <SharePoint Site Url> -WorkflowHostUri <Workflow web application> -AllowOAuthHttp -Force
The code of the example below can be downloaded here (or below) and it represents the first step for my little DLL for helping SharePoint development (Applause).
Please refers to the Example 1 feature referenced code to follow the example below.
In this walktrough i will develop a simple approval workflow with dinamically chosen approvers, so we assume the list item contains a SPUser multivalue field named "Approvers" (Yep, very original) with this information.
And now we can walk trough the code.

Let's have a look on the first activity, LookupSPListItem, which is one of the most important.
Like in the past, we have to bind it to the ItemId and the ListId.

Clicking on GetProperties creates a new activity below, named GetDynamicValueProperties.
Clicking on ViewProperties we can choose the entity type (in this case List Item of Item2Approve), point to the Path and assign the return value to a worflow scoped variable.
Clicking on Variables we can see all workflow scoped variables, you can notice we have approvers user in a Collection<string> variable users (remember that no SPUser variable could be a workflow scoped one because it is not a serializable class).
 
And now the most simple part, with composite task we can configure parallel/sequence task simply assigning the variable in the AssignedTo field. CompositeTask activity will resolve automagically SPUser for us.
 
And yeah, it works like a charm.
Now, let's think about how to start the workflow programmatically. In SharePoint 2010 you can find the workflow association of the list using WorkflowAssociations property of SPList object. In SP2013 I spent a lot of time trying to figure out why this property was not populated with my workflow, when i found out also the workflow template was not registered to the site.
So i realize...

Remember the stuffs about the other web application and so on?
We have to call the new shiny Workflow service manager.
At first we havo to include the (almost hidden) library
C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SharePoint.WorkflowServicesBase
Then we have to call this piece of code
public static void StartWorkflow(SPListItem item, Guid workflowDefinitionId, Dictionary parameters)
{
    SPSecurity.RunWithElevatedPrivileges(() =>
    {
        if (parameters == null)
        {
            parameters = new Dictionary();
            parameters.Add("a property", "a value");
        }

        SPWeb web = item.Web;
        SPList list = item.ParentList;

        WorkflowServicesManager workflowServiceManager = new WorkflowServicesManager(web);
        WorkflowSubscriptionService workflowSubscriptionService = workflowServiceManager.GetWorkflowSubscriptionService();
        WorkflowSubscriptionCollection subscriptions = workflowSubscriptionService.EnumerateSubscriptionsByList(list.ID);

        WorkflowSubscription subscription = subscriptions.FirstOrDefault(w => w.DefinitionId.Equals(workflowDefinitionId));

        if (subscription != null)
        {
            workflowServiceManager.GetWorkflowInstanceService().StartWorkflowOnListItem(subscription, item.ID, parameters);
        }
    });
}
And yep, for now, that's all. May the force be with you.

Download source code

Monday, April 28, 2014

SharePoint 2013 on i5? Sure (if you have a SSD)

Yesterday i was looking for an answer to the question: Will Dell Latitude E7440 run SP2013 like a charm or i'll have to ask for another notebook?
Even if I looked around for a clear answer, as usual, the best way was try for myself.
Let's start from my hardware configuration:

CPU: Intel i5-4300
RAM: 8GB
HD: 250GB SSD (makes the real difference)
OS: Windows 8.1 Enterprise

I choose to install everything on a single virtual machine (ADDS features, SQL 2012 SP1 and SP2013) and i noticed the VM was very slow.
Opening Task Manager, i had enough clues about the most CPU and RAM consuming processes: my first enemy was Windows Module Installer Worker.
So i switched Windows Update settings on "Never check for updates".
Do we really need automatic updates on a develompment machine ? Mmm i don't think so.
This helped me lowering CPU consumption but it wasn't enough.
The second potential process was SQL Server NT Process. Especially when i tried to access SharePoint site i experienced extremely slow responses, so i found some interesting tweaks that dramatically boosted up my dev machine.
Using SQL server management studio i went on database server properties and set up two properties.
On memory i set up the maximum RAM SQL server have to use (in my case 2048MB)


Another useful setting was boost SQL server priority among processes section, this helped me a lot making the VM really responsive to SharePoint requests.



After that, what i could furthermore do was to switch off SharePoint search indexing service. You don't need continous crawling during development, you can run it manually whenever you need.


What you can do furthermore? Switch off SharePoint services you don't need but i noticed it doesn't help you a lot. I also shut down not needed web applications. So, after this adventure i went from 80% to 5% CPU consumption, and from 90% to 50% RAM consumption with a SharePoint reactivity improvement and... that's all folks.

Me, myself and I

My Photo
I'm just another IT guy sharing his knowledge with all of you out there.
Wanna know more?