Freitag, 17. April 2015

Flatten dictionary to string

Problem:
How to save the content of a dictionary into a string?

Solution:

Dictionary<string, string> testDic = new Dictionary<string, string>();
testDic.Add("key1", "value1");
testDic.Add("key2", "value2");
testDic.Add("key3", "value3");

// flatten dictionary
string resultStr = string.Join(";", testDic.Select(y => y.Key + "=" + y.Value));

// reverse
Dictionary<string, string> resultDic = resultStr.Split(';').Select(x => x.Split('=')).ToDictionary(x => x[0], y => y[1]);


             
How to do it with a nested dictionary?

Solution:
Dictionary<string, Dictionary<string, double>> testDic = new Dictionary<string, Dictionary<string, double>>();

testDic.Add("key1", new Dictionary<string, double>());
testDic["key1"].Add("key11", 11);
testDic.Add("key2", new Dictionary<string, double>());
testDic["key2"].Add("key21", 21);
testDic["key2"].Add("key22", 22);
testDic.Add("key3", new Dictionary<string, double>());
testDic["key3"].Add("key31", 31);

// flatten dictionary
string resultStr = string.Join("|", testDic.Select(x => x.Key + ":" + string.Join(";", testDic[x.Key].Select(y => y.Key + "=" + y.Value))));

// reverse
Dictionary<string, Dictionary<string, double>> resultDic = new Dictionary<string, Dictionary<string, double>>();
Dictionary<string, string> tmpDic = resultStr.Split('|').Select(x => x.Split(':')).ToDictionary(x => x[0], y => y[1]);
tmpDic.ToList().ForEach(t => resultDic.Add(t.Key, t.Value.Split(';').Select(x => x.Split('=')).ToDictionary(x => x[0], y => Convert.ToDouble(y[1]))));
 

Montag, 30. März 2015

ExecuteOrDelayUntilScriptLoaded not working

Problem:
ExecuteOrDelayUntilScriptLoaded in a page or specifically in a publishing page does not work.
This might be also the case when a user who has only read/view access to the site, sp.js refuses to load when ExecuteOrDelayUntilScriptLoaded is used.

Solution:
In SharePoint 2013, the correct way to execute a function after script is loaded is to use SP.SOD class and not ExecuteOrDelayUntilScriptLoaded.
For example I needed to use it in:
 
function openInDialog(dlgWidth, dlgHeight, dlgAllowMaximize, dlgShowClose, pageUrl ) {
      var options = {
          url: pageUrl,
          width: dlgWidth,
          height: dlgHeight,
          allowMaximize: dlgAllowMaximize,
          showClose: dlgShowClose
      };

      options.dialogReturnValueCallback = Function.createDelegate(null, CloseDialogCallback);
      SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', options);
  }


  function CloseDialogCallback(dialogResult, returnValue) {
      if (dialogResult == SP.UI.DialogResult.OK) { // refresh parent page
          SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.RefreshPage', SP.UI.DialogResult.OK);
      }
      // if user click on Close or Cancel
      else if (dialogResult == SP.UI.DialogResult.cancel) { // Do Nothing or add any logic you want
      } else { //alert("else " + dialogResult);
      }
  }

Sonntag, 22. März 2015

Create client-side email using mailto before server postback

Problem:
So it looks like it isn't a good idea to set the window.location.href before a postback.

 I tried a few options, like using the setTimeout function to force setting window.location.href slightly later in the JS thread lifecycle. But that didn't work; it seemed that any alteration of the DOM's location was causing issues with the postback.

So how can we get the browser to call the mailto link without affecting the postback?
Use an iframe, as the source of the iframe would be separate from the current document and should not interfere with any postbacks.
I modified my CreateEmail function so it would create a new iframe with its src attribute set to the mailto link, append it to the document body so the browser would execute the mailto link, and then remove it again from the DOM:
Solution:

<script type="text/javascript">

  function CreateEmail() {
    var mailto =  'mailto:?to=any@anydomain.com';

    $('<iframe />')
       .prop('src', mailto)
       .css('display', 'none')
       .appendTo('body')
       .remove();
  }
</script>

Montag, 16. März 2015

Setting EventFiringEnabled property from Powershell

You would like to upload documents to a document library via Powershell and disable events that might be fired or don't start workflows on this item change?

How to set the EventFiringEnabled property from Powershell?

Solution:
Actually this is not really something you generally do from PowerShell. The purpose of EventFiringEnabled is to prevent an event receiver from triggering the same event recursively.
However,  you can switch it off for the thread upon which your PowerShell code is running:

$myAss = [Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint");
$type = $myAss.GetType("Microsoft.SharePoint.SPEventManager");
$prop = $type.GetProperty([string]"EventFiringDisabled",[System.Reflection.BindingFlags] ([System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Static));
$prop.SetValue($null, $true, $null);
#code to update list goes here!

Donnerstag, 3. Juli 2014

SharePoint ThreadAbortException

Problem: If you are doing a SPSite.OpenWeb() (or maybe its done for you, when you request the profile service) and you do not have the permissions to the site there is an UnauthorizedAccessException being thrown. But if you are trying to catch it, immediately after the catch an ThreadAboardException is thrown and you code does not continue. That is because of access denied exceptions inside page requests are explicitly handled by the platform. For example, when Forms-based authentication is used, anonymous users are redirected to the login page. If the user is already authenticated, he may be redirected to an error message page such as _layouts/AccessDenied.aspx.
When you are developing web parts that behavior is okay but running such code in a timer job or WCF webservice is problematic.

Solution: You should turn off that behaviour by setting the following flag:

bool originalCatchValue = SPSecurity.CatchAccessDeniedException;
SPSecurity.CatchAccessDeniedException = false;

try
{
   // your code

}
finally
{
   SPSecurity.CatchAccessDeniedException = originalCatchValue;
}


Within the try statement you are able to catch the UnauthorizedAccessException as usual.


2nd Problem: Another reason you get a ThreadAbortException could be that your request could not be validated by SharePoint. This could be the case if you are developing a WCF webservice within SharePoint context. In the exception stacktrace you should see  Microsoft.SharePoint.SPWeb.ValidateFormDigest()

Solution:
In this case SPContext.Current is not null, Sharepoint tries to verify requests using security validation digest provided by FormDigest Class. According to msdn:
"To make posts from a Web application that modify the contents of the database, you must include the FormDigest control in the form making the post. The FormDigest control generates a security validation, or message digest, to help prevent the type of attack whereby a user is tricked into posting data to the server without knowing it. The security validation is specific to a user, site, and time period and expires after a configurable amount of time. When the user requests a page, the server returns the page with security validation inserted. When the user then submits the form, the server verifies that the security validation has not changed".
In WCF service you don't have security digest. To avoid this check try to set HttpContext.Current to null temporary when you call siteCollection.Add() method:

var ctx = HttpContext.Current;
try
{
    HttpContext.Current = null;
    // your code
}
finally
{
    HttpContext.Current = ctx;
}

Donnerstag, 19. Juni 2014

UserProfile Sync problem:Could not connect to http://(server):5725/ResourceManagementService/MEX

Problem: You are trying to sync user profiles from active Directory and get an error:

Could not connect to :5725/ResourceManagementService/MEX. TCP error code 10061: No connection could be made because the target machine actively refused it


Solution: Verify that windows service "Forefront Identity Manager Service" and "Forefront Identity Manager Synchronization Service" are started. If not, please start them and then check the effect.

Mittwoch, 16. April 2014

Office 2013 breaks your SharePoint 2010

Problem:
After installing Office 2013 on your SharePoint 2010 box you experience the following, when trying to upload an InfoPath form:

There are some policy files that reference the wrong assemblies. The following post got me to the right solution: http://smindreau.wordpress.com/2012/12/04/office-preview-2013-breaks-your-sharepoint-2010-enterprise-notably-infopath/

Solution:
Basically you must:
1. Entering the path C:\Windows\Assembly\GAC_MSIL in the Start/Run
2. Delete the following three folders:
 Policy.14.0.Microsoft.Office.InfoPath
 Policy.14.0.Microsoft.Office.InfoPath.Client.Internal.Host
 Policy.14.0.Microsoft.Office.InfoPath.FormControl
3. Run an IISRESET from a command prompt.