Curia Damiano blog

Insert my slogan here...

Error in TypeScript compilation when upgrading to VS DEV15 and TypeScript 2

If you upgrade to TypeScript 2 (incidentally, done automatically by installing VS DEV15), you can get the following errors in a web project containing TypeScript files:

  • The "VsTsc" task could not be initialized with its input parameters.
  • The "OutputLogFile" parameter is not supported by the "VsTsc" task. Verify the parameter exists on the task, and it is a settable public instance property.

You need to open a Notepad as administrator and edit the file C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v15.0\TypeScript\Microsoft.TypeScript.targets, removing the OutputLogFile parameter.

Invoking the debugger from a .NET application

Recently I was in a particular debugging situation where the process that was debugged by Visual Studio was launching another process, and I needed to debug the startup of this second process too (no way to attach to the process from the IDE, then).

So something like the "debugger" instruction in JavaScript.


I have found that the solution is to call:

    System.Diagnostics.Debugger.Launch();

Process Monitor in Windows 10 error

If when running Process Monitor in Windows 10 you get the error 

   Unable to write PROCMON23.SYS.

   Make sure that you have permission to write to the %%SystemRoot%%\System32\Drivers directory.

then you can follow the suggestion from Error from Process Monitor: “Unable to write PROCMON23.SYS”: "go into C:\Windows\System32\drivers and rename procmon23.sys to something else, then try to enable boot logging from options menu again".

SharePoint 2013: how get the managed navigation from CSOM and REST

SharePoint 2013 has introduced the Managed Metadata Navigation.

To get the managed navigation from client side code, an excellent introduction for JSOM is presented in Get Navigation Taxonomy term tree in SharePoint App, where we have the following points:

  1. get the taxonomy session from the current client context
  2. get the current navigation settings, to retrieve the term store id and the term set id of the terms storing the navigation for the current site
  3. load the term set
  4. load the navigation term set, i.e. the term set "casted" as navigation term set, so offering the additional navigational properties (note: the navigation term set doesn't inherit from from the standard term set)

I needed to do the same from C# code, containing CSOM calls, and here are more or less the same steps, even if we need first to convert the claim token to a Windows identity. Here is the CSOM file: SharePointNavigationProvider_CSOM.cs (7.4KB)

        private WindowsIdentity GetWindowsIdentity()
        {
            WindowsIdentity windowsIdentity = null;

            SPSecurity.RunWithElevatedPrivileges(() =>
            {
                ClaimsIdentity identity = (ClaimsIdentity)Thread.CurrentPrincipal.Identity;
                string upnFromClaim = identity.Claims.Where(c => c.ClaimType == ClaimTypes.Upn).First().Value;

                try
                {
// To get the current Windows identity, we need the Claims to Windows Token Service started on all frontends of the SharePoint farm
                    windowsIdentity = S4UClient.UpnLogon(upnFromClaim);
                    if (windowsIdentity == null)
                        throw new ApplicationException("windowsIdentity == null");
                }
                catch (System.ServiceModel.EndpointNotFoundException ex)
                {
                    throw new ApplicationException("The Claims to Windows Token Service is not running on this frontend", ex);
                }
                catch (System.ServiceModel.Security.SecurityAccessDeniedException ex)
                {
                    throw new ApplicationException("Unable to communicate with the domain controller", ex);
                }
            });

            return windowsIdentity;
        }

        private TermSet GetTermSet(ClientContext clientContext)
        {
            TaxonomySession taxonomySession = TaxonomySession.GetTaxonomySession(clientContext);
            StandardNavigationSettings navigationSettings = new WebNavigationSettings(clientContext, clientContext.Web).CurrentNavigation;
            clientContext.Load(navigationSettings,
                navSettings => navSettings.TermStoreId,
                navSettings => navSettings.TermSetId);
            clientContext.ExecuteQuery();

            TermStore termStore = taxonomySession.TermStores.GetById(navigationSettings.TermStoreId);
            TermSet termSet = termStore.GetTermSet(navigationSettings.TermSetId);
            clientContext.Load(termSet);
            return termSet;
        }

        private void GetNavigationTermSet(ClientContext clientContext, TermSet termSet,
            out NavigationTermCollection navTerms, out NavigationTermCollection allNavTerms)
        {
            NavigationTermSet navigationTermSet = NavigationTermSet.GetAsResolvedByWeb(clientContext, termSet, clientContext.Web, "GlobalNavigationTaxonomyProvider");
            clientContext.Load(navigationTermSet);

            navTerms = navigationTermSet.Terms;
            clientContext.Load(navTerms,
                terms => terms.Include(term => term.Id));

            allNavTerms = navigationTermSet.GetAllTerms();
            clientContext.Load(allNavTerms,
                terms => terms.Include(
                    term => term.FriendlyUrlSegment,
                    term => term.HoverText,
                    term => term.Id,
                    term => term.LinkType,
                    term => term.SimpleLinkUrl,
                    term => term.Terms,
                    term => term.Title));

            clientContext.ExecuteQuery();
        }

        List<NavigationNodeInfo> BuildRecursiveNodeList(string url, NavigationTermCollection allNavTerms, NavigationTermCollection currentNavTerms, int maxDepth)
        {
            List<NavigationNodeInfo> Result = new List<NavigationNodeInfo>(currentNavTerms.Count);
            foreach (NavigationTerm navTerm in currentNavTerms)
            {
                NavigationTerm currentTermInAllTerms = allNavTerms.First(term => term.Id == navTerm.Id);
                NavigationNodeInfo navNodeInfo = new NavigationNodeInfo
                {
                    Title = currentTermInAllTerms.Title.Value,
                    Url = currentTermInAllTerms.LinkType == NavigationLinkType.FriendlyUrl ?
                        SPUtility.ConcatUrls(url, currentTermInAllTerms.FriendlyUrlSegment.Value) :
                        currentTermInAllTerms.SimpleLinkUrl,
                    HoverText = currentTermInAllTerms.HoverText
                };

                if (maxDepth > 1 && currentTermInAllTerms.Terms.Any())
                    navNodeInfo.Childs = BuildRecursiveNodeList(url, allNavTerms, currentTermInAllTerms.Terms, maxDepth - 1);
                
                Result.Add(navNodeInfo);
            }
            return Result;
        }


This solution, even if technically correct, has the disadvantage that these multiple CSOM calls are very slow.
An alternative to improve the performances is to use the REST calls (still after having impersonated the calling user). Here is the REST file: SharePointNavigationProvider_REST.cs (5.3KB)

private XDocument GetWebAppNavigationRest(WindowsIdentity windowsIdentity, string url)
{
using (new SPMonitoredScope("SZH.IntraZueri.Core.Providers.Navigation.SharePointNavigationProvider.GetWebAppNavigationRest"))
{
XDocument Result;

// Impersonating the user requires Kerberos in place
using (WindowsImpersonationContext ctx = windowsIdentity.Impersonate())
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(SPUtility.ConcatUrls(url,
"_api/navigation/menustate(mapprovidername='GlobalNavigationTaxonomyProvider')")); //CurrentNavigationSwitchableProvider
request.Method = "GET";
//request.ContentType = "application/json";
request.Credentials = CredentialCache.DefaultNetworkCredentials;

using (new SPMonitoredScope("SZH.IntraZueri.Core.Providers.Navigation.SharePointNavigationProvider.GetWebAppNavigationRest.ServiceInvoke"))
//using (WebResponse webResponse = request.GetResponse())
using (Task<WebResponse> asyncResponse = webReq.GetResponseAsync())
{
asyncResponse.Wait();
using (WebResponse response = asyncResponse.Result)
using (Stream webStream = webResponse.GetResponseStream())
Result = XDocument.Load(webStream);
}

return Result;
}
}
}

private List<NavigationNodeInfo> BuildRecursiveNodeList(XElement parentNode, XNamespace ns, string url, int maxDepth)
{
List<NavigationNodeInfo> Result = new List<NavigationNodeInfo>();

foreach (XElement currElement in parentNode.Elements())
{
// Check isHidden flag. If it's hidden, don't include in result set
string isHiddenStr = currElement.Element(ns + "IsHidden").Value;
bool isHidden;
bool.TryParse(isHiddenStr, out isHidden);
if (isHidden)
continue;

string title = currElement.Element(ns + "Title").Value;
string friendlyUrlSegment = currElement.Element(ns + "FriendlyUrlSegment").Value;
string simpleUrl = currElement.Element(ns + "SimpleUrl").Value;
string linkUrl;
if (!string.IsNullOrEmpty(friendlyUrlSegment))
linkUrl = SPUtility.ConcatUrls(url, friendlyUrlSegment);
else
linkUrl = SPUtility.ConcatUrls(url, simpleUrl);
List<NavigationNodeInfo> childs;
if (maxDepth > 1)
childs = BuildRecursiveNodeList(currElement.Element(ns + "Nodes"), ns, url, maxDepth - 1);
else
childs = new List<NavigationNodeInfo>();

NavigationNodeInfo navNodeInfo = new NavigationNodeInfo
{
Title = title,
Url = linkUrl,
Childs = childs
};
Result.Add(navNodeInfo);
}
return Result;
}

1Password: how use OneDrive to share content between PC, Mac and iPhone/iPad

To avoid the stupid problem of the DropBox icons overwriting the OneDrive and OneDrive for Business icons explained in OneDrive: sync icons not showing problem, I've chosen to uninstall DropBox.

In the end, I was using it only to share my 1Password vaults between PC, Mac and iPhone/iPad. OneDrive has the advantage of being integrated in Windows and also with Office 365 you have 1Tb of space for free.


On the Mac:

  • go to 1Password preferences, sync tab, and change it to folder (choose a folder inside OneDrive)
  • it will ask if you are sure to delete the files in DropBox, take risk and say yes
  • to uninstall DropBox: close it (from the top right menu), and from the Activity Monitor kill all the DropBox processes still running. Then you can drag the application icon to the trask
  • in Finder, search for DropBox, you will still find a folder in your profile; delete it
On the PC:
  • run both the DropBox and OneDrive sync
  • open 1Password, it will automatically ask to open the vault from another source; choose the OneDrive folder
  • uninstall DropBox
  • search for all the DropBox folders and delete them (this can require the reboot of the computer)
On the iPhone/iPad:
  • so far you can't use directly the OneDrive folder, so you need to use wifi sync
  • from the Mac, Preferences | Wifi Server, check "Run a Wi-Fi server trom this Mac"
  • from the iPhone/iPad, start 1Password and dismiss the message about DropBox
  • from Settings | Sync | Start Syncing | Sync using Wi-Fi, select your Mac and enter the secret phrase from the Mac, then finally you can "Sync Now"

Xamarin: adding Android components with problems

Working on a Xamarin project, I have added a component but I had some problem: the component was downloaded, but the dll was not referenced in the project.

I have found the explanations of the guide Walkthrough: Including a Component in your project, but it must be something simple because I add the component inside Visual Studio 2015.

Then I've found the help Quick work around for unresolved Xamarin components in Visual Studio, and I thought that this could be the case, but the files were already on the disc so the issue was not about the path length.

In the end the component was badly downloaded on the first instance, and I had to:

  • remove the components from my project
  • remove the NuGet packages related to the components from my project (founding this took me really a lot of time...)
  • clear the Components folder at the solution level
  • clear the Packages folder at the solution level

OneDrive: sync icons not showing problem

On my fresh Windows 10 installation, I had OneDrive, OneDrive for Business and Dropbox.

I was able to see only the Dropbox icons, but not the OneDrive ones.

The solution is to go to the registry settings under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers and ensure that there are max 15 entries.

In my case I had this:



So in my case I have delete the Dropbox icons, and now I can see the OneDrive sync status.



Addendum:

taking inspiration from the blog post Managing overlay icons for Dropbox and TortoiseSVN and TortoiseGit, I see that the best solution is to keep the important icons for both OneDrive, OneDrive for Business and DropBox (for DropBox, I keep the icons 1, 2, 5, and 7). So in total I have now 14 entries, and I should be fine.

My registry settings now are:



Xamarin: how to use OneDrive and TFS or Visual Studio Online on a Mac

For Xamarin projects on a Mac, you can share source files with cloud based file sharing systems like OneDrive, or use source versioning systems like TFS or Visual Studio Online.

If you want to use OneDrive, you need to download it from the Mac AppStore. Here there is the direct link.
Once you setup OneDrive, as usual you can choose what folder to sync. Maybe for a Mac you don't want to sync everything, but only a folder used to share files with the PC for the Xamarin projects.
In case you want to change the synced folders, you can access the OneDrive preferences menu from the top right of your screen.
Important is not to forget in the OneDrive preferences to check "Open at login".
The advantage of this solution is that it is simple and doesn't require any additional software (apart from the OneDrive client itself), but impractical in enterprise scenarios, because you don't keep your TFS folders synced in in OneDrive.

In the second case, using TFS or Visual Studio Online, how do you do it? I recap here the updated steps to use TFS or Visual Studio Online on a Mac:
  • download Eclipse from www.eclipse.org/downloads (I have chosen the version "Eclipse IDE for Java EE Developers"), then after opening the zip file, move it to the Applications folder in Finder;
  • start the application
  • then it will ask for the workspace, accept the default path and check "Use this as the default and do not ask again"
  • go to the Team Explorer Everywhere 2015 plugin and select TFSEclipsePlugin-UpdateSiteArchive-14.0.1.zip; if the download doesn't start automatically, the direct link is here);
  • after the download, right click on the file, Open, to uncompress it;
  • from the Help menu (on Mac, it is on top of the screen...), Install New Software, Add button, Local button, select the folder named "TFSEclicsePlugin..." created at the previous step, then Next, Next, accept the licence terms, Finish
  • in Eclipse, Window | Show View | Other, select Team Foundation Server | Team Explorer
  • now click on "Connect to Team Foundation Server" or "Sign up for Visual Studio Online", based on your case; then provide the connection information, and select the project you want to connect
  • finally create a workspace in the workspace folder created previously (when you have installed Eclipse, anyway it should be in the user documents folder), then get all the files

From Xamarin Studio on Mac, it's now possible to open the solution from the workspace folder whose files have just been retrieved.

For this blog post I've used references from:

VS2015 Android emulator: multiple issues

Visual Studio 2015 introduces the new Android emulator. What is great is that it is based on Hyper-V technology, so hardware virtualization, as described more extensively in Introducing Visual Studio’s Emulator for Android.

Using it to develop Xamarin application, I've run into some issues, and I think that it would be good to collect them here:

  • first of all, during my first attempt to run it to debug a simple application, I got in the Output windows of Visual Studio this cryptic error:
         In mgmain JNI_OnLoad
         
    Couldn't connect to logcat, GetProcessId returned: 0
    As described in 
    Can't run app on Visual Studio 2015 emulator (DWP Handshake failed), the solution is to go to the Android project settings and in the Android Options tab, disable Fast Deployment
  • the second problem was that because of my naming convention for demo projects, I had a too long project name.
    Doing some attempts, I've verified that the longest project name you can give is 37 characters (more create problems with the deployment);
  • when I've been finally able to run my application, I've noticed that I had multiple graphic issues (even if the application is really basic).
    As described in Visual studio android emulator will not start fully, you have to go to the folder C:\Program Files (x86)\Microsoft XDE\10.0.10240.0\SKUs\Android, edit the file xdesku.xml and delete/comment the line:
         GuestDisplayProvider="VsEmulator.OpenGLGuestDisplay"