Monday 23 July 2018

Using MSMQ with WCF and message security

This article will present how you can get started using MSMQ as the communication protocol with WCF and apply message level security. MSMQ has got some strengths compared to HTTP requests and other communication protocols:
  • Requests are default durable, that is if the server is down, the client can send the messages to the server later when it is back again
  • There are no responses as the protocol is one-way and sometimes avoiding a response is a gain
  • All requests are queued and can be made ordered. Using transactional MSMQ queues allows requests only be sent once
  • It can utilize features such as Journal, system queues such as poison messages and dead letters and integrates well with Biztalk
  • It is the most resilient and sturdy communication protocol around and works well also in server-server scenarios and for clients
It also has some weaknesses:
  • There are no responses, so it requires to inspect the queue(s) if something went wrong
  • If there are a lot of messages, chances are that MSMQ queues will go full - it is not the quickest protocol
  • Clients must also have MSMQ installed, not default set up in Windows
  • There is a learning curve for developers and users as MSMQ is less known protocol compared to HTTP, HTTPS and TCP
I have created a sample to get you started with WCF and MSMQ. It will support Message-level security with self signed certificates for client and server. First clone this repo with Git:
git clone https://toreaurstad@bitbucket.org/toreaurstad/demonetmsmqwcfgit.git

Open up the solution in Visual Studio (2017 or 2015). First off, the solution needs to set up self signed certificates for client and server on your developer PC. Run the Script in the Scripts folder in the Host project, the Powershell script is: CreateCertificatesMsmqDemo.ps1 Run it as admin, as it will use Powershell to generate a new certificate, copy over Openssl.exe to c:\openssl folder (if you already have c:\openssl populated, you might want to change this) and convert the certificate to have a RSA format instead of CNG. There are more setup to do, such as selecting your web site in Internet Information Server admin (inetmgr) and setting up enabled protocols to http, net.msmq for the web site for this solution. You need to install MSMQ as a feature in Windows with required subfeatures. Also after the certificates are installed, right click them (in MMC you select Local Computer and Personal certificate store) and select Manage private keys. Now adjust security settings here so that your App Pool user can access the certificates for MSMQ.

Here is where you in Inetmgr (IIS Admin) set up enabled protocols to MSMQ for the web site of this article:
Moving on to the solution itself, I will describe the implementation details. Note that the creation of the MSMQ queue is helped programatically, as the queue cannot be created automatically by WCF. I created a ServiceHostFactory class to create the MSMQ queue that is used in the communication between the client and server.
using System;
using System.Configuration;
using System.Messaging;
using System.ServiceModel;
using System.ServiceModel.Activation;

namespace WcfDemoNetMsmqBinding.Host
{
    public class MessageQueueFactory : ServiceHostFactory
    {

        public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
        {
            CreateMsmqIfMissing();
            return base.CreateServiceHost(constructorString, baseAddresses);
        }

        public static void CreateMsmqIfMissing()
        {
            string queueName = string.Format(@".\private$\{0}", MessageQueueName);
            if (!MessageQueue.Exists(queueName))
            {
                MessageQueue createdMessageQueue = MessageQueue.Create(queueName, true);
                string usernName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
                createdMessageQueue.SetPermissions(usernName, MessageQueueAccessRights.FullControl);

            }
        }

        public static string MessageQueueName
        {
            get
            {
                return ConfigurationManager.AppSettings["QueueName"];

            }
        }

    }
}
This class will create the MessageQueue if it is missing. The QueueName is an appsetting in web config. The .svc file for the Msmq service contains a reference to the factory.

<%@ ServiceHost Language="C#" Debug="true" Service="WcfDemoNetMsmqBinding.Host.MessageQueueService" Factory="WcfDemoNetMsmqBinding.Host.MessageQueueFactory" %>

Now, the setup of the wcf service is done declaratively in web.config (it could be done in code, but I chose to use web.config for most of this sample for defining the MSMQ service). This is the web.config that define the MSMQ service, as you can see it is not very extensive to get started with MSMQ and WCF:

<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
    <add key="QueueName" value="DemoQueue3" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1"/>
  </system.web>
  
  <system.serviceModel>

    <services>
      <service name="WcfDemoNetMsmqBinding.Host.MessageQueueService" behaviorConfiguration="NetMsmqBehavior">
        <endpoint contract="WcfDemoNetMsmqBinding.Host.IMessageQueueService" name="NetMsmqEndpoint" 
                  binding="netMsmqBinding" bindingConfiguration="NetMsmq" address="net.msmq://localhost/private/DemoQueue3" />
      </service>    
    </services>

    <bindings>
      <netMsmqBinding>
        <binding name="NetMsmq" durable="true" exactlyOnce="true" receiveErrorHandling="Move" useActiveDirectory="False" queueTransferProtocol="Native">
          <security mode="Message">
            <message clientCredentialType="Certificate"/>
          </security>
        </binding>
      </netMsmqBinding>
    </bindings>
    
      
    <behaviors>
      <serviceBehaviors>
        <behavior name="NetMsmqBehavior">
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
        <serviceCredentials>
          <serviceCertificate findValue="MSMQWcfDemoserver" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
            <clientCertificate>
              <certificate findValue="MSMQWcfDemoClient" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
              <authentication certificateValidationMode="PeerTrust" />
            </clientCertificate>
        </serviceCredentials>
        
        </behavior>
      </serviceBehaviors>
    </behaviors>

  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

Note that the two certificates that were generated in this sample is set up in serviceCredentials element. We define the serviceCertificae and clientCertificate here. The client takes note to point to the same queue, net.msmq://localhost/private/DemoQueue3 Note that this example is tested with the client and server on same machine. The client could have a local queue in case the server was on a different machine to support durability in the scenario of many computers The client sets up the corresponding certificates in the app.config:
 
 <?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <system.serviceModel>
        <bindings>
            <netMsmqBinding>
                <binding name="NetMsmqEndpoint">
                    <security mode="Message">
                        <message clientCredentialType="Certificate" algorithmSuite="Default" />
                    </security>
                </binding>
            </netMsmqBinding>
        </bindings>
      <behaviors>
        <endpointBehaviors>
          <behavior name="MsmqEndpointBehavior">
            <clientCredentials>
              <clientCertificate storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName"
                                  findValue="MSMQWcfDemoClient" />
              <serviceCertificate>
                <defaultCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="MSMQWcfDemoserver"/>
              </serviceCertificate>
            
            </clientCredentials>
            
          </behavior>
        </endpointBehaviors>
      </behaviors>
        <client>
            <endpoint address="net.msmq://localhost/private/DemoQueue3" binding="netMsmqBinding"
                bindingConfiguration="NetMsmqEndpoint" behaviorConfiguration="MsmqEndpointBehavior" contract="MessageQueueServiceProxy.IMessageQueueService"
                name="NetMsmqEndpoint">
              <identity>
                <dns value="MSMQWcfDemoServer"/>
              </identity>

            </endpoint>
        </client>
    </system.serviceModel>
  <system.web>
    <compilation debug="true" />
  </system.web>
</configuration>

All in all, we end up with a sample where you can communicate between a client and a service using WCF with durable and ordered requests using NetMsmqBinding. As I have presented in earlier articles, the communication is actually in the form of WCF message inside every MSMQ message. The WCF message itself is protected, as this picture shows.

(it is protected using the self signed certificate we generated)
The Powershell script InspectMessageQueueWcfContent.ps1 is included, if you want to inspect the WCF messages themselves of the queue themselves. Note that if you enable Journal on the MSMQ queue this solution creates, you can see the MSMQ messages after they have been received and consumed, using compmgmt.msc Or an alternative is to use QueueExplorer instead, available as a trial here: Queue Explorer
This tool can view the WCF message inside the MSMQ message as in my Powershell script, but also display syntax coloring and other functionality for quickly navigation of your MSMQ queues. Are MSMQ in WCF an alternative for ordinary scenarios using HTTP, TCP or Federated bindings? This article was meant at least to give a demo of the capability WCF gives developers to utilize MSMQ as the communication protocol between client and server. Hope you found this article interesting.

Sunday 22 July 2018

Self-signed certificates in .NET with RsaCryptoServiceProvider

This article is written after experiencing how difficult it is today to create self-signed certificates that works with .NET and specificially WCF. If you use the default method in Windows, using the cmdlet New-SelfSignedCertificate in Powershell, chances are high that you will stumble upon this error: System.Security.Cryptography.CryptographicException: Invalid provider type specified. A few years back, creating certificates was way easier using makecert.exe Then Windows required the certificates to have length of minimum 1024. After some years passed, makecert.exe was deprecated. Microsoft now offers .NET developers to create a self signed certificate the cmdlet New-SelfSignedCertificate to use in development and test environments. Actually it turns out that you still must adjust the private part of certificate to use the RSACryptoServiceProvider by using OpenSSL to achieve this and then import to the certificate, sadly Microsoft gives developers tools for self-signed certificate generation that needs to use third-part libraries such as SSLR to work properly with .NET, at least this is the case with WCF.. Here is the Powershell script I ended up with:
 Write-Host "Generating a self signed certificate for client in MSMQ WCF demo"

$clientCertFile = "C:\temp\MSMQWcfDemoClient.pfx" 

$clientCertFileRsaFormatted = "C:\temp\MSMQWcfDemoClient.RSAConverted.pfx"

$cert = New-SelfSignedCertificate -Subject "CN=MSMQWcfDemoClient" -certstorelocation cert:\localmachine\my `
-NotAfter (Get-Date).AddYears(3) -KeyLength 2048 -KeySpec KeyExchange
$pwd = ConvertTo-SecureString -String ‘bongo’ -Force -AsPlainText 
$path = 'cert:\localMachine\my\' + $cert.thumbprint 
Export-PfxCertificate -cert $path -FilePath $clientCertFile -Password $pwd

$clientCertPasswordSec = ConvertTo-SecureString "bongo" -AsPlainText -Force


Write-Host "Generating a self signed certificate for server in MSMQ WCF demo"

$serverCertFile = "C:\temp\MSMQWcfDemoServer.pfx" 

$serverCertFileRsaFormatted =  "C:\temp\MSMQWcfDemoServer.RSAConverted.pfx"

$certServer = New-SelfSignedCertificate -Subject "CN=MSMQWcfDemoserver" -certstorelocation cert:\localmachine\my `
  -NotAfter (Get-Date).AddYears(3) -KeyExportPolicy Exportable -KeyLength 2048  -KeySpec KeyExchange
$pwdServer = ConvertTo-SecureString -String ‘kongo’ -Force -AsPlainText
$pathServer = 'cert:\localMachine\my\' + $certServer.thumbprint 
Export-PfxCertificate -cert $pathServer -FilePath $serverCertFile -Password $pwdServer

$serverCertPasswordSec = ConvertTo-SecureString "kongo" -AsPlainText -Force

$command = @'
cmd.exe /c c:\temp\rsaconvert.bat
'@

Write-Host "Starting bat file to convert from CNG to RSA format.." 

Invoke-Expression -Command:$command 

Write-Host "Importing RSA formatted certificates.."

Import-PfxCertificate -FilePath $clientCertFileRsaFormatted -CertStoreLocation Cert:\LocalMachine\My -Password $clientCertPasswordSec
Import-PfxCertificate -FilePath $clientCertFileRsaFormatted -CertStoreLocation Cert:\LocalMachine\root -Password $clientCertPasswordSec



Import-PfxCertificate -FilePath $serverCertFileRsaFormatted -CertStoreLocation Cert:\LocalMachine\My -Password $serverCertPasswordSec
Import-PfxCertificate -FilePath $serverCertFileRsaFormatted -CertStoreLocation Cert:\LocalMachine\root -Password $serverCertPasswordSec

The powershell script uses a bat file that calls Openssl to convert the pfx certificate to use the RSACryptoServiceProvider. This is how the bat file looks like:
echo Generating RSA format certificates for server using OpenSSL..

c:\openssl\openssl.exe pkcs12 -in "C:\temp\MSMQWcfDemoserver.pfx" -nokeys -out "C:\temp\MSMQWcfDemoserver.cer" -passin "pass:kongo"
c:\openssl\OpenSSL.exe pkcs12 -in "C:\temp\MSMQWcfDemoserver.pfx" -nocerts -out "C:\temp\MSMQWcfDemoserver.pem" -passin "pass:kongo" -passout "pass:kongo"
c:\openssl\OpenSSL.exe rsa -inform PEM -in "C:\temp\MSMQWcfDemoserver.pem" -out "C:\temp\MSMQWcfDemoserver.rsa" -passin "pass:kongo" -passout "pass:kongo"
c:\openssl\openssl.exe pkcs12 -export -in  "C:\temp\MSMQWcfDemoserver.cer" -inkey "C:\temp\MSMQWcfDemoserver.rsa" -out "C:\temp\MSMQWcfDemoserver.RSAConverted.pfx" -passin "pass:kongo" -passout "pass:kongo"


echo Generating RSA format certificates for client using OpenSSL..

c:\openssl\openssl.exe pkcs12 -in "C:\temp\MSMQWcfDemoclient.pfx" -nokeys -out "C:\temp\MSMQWcfDemoclient.cer" -passin "pass:bongo"
c:\openssl\OpenSSL.exe pkcs12 -in "C:\temp\MSMQWcfDemoclient.pfx" -nocerts -out "C:\temp\MSMQWcfDemoclient.pem" -passin "pass:bongo" -passout "pass:bongo"
c:\openssl\OpenSSL.exe rsa -inform PEM -in "C:\temp\MSMQWcfDemoclient.pem" -out "C:\temp\MSMQWcfDemoclient.rsa" -passin "pass:bongo" -passout "pass:bongo"
c:\openssl\openssl.exe pkcs12 -export -in  "C:\temp\MSMQWcfDemoclient.cer" -inkey "C:\temp\MSMQWcfDemoclient.rsa" -out "C:\temp\MSMQWcfDemoclient.RSAConverted.pfx" -passin "pass:bongo" -passout "pass:bongo"


The bat file uses OpenSSL to extract (dismantle) the public part of the certificate into a .cer file (this part could have been done with MMC). The next step is to generate a from our existing pfx file to export to a pem file and then a rsa file with OpenSSL. We then meld the .cer file and .rsa file into a converted .pfx file. This file is with the Powershell script automatically imported into the certificate store Personal (My) of certificate location Local Computer. The Powershell script also Import-PfxCertificate to Trusted Root Certification Authorities. Anyways, my goal was to give you a demo about .NET, WCF and NetMsmqBinding using message security, but I first had to get over this hurdle to be able to have some protection in WCF with certificate and had no idea that Microsoft had given developers so cumbersome tools to generate a self signed certificate to actually work with WCF. Now my MSMQ message queue is filled with encrypted and protection MSMQ messages (containing WCF message to be consumed)! :)
Note: the MSMQ queue was inspected using this Powershell script:

#
# InspectMessageQueueWcfContent.ps1
#


#
# InspectMessageQueue.ps1
#

[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.ServiceModel") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.IO") | Out-Null


$queuePath = ".\private$\demoqueue3"

Write-Host "Powershell MSMQ queue WCF inspector v0.1. Inspecting queue contents of the queue: $queuePath"
Write-Host ""


Run-MainDemoIterateMsmq $queuePath



Function Get-XmlFromWcfMessage([System.Messaging.Message] $msg) {
   
    $doc = New-Object System.Xml.XmlDocument;
    $messageLength = [int] $msg.BodyStream.Length


    $buffer = New-Object byte[] $messageLength

    
    $msg.BodyStream.Read($buffer, 0, $messageLength)

    $envelopeStart = Find-SoapEnvelopeStart($buffer)

    $envelopeStart = $envelopeStart - 0

    $envelopeLength = $($buffer.Length - $envelopeStart)
    #Write-Host $envelopeStart


    $stream = New-Object System.IO.MemoryStream($buffer, $envelopeStart, $envelopeLength)

    $elm = New-Object System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
    $elm.ReaderQuotas.MaxStringContentLength = 10000000
    $elm.ReaderQuotas.MaxBytesPerRead = 10000000


    $msg1 = $elm.CreateMessageEncoderFactory().Encoder.ReadMessage($stream, 10000000);

    $doc.Load($msg1.GetReaderAtBodyContents());

    $msg.BodyStream.Position = 0;



    return $doc;
}

Function Find-SoapEnvelopeStart([byte[]] $stream)
{
    $i = 0;
    $j = 0;
    $prevByte = $stream[$i];
    $curByte = [byte]$j;
    for ($i = 0; $i -lt $stream.Length; $i++)
    {
        $curByte = $stream[$i];
        if ($curByte -eq [byte] 0x02 -and $prevByte -eq [byte] 0x56) {
            break;
        }
        $prevByte = $curByte;
    }
    return $i - 1;
}


Function Run-MainDemoIterateMsmq([string] $queuePath) {

$queue = New-Object System.Messaging.MessageQueue $queuePath

foreach ($message in $queue.GetAllMessages()){
  $xmlDoc = Get-XmlFromWcfMessage $message 
  Write-Host $xmlDoc.OuterXml
 } 


}





Saturday 21 July 2018

Reading WCF messages in MSMQ queues in Powershell

The last article looked at displaying MSMQ contents for a MSMQ queue used with NetMsmqBinding using Powershell. The message queues contained characters that were unreadable. That is because the message queue items contains actually ready to consume WCF messages. This article will present a new Powershell script where the MSMQ body contents is finally readable using Powershell and .NET WCF classes in System.ServiceModel. Here is how the contents looks using regular methods to extract the MSMQ Message queue items with garbled contents. This is as noted due to the MSMQ queue items each containing a corresponding WCF message.
Let's fix this up by using System.ServiceModel classes!
[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.ServiceModel") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.IO") | Out-Null


$queuePath = ".\private$\demoqueue4"

Write-Host "Powershell MSMQ queue WCF inspector v0.1. Inspecting queue contents of the queue: $queuePath"
Write-Host ""


Run-MainDemoIterateMsmq $queuePath



Function Get-XmlFromWcfMessage([System.Messaging.Message] $msg) {
   
    $doc = New-Object System.Xml.XmlDocument;
    $messageLength = [int] $msg.BodyStream.Length


    $buffer = New-Object byte[] $messageLength

    
    $msg.BodyStream.Read($buffer, 0, $messageLength)

    $envelopeStart = Find-SoapEnvelopeStart($buffer);

    $envelopeLength = $($buffer.Length - $envelopeStart)
    #Write-Host $envelopeStart


    $stream = New-Object System.IO.MemoryStream($buffer, $envelopeStart, $envelopeLength)

    $elm = New-Object System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
    $elm.ReaderQuotas.MaxStringContentLength = 10000000
    $elm.ReaderQuotas.MaxBytesPerRead = 10000000


    $msg1 = $elm.CreateMessageEncoderFactory().Encoder.ReadMessage($stream, 10000000);

    $doc.Load($msg1.GetReaderAtBodyContents());

    $msg.BodyStream.Position = 0;



    return $doc;
}

Function Find-SoapEnvelopeStart([byte[]] $stream)
{
    $i = 0;
    $j = 0;
    $prevByte = $stream[$i];
    $curByte = [byte]$j;
    for ($i = 0; $i -lt $stream.Length; $i++)
    {
        $curByte = $stream[$i];
        if ($curByte -eq [byte] 0x02 -and $prevByte -eq [byte] 0x56) {
            break;
        }
        $prevByte = $curByte;
    }
    return $i - 1;
}


Function Run-MainDemoIterateMsmq([string] $queuePath) {

$queue = New-Object System.Messaging.MessageQueue $queuePath

foreach ($message in $queue.GetAllMessages()){
  $xmlDoc = Get-XmlFromWcfMessage $message 
  Write-Host $xmlDoc.OuterXml
 } 


}
The soap envelope is found looking after the escape sequence "V" followed with the special ANSI character 0x02 (STX = Start of Text). From this point on, the rest of the WCF Message is our SOAP body! We then get readable output!
Finally, the WCF messages inside the MSMQ queue that is filled up using NetMsmqBinding is readable! In my next article I will present a demo solution of how to use NetMsmqBinding in WCF! Until then, you can clone the solution already from here: git clone git@bitbucket.org:toreaurstad/demonetmsmqwcfgit.git

Reading MSMQ contents with Powershell

This article will present two ways to read a MSMQ (Microsoft Message Queue) using Powershell. First, the queue will be read using the GetString method of System.Text.UTF8Encoding:

[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
 
$queuePath = ".\private$\myqueue"

$queue = New-Object System.Messaging.MessageQueue $queuePath

foreach ($message in $queue.GetAllMessages()){

 Write-Host (New-Object System.Text.UTF8Encoding).GetString($message.BodyStream.ToArray())

 Write-Host $msg 
}

As an alternative, it is also possible to use the StreamReader (more ceremony really):

[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
 
$queuePath = ".\private$\myqueue"

$queue = New-Object System.Messaging.MessageQueue $queuePath

foreach ($message in $queue.GetAllMessages()){

 Write-Host ([Environment]::NewLine)

 $sr = New-Object System.IO.StreamReader($message.BodyStream)

 $message.Formatter = New-Object System.Messaging.XmlMessageFormatter(@(""));
 
 $msg = "";

 while ($sr.Peek() -ge 0){
  $msg += $sr.ReadLine()
 }

 Write-Host $msg 
}

Actually, I was needing a simple way to look at some messages sent with the NetMsmqBinding in WCF, so making a Powershell script seemed the quickest way! WCF does some strange formatting on the message that is sent through the wire, you can though see that our two alternatives gives also a bit different formatting, the first alternative being the most clean and with shortest syntax.
As the reader can see, the contents of the MSMQ queue that the NetMsmqBinding uses shows unreadable characters. That is because the MSMQ message item are containing actually WCF Messages. QueueExplorer showed me this fact, so next article will present a more lengthy version where the content can be properly decoded using Powershell to the rescue!

Tuesday 3 July 2018

Basic WCF solution in Monodevelop

Basic WCF Solution in Monodevelop

I created a basic solution with a WCF Servicehost and client in Monodevelop today using MX Linux 17 "Horizon". To check it out, clone the following repository:
git clone https://bitbucket.org/toreaurstad/hellowcfmono
The source code is small and can be seen in a browser here: HelloWcfMono source code
If you have not installed Monodevelop in Linux yet, it is available as package "Monodevelop", "Monodevel" or "Monodevelop-complete", for example in MX-Linux I used:
apt-get install monodevel

The HelloWcf solution consists of three projects. The Service project is a console project, running the ServiceHost through the console. You will want to tweak Monodevelop to use External Console by right clicking and selecting Options=>Run=>General: "Run on external console". I just installed xterm to use the console as it is (apt get install xterm). In case Monodevelop crashes when you open the .sln file, another problem with Monodevelop, you can run the following command to open the .sln file directly in the root folder of the cloned repository.: monodevelop HelloWcf.sln
To run the WCF sample, right click on the Host project and choose Set as Startup project Choose first to Rebuild all (Ctrl+F8) to build the Service, Host and Client projects. Now press F5 to debug the Host project. The terminal window should show up, indicating that the WCF Service is running:



Now, switch over to a new terminal window and navigate to the Client project. Go to the bin folder, then the Debug folder. If you did not build Client, there are no files here, so do this now by right clicking on the Client project in Monodevelop and choose build. Now a file called Client.exe should pop up in your console. To run the client, enter: mono Client.exe Then you provide the Service a string through a call WCF service call with the proxy (Client) and get a reply. This project is really the basic set up of a client to get started coding WCF Servicehost and a proxy supporting BasicHttpBinding in .NET System.ServiceModel (which Mono actually supports). Developers can now use Linux and Monodevelop for example and commit code, while other developers use other platforms. The same .sln file can be openened in Visual Studio in Windows for example, while front-end guys use Apple to do their bit. Monodevelop is truly a possible bridge and will you will save money on license costs and freedom to add a lot of free software to use to build your projects. So what are you waiting for, grab hold of Monodevelop today and Linux and try it out! Nice thing to see that Mono framework supports WCF, much can be developed for .NET in Linux!

Saturday 19 May 2018

Call a Javascript function from Blazor page

This article will show how a Js function can be called from a Blazor page. First off, create a button like this:
 <button class="btn btn-warning" onclick="@SayHelloToBlazor">Click me!</button>
Then define the .Net method to handle the onclick event.
@using Microsoft.AspNetCore.Blazor.Browser.Interop

 private async void ShowAlert()
 {
    if (RegisteredFunction.Invoke("showAlert", "Hello World!"))
        Console.WriteLine("The Js function showAlert was called!");
 }
The code invokes a registered function with the invoke method and passing in the method name and an argument. Note that you must add the Interop namespace to Blazor in AspNetCore. We then add the Js function, but Blazor will give you a compiler error if you put the Js function in the same file as the Blazor page. Instead, add it in the index.html file under wwwroot folder of your Blazor project (check the wwwroot folder). You can define the Js function in a .js file or right into the index.html file.

    Blazor.registerFunction('showAlert', (msg) => {
        console.log(msg);
        alert(msg);
        return true;

    });

Note that if you refactor the Js method, your reference in the .DotNet code of Blazor will of course go stale, and you must update it. Since we return true (as Blazor wants you to do), we can act upon that in the Blazor code as a callback (check the async modifier of the DotNet method). That is what you need to do to get started with calling Javascript from Blazor page running in DotNetCore 2.1 and later.

Thursday 10 May 2018

Powershell - Search for big files and output to Excel

Here is a Powershell script that you can run to search for the ten biggest files in your current file directory and display them in Excel. My version of Powershell is 5.1 according to the built in Powershell variable $PSVersionTable.PSVersion, so if you run the script in earlier versions of Powershell, the script must be changed a bit.

Write-Host 'Look for big files in current directory' 

$alternatingOddRowColor = 19
$alternatingEventRowColor = 20

$filename = ''

#$filename = Read-Host 'Directory to output filelist? (c:\temp) default'


if ([string]::IsNullOrEmpty($filename)){
 $filename = "c:\temp\\" 
}

$filename = $filename + 
 ([TimeSpan](Get-Date).ToLongTimeString()).Ticks.ToString() + '_Bigfiles' + '.csv'

Write-Host $filename


gci -r | sort Length -desc |
Select-Object @{Name='Filesize(MB)'; Expression = { [int]$($_.Length /1MB) }}, Name, FullName, LastWriteTime -First 10 | 
Export-Csv $filename -NoTypeInformation -Encoding ASCII -UseCulture

$excelFileName = $filename.Replace('.csv', '.xlsx')


$excel = New-Object -ComObject Excel.Application 
$excel.Visible = $true
$excel.Workbooks.Open($filename)

$excel.DisplayAlerts = false

$objWorksheet = $excel.Workbooks.Item(1)

$activeRange = $excel.ActiveWorkbook.ActiveSheet.UsedRange

$activeRange.EntireColumn.AutoFit()

For ($i = 1; $i -le $activeRange.Rows.Count; $i++) { 
 $themeColorIndex = $(If ($($i %2) -eq 0) { $alternatingOddRowColor } 
   Else { $alternatingEventRowColor });

 $currentRow = $excel.ActiveWorkbook.ActiveSheet.UsedRange.Rows($i).EntireRow
 $currentRow.Font.Name = 'Comic Sans MS'
 $currentRow.Interior.ColorIndex =  $themeColorIndex;
 if ($i -eq 1){
  $currentRow.Font.Bold = true 
  $currentRow.Font.Size = 14
 } 
}


$excel.SaveAs($excelFileName,51)

#$excel.Quit()



A timestamp can be created in Powershell using the Get-Date cmdlet, converting the Get-Date DateTime object to a string with ToLongTimeString(), then casting that string into a timestamp and performing a ToString. Like this:

 ([TimeSpan](Get-Date).ToLongTimeString()).Ticks.ToString()

It is nice to have a file size in megabyte with Get-ChildItem That can be achieved using a calculated property in Powershell. This is done with the following construct ${ .. }
@{ Name : 'PropertyName', Expression { $( ..calculation here .. ) }}

#Like this! 

gci -r | sort Length -desc |
Select-Object  @{Name='Filesize(MB)'; Expression = { [int]$($_.Length /1MB) }} , Name, FullName, LastWriteTime -First 10 | 
Export-Csv $filename -NoTypeInformation -Encoding ASCII -UseCulture

After running the Powershell script I could find out why my source code repository seemingly had grown so much in size. The repo was not increased, but the folder Test Results contained almost a gigabyte of disk space after running some web tests and load tests. My .hgignore file ignore these files anyways. The picture below shows how the generated file looks. Of course with a Comic Sans MS. Font

Sunday 10 December 2017

Compressing files in a MVC environment

This article will present a way to compress files in a MVC environment. For compression, we will use the DotNetZip Nuget package, which is an open and free compression library hosted on Codeplex and supported also by Xceed. The DotNetZip produces of course Zip files. DotNetZip website We install this compression library by initiating the following Nuget command: Install-Package DotNetZip We then define a simple view in MVC that has got a file upload input and a submit button:

@model ZipAndMvc.Models.HomeViewModel
@{
    ViewBag.Title = "Home Page";
}

<div class="jumbotron">
    <h2>Test out zipping a file</h2>   
</div>

<div class="row">

    @using (Html.BeginForm("ZipIt", "Home", FormMethod.Post, new {  enctype = "multipart/form-data" }))
    {
        <div class="col-md-3">@Html.Label("Zip password") @Html.TextBoxFor(m => m.ZipPassword) </div>
        <div class="col-md-3"><input type="file" name="FileUpload" /> </div>
        <div>  <input type="submit" id="Submit" value="Upload and zip file" /> </div>
    }
</div>

This view allows the user to type in a password for the file to compress, where the user also selects the file to compress. The user then hits the submit button. The HomeViewModel is very simple with a simple property for setting the zip password. Then we define the following code in the MVC controller:

        public FileStreamResult ZipIt(HomeViewModel viewmodel)
        {
            if (Request.Files.Count > 0)
            {
                using (var zip = new ZipFile())
                {
                    zip.Encryption = EncryptionAlgorithm.PkzipWeak;
                    zip.Password = viewmodel.ZipPassword;
                    zip.CompressionLevel = Ionic.Zlib.CompressionLevel.Default; 
                    var memoryStream = new MemoryStream();
                    zip.AddFile(Request.Files[0].FileName, "");
                    zip.Save(memoryStream);
                    memoryStream.Position = 0;
                    return new FileStreamResult(memoryStream, contentType: "application/zip")
                    {
                        FileDownloadName = Path.ChangeExtension(Request.Files[0].FileName, "zip")
                    };
                }
            }
            return null;
        }


The client posts the file to compress. The controller then inspects the Request.Files collection and selects the first file if there is present any files there. Here we return a FileStreamResult where the compressed data inside the memorystream is returned to the client. We use DotNetZip to do the compression. The benefit of DotNetZip compared to .Net built-in support for compression is more functionality. The code above should be sufficient for basic compression scenario in MVC. Feel free to experiment with DotNetZip. As you can see, you can specify compression level. You can also choose to add directories and much more. The reason for the second argument in AddFile method is to ensure that the file to be added to the zip package is put in the root folder of the zipped file. Also, set the values of Encryption and Password before adding files or directories (Folders) in the ZipFile. You can actually use different passwords also in the Zip file.

Friday 8 December 2017

Finding old Git Branches with WSL and Bash

Finding old branches in Git

I had to find out which branches in a Git repository was old and output it to a file. An old branch is defined to have no commits the last four months. Here is the bash script I ended up with.




#!/bin/bash

resolveOldBranches(){
branchfile="oldbranches.txt"
declare -i branchiteration=0
branchcount=$(git branch -a | wc -l)

if [ ! -e $branchfile ] ; then
 touch $branchfile
fi

#empty the oldbranch file
: > $branchfile

for k in $(git branch -a | sed /\*/d); do


 if [ -z "$(git log -1 --since='4 months ago' -s $k)" ]; then
  echo $k | cut -d/ -f3 >> $branchfile
 fi
 branchiteration=$branchiteration+1
 percentage= bc <<< "scale=2;($branchiteration/$branchcount)*100"


 read -n 1 -t 0.1 input                  # so read doesn't hang
   if [[ $input = "q" ]] || [[ $input = "Q" ]]
   then
      echo # to get a newline after 
echo -e "XXX\n$($percentage)\nAnalyzing $branchiteration of $branchcount $(bc <<< "scale=2;($branchiteration/$branchcount)*100") % done. \n(Exit: Q/q)... \nXXX"

done | whiptail --title "Resolving OpPlan 4 branch ages" --gauge "Analyzing.. (Press Q or q to exit)" 10 60 0


}

resolveOldBranches
cat $branchfile

Saturday 21 October 2017

X11 Subsystem running WSL Windows 10 subsystem for Linux


This article will look at running graphical Linux applications in Windows 10. As many of you know, Windows 10 can offer a subsystem for Linux running inside Windows 10. We need to download and install a X11 server to be able to run graphical applications that need more than the console, that is a graphical user interface. First off, download XMing for Windows Server from here:

XMing X Server for Windows Server
After installation of Xming, start Xming from your start button.
Now we need to install the Linux Subsystem itself, if you have not done this yet.
Inside Powershell, enter the following command as an administrator:

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux 

If you are not a Windows Insider yet, you must join this program. See this page for a description how to obtain WSL or Windows Subsystem for Linux and install it.
Installation guide of WSL - Windows Subsystem for Linux After you have downloaded WSL and installed it using Powershell, select Launch and in the console Window after WSL is further installed and setup, enter a user in Linux you will use as administrator (in Linux terms, this is the root user). You can add another user using the adduser command as root in the Bash console. You can access WSL Linux inside Windows 10 by selecting the menu item Bash on Ubuntu on Windows.


Getting started using WSL

You probably want to update your WSL to the latest version. WSL is a specialized Ubuntu Linux distribiton. Enter the following command to upgrade Linux Kernel and applications, note that it will take time to download package and upgrade to latest versions:

apt-get update && apt-get upgrade The version of Linux distro can be found using this command:


lsb_release -irc 

As we see, I am running Ubuntu 16 Xenial. Next off, we are going to support X-Server. Download first the X11 apps.
root@tore# apt-cache search x11-apps x11-apps - X applications
Install X11-Apps. This will also download all required additional pacages. apt-get install X11-Apps
You need to do this as root or switching to a super user and use the sudo command. Next off, edit your ~/.bashrc file. This is similar to the $Profile file that Powershell uses. You are setting up your environment here to make sure you can use X-Server based Graphical User Interfaces. Such as Gimp, Firefox, Stellarium, Quake and so on - requiring a GUI. But we will start off with running a X11-app, such as Xeyes. Make sure your ~/.bashrc file got the following content. First download Nano if you do not want to use Vim or Vi. (apt-get install nano)
nano ~/.bashrc Next off, add the following line at least: export DISPLAY=:0 We can also add more nice colors and some additional information and offer to switch to a non-root user initally.
export DISPLAY=:0
LS_COLORS='rs=0:di=1;35:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:';
export LS_COLORS
PS1='\e[37;1m\u@\e[35m\W\e[0m\$ '
echo "Welcome to Bash on Ubuntu on Windows. To switch to your user Tore :"
echo "su tore && cd /home/tore"
echo "Do this now? [y/n]"

read -rsn1 input
if [ "$input" = "y" ]; then
    cd /home/tore
    su tore
    ls -al
fi


echo "To adjust profile file edit the file ~\.bashrc with Nano"


Last, we can test out everything, running Xeyes. Note that you can test out more advanced Linux applications such as Gimp by running: apt-get install gimp This will install Gimp, the Gnu Image Manipulation Program. Then just enter gimp from the console. You can also run such programs in the background by adding the ampersand (&): gimp &

Sometimes, we need to force an exit of such a Linux app with a GUI running from the console entering Ctrl+C to force exit the process.

Tuesday 3 October 2017

Setting up a Git alias with a shell function

This short article will show you how to search in the log of a Git repository with a shell function. This shell function can also receive a positional parameter to use in the shell function. First off, edit the .gitconfig file in your user's home folder. On Linux Mint for example, the folder should reside in the /home directory. You can use nano for example. (apt-get install nano)


.gitconfig : 

[alias]
        searchlog = "!f() { git log --all --decorate --graph -i --grep \"$1\";  }; f"




Note the positonal parameter $1 here, we escape the quote also. The function inside the alias is a shell function.


To use this alias command, type for example:
git searchlog test
This will search the Git log for the parameter passed in (test) and include some flags to decorate the log displayed. Using Git aliases, we can do lenghty Git commands with shorter aliased commands.

Friday 22 September 2017

Displaying altitude with Google Maps





We will look at displaying additional positional information with Google Maps in this article, such as altitude. First off, we need to add a new object to Google Maps Api v3 - the MarkerWithLabel object. This allows us to add text labels to Google Maps. They are also draggable. I have updated a Plunk below so you can see the end result yourself:

Location in Google Maps with altitude - Plunk

The MarkerWithLabel.js contains the additional javascript code to add the MarkerWithLabel object. We add the marker inside the showPosition method with the following code:


  function showPosition(position){
        
         var mapCanvas = document.getElementById("demo");
  var myCenter = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); 
  var mapOptions = {center: myCenter, zoom: 12};
  var map = new google.maps.Map(mapCanvas,mapOptions);
  var marker = new google.maps.Marker({
    position: myCenter,
    animation: google.maps.Animation.BOUNCE
  });
  marker.setMap(map);
  
  console.log(position.coords);
  
  
   var image = 'https://developers.google.com/maps/documentation/javascript/examples/full/images/beachflag.png';
 
  

     var altitudeMarker = new MarkerWithLabel({
       position: myCenter,
       draggable: true,
       raiseOnDrag: true,
       icon: image,
       map: map,
       labelContent: position.coords.altitude.toString(),
       labelClass: "labels", // the CSS class for the label
       labelStyle: {opacity: 0.75}
     });
     
     
        
      }

We add the altitude, using the position.coords.altitude object.

A good tip here is to add high accuracy of the GeoLocation.


  function getLocation() {
    

    var geo_options = {
     enableHighAccuracy: true, 
     maximumAge        : 30000, 
     timeout           : 27000
    };


         if (navigator.geolocation){
          var position = navigator.geolocation.getCurrentPosition(showPosition, null, geo_options);
        }
      }



Note that the client has got to have a positioning device supporting returning the altitude. Most smartphones today got GPS for example.
As a test - you can change the value displayed to position.coords.accuracy.toString() instead. Accuracy is always return in the Coords object.

Sunday 17 September 2017

HTML 5 Geolocation introduction

This article will introduce you to HTML 5 Geolocation API.

First off, test the browser for support of HTML 5 Geolocation. The first call to get the location of the client / user will also prompt a dialog that the user must usually confirm to to allow getting the location.
The following Javascript is necessary to get the latitude and longitude of the client :

 function getLocation() {
  if (navigator.geolocation){
   var position = navigator.geolocation.getCurrentPosition(showPosition);
  }
 }
        
 function showPosition(position){
  console.log(position);
  $("#demo").html(position.coords.latitude + " " + position.coords.longitude);
 }








Note that you can retrieve additional information such as altitude, heading and speed if the client got positioning hardware supporting this.
Mozilla Developer Network - Coordinates object
In Firefox, you have to use HTTPS to use Geolocation in newer versions of this browser. The client must agree to share the current location. A demo of Geolocation is here:

HTML 5 Geolocation demo - Plunk

Let us also use a map to show the location of the user. We can use Google Maps API. To use this API, request a Google API Key from here:

Google API Key site

We plot the current location with some script below using the Google Maps API, adding a Marker that is bouncing on top of the current location.

  function getLocation() {
   if (navigator.geolocation){
    var position = navigator.geolocation.getCurrentPosition(showPosition);
   }
  }
        
  function showPosition(position){
        
   var mapCanvas = document.getElementById("demo");
   var myCenter = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); 
   var mapOptions = {center: myCenter, zoom: 12};
   var map = new google.maps.Map(mapCanvas,mapOptions);
   var marker = new google.maps.Marker({
    position: myCenter,
    animation: google.maps.Animation.BOUNCE
   });
    marker.setMap(map);
        
  }
      



The current location is displayed using Google Maps as displayed here:



Support for Geolocation in Firefox is limited to HTTPS and recent version of Firefox may not function with Geolocation in Linux, newer than Firefox version 20. If so, downgrade to Firefox Version 20. I have tested the code above using Opera web browser in Linux Mint 15.

Note that we here added Google Maps Javascript source reference and an Google API key.





  <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAeymq4mlrbKoBUhU3LdegaudQDnY7MFPo&callback=myMap"></script>