.Net Core & WCF TransportWithMessageCredential

In one of my day jobs I look after a system which has been around since 2010 (Early adopter of Microsoft Azure, developement started on .Net 3.5). The product has a number of Windows Communication Foundation(WCF) services hosted in an Azure CloudService.

A client built with .Net Core wanted to be able to call one of the services which was implemented using wsHttpBinding and TransportWithMessageCredential and this proved a bit more painful than expected…

I first tried the Visual Studio 2017 Microsoft WCF Web Service Reference Provider fromt the WCF Core Team.

The “add connected service” extension dialog allowed me to select an endpoint

ConfigureWCFWebSeriveReference

But the code generation process failed

WCFWebServiceReferenceError.png

The error message wasn’t particularly helpful so I used the command line utility svcutil to generate client classes. Which I used to built a .net core client with and the associated .Net Core WCF NuGet packages.

The console application failed when I called the service with a “PlatformNotSupportedException”. After some searching I found that the .Net Core WCF libraries don’t support TransportWithMessageCredential (September 2017).

Some more searching lead to a StackOverflow article where an answer suggested using the SimpleSOAPClient NuGet package. I then created a new client using the generated classes as the basis for the ones used in my SimpleSOAPClient proof of concept(PoC)

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="Redeem", WrapperNamespace="http://qwertyuiop.com/services2011/08", IsWrapped=true)]
public partial class RedeemRequest
{
    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://qwertyuiop.com/services2011/08", Order=1)]
    public string voucherCode;

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://qwertyuiop.com/services2011/08", Order=2)]
    public string merchantId;

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://qwertyuiop.com/services2011/08", Order=3)]
    public string merchantReference;

    [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://qwertyuiop.com/services2011/08", Order=4)]
    public string terminalId;

    public RedeemRequest()
    {
    }

    public RedeemRequest(string voucherCode, string merchantId, string merchantReference, string terminalId)
    {
        this.voucherCode = voucherCode;
        this.merchantId = merchantId;
        this.merchantReference = merchantReference;
        this.terminalId = terminalId;
    }
}

became

[XmlRoot("Redeem", Namespace = "http://qwertyuiop.com/services2011/08")]
public partial class RedeemRequest
{
   [XmlElement("voucherCode")]
   public string voucherCode;
   [XmlElement("transactionAmount")]
   public decimal transactionAmount;
   [XmlElement("merchantId")]
   public string merchantId;
   [XmlElement("merchantReference")]
   public string merchantReference;
   [XmlElement("terminalId")]
   public string terminalId;
}

This client failed with a SOAPAction related exception so I fired up Telerik Fiddler and found that the header was missing. When I manually added the header in the request composer (after dragging one of my failed requests onto the composer tab) it worked.

I had a look at the code in the SimpleSOAPClient repository to see how to add a custom HTTP Header to a request.

RedeemRequest redeemRequest = new RedeemRequest()
{
   merchantId = "......",
   merchantReference = "......",
   terminalId = "......",
   voucherCode = "......",
};

using (var client = SoapClient.Prepare())
{
   client.HttpClient.DefaultRequestHeaders.Add("SOAPAction", "http://qwertyuiop.com/services2011/08/IRedemptionProxyServiceV1/Redeem");
   var responseEnvelope = await client.SendAsync(
      "https://qwertyuiop.com/RedemptionProxy.svc",
      "https://qwertyuiop.com/services2011/08/IRedemptionProxyServiceV1/Redeem",
      SoapEnvelope.Prepare()
      .WithHeaders(KnownHeader.Oasis.Security.UsernameTokenAndPasswordText(".....", "......"))
      .Body(redeemRequest), ct);

      var response = responseEnvelope.Body<RedeemResponse>();

      Console.WriteLine("Redeem Result:{0}  Message:{1}", response.Result, response.messageText);
   }
}

After sorting out a few typos my request worked as expected. Only a couple of hours lost from my life, hopefully this post will help someone else.

nRF24 Windows 10 IoT Core Test Harness

After modifying the Raspbery PI nRF24L01 shields I built a single page single button Universal Windows Platforms(UWP) test harness (using the techfooninja RF24 library) to check everything was working as expected.

I used a couple of Netduinos and Raspbery PI devices to as test clients.

public sealed partial class MainPage : Page
{
   private const byte ChipEnablePin = 25;
   private const byte ChipSelectPin = 0;
   private const byte InterruptPin = 17;
   private const byte Channel = 10;
   private RF24 radio;

   public MainPage()
   {
      this.InitializeComponent();

      this.radio = new RF24();

      this.radio.OnDataReceived += this.Radio_OnDataReceived;
      this.radio.OnTransmitFailed += this.Radio_OnTransmitFailed;
      this.radio.OnTransmitSuccess += this.Radio_OnTransmitSuccess;

      this.radio.Initialize(ChipEnablePin, ChipSelectPin, InterruptPin);
      this.radio.Address = Encoding.UTF8.GetBytes("Base1");
      this.radio.Channel = Channel;
      this.radio.PowerLevel = PowerLevel.Low;
      this.radio.DataRate = DataRate.DR250Kbps;

      this.radio.IsEnabled = true;

      Debug.WriteLine("Address: " + Encoding.UTF8.GetString(this.radio.Address));
      Debug.WriteLine("Channel: " + this.radio.Channel);
      Debug.WriteLine("DataRate: " + this.radio.DataRate);
      Debug.WriteLine("PA: " + this.radio.PowerLevel);
      Debug.WriteLine("IsAutoAcknowledge: " + this.radio.IsAutoAcknowledge);
      Debug.WriteLine("IsDynamicAcknowledge: " + this.radio.IsDynamicAcknowledge);
      Debug.WriteLine("IsDynamicPayload: " + this.radio.IsDynamicPayload);
      Debug.WriteLine("IsEnabled: " + this.radio.IsEnabled);
      Debug.WriteLine("IsInitialized: " + this.radio.IsInitialized);
      Debug.WriteLine("IsPowered: " + this.radio.IsPowered);
   }

   private void Radio_OnDataReceived(byte[] data)
   {
     string dataUTF8 = Encoding.UTF8.GetString(data);

     Debug.WriteLine(string.Format("Received: {0}", dataUTF8));
   }

   private void buttonSend_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
   {
      this.radio.SendTo(Encoding.UTF8.GetBytes("Duino"), Encoding.UTF8.GetBytes(DateTime.UtcNow.ToString("yy-MM-dd hh:mm:ss"))) ;
   }

   private void Radio_OnTransmitSuccess()
   {
      Debug.WriteLine("Radio_OnTransmitSuccess");
   }

   private void Radio_OnTransmitFailed()
   {
      Debug.WriteLine("Radio_OnTransmitFailed");
   }
}

Interrupt Triggered: FallingEdge
Data Sent!
Radio_OnTransmitSuccess
Interrupt Triggered: RisingEdge
Interrupt Triggered: FallingEdge
Received: 20.4 70.7
Interrupt Triggered: RisingEdge
Interrupt Triggered: FallingEdge
Data Sent!
Radio_OnTransmitSuccess
Interrupt Triggered: RisingEdge
Interrupt Triggered: FallingEdge
Received: 20.3 70.8
Interrupt Triggered: RisingEdge

The Raspberry PI could reliably receive and transmit messages.

nRF24 Windows 10 IoT Core Hardware

Taking my own advice I decided to purchase a couple of Raspberry Pi to NRF24L01 shields from Ceech a vendor on Tindie.

The nRF24L01 libraries for my .Net Micro framework and WIndows 10 IoT Core devices use an interrupt driver approach rather than polling status registers to see what is going on.

Like most Raspberry PI shields intended to be used with a *nix based operating system the interrupt pin was not connected to a General Purpose Input/Output (GPIO) pin.

NRF24PiPlateModification

My first step was to add a jumper wire from the pin 8 on the nRF24L01 to GPIO pin 17 on Raspberry PI connector.

I then downloaded the techfooninja Radios.RF24 library for Windows IoT core and update the configuration to suit my modifcations. In the TestApp the modifications were limited to changing the interrupt pin from GPI 4 to GPO 17

private const byte IRQ_PIN = 4;

private const byte IRQ_PIN = 17;

I used a socket for the nRF24L01 device so I can trial different devices, for a production system I would solder the device to the shield to improve reliability.

RPiWithnRF24Plate

I then ran the my test application software in a stress test rig overnight to check for any reliability issues. The 5 x netduino devices were sending messages every 500mSec

RPIStressTester

nRF24L01 Raspberry PI Gateway Hardware

For those who came to my MS Ignite AU Intelligent Cloud booth session

Building Wireless Field Gateways

Connecting wireless sensor nodes to the cloud is not the mission it used to be, because the Azure team (and many OS projects) have developed tooling which can help hobbyist and professional developers build solutions. How could you build a home scale robust, reliable and secure solution with off the shelf kit without blowing the budget?

Sparkfun nRF24L01 module &Adafruit perma proto hat

NRF24L01 Raspberry PI DIY Gateway Hardware

BoM (all prices as at Feb 2016)

You will also need some short lengths of wire and a soldering iron.

For those who want an “off the shelf” solution (still requires a minor modification for interrupt support) I have used the Raspberry Pi to NRF24l01+ Shield USD9.90

2015-09-25t072754-447z-20150925_091942-855x570_q85_pad_rcrop

Instructions for modifications and software to follow.

NetMF MP3 Player Part 3

Building on the file listing code from the previous post in the next class we built a basic multi threaded music player using an enhanced version of the Vs1053B driver based on the softelectrotech.and bluecone code.

The code uses five interrupt ports (I used 5 buttons on the 4 analog ports on the Seeedstudio V2 Base shield and D5 to make it easier to fit the Mp3 shield)

As the Vs1053 driver is now running asynchronously it fires an event when the current track has finished playing

   public class Program
   {
      static string[] MusicFiles;
      static Vs1053B player = new Vs1053B(Pins.GPIO_PIN_D2, Pins.GPIO_PIN_D6, Pins.GPIO_PIN_D7, Pins.GPIO_PIN_D8);
      static byte volume = 200;
      static int trackNumber = 1;
      static public string TrackFilename { get { return MusicFiles[trackNumber - 1]; } }

      public static void Main()
      {
         MusicFiles = Directory.GetFiles(@"\SD");

         foreach( string file in MusicFiles)
         {
            Debug.Print(file);
         }

         InterruptPort playPause = new InterruptPort(Pins.GPIO_PIN_D5, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
         playPause.OnInterrupt += playPause_OnInterrupt;

         InterruptPort volumeUp = new InterruptPort(Pins.GPIO_PIN_A0, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
         volumeUp.OnInterrupt += volumeUp_OnInterrupt;

         InterruptPort volumeDown = new InterruptPort(Pins.GPIO_PIN_A1, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
         volumeDown.OnInterrupt += volumeDown_OnInterrupt;

         InterruptPort previousTrack = new InterruptPort(Pins.GPIO_PIN_A2, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
         previousTrack.OnInterrupt += previousTrack_OnInterrupt;

         InterruptPort nextTrack = new InterruptPort(Pins.GPIO_PIN_A3, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
         nextTrack.OnInterrupt += nextTrack_OnInterrupt;

         player.SetVolume(volume);
         player.Filename = TrackFilename;
         player.onMusicFinished += player_onMusicFinished;

         player.Play();

         Thread.Sleep(Timeout.Infinite);
      }

      static void player_onMusicFinished()
      {
         trackNumber += 1;

         if (trackNumber > MusicFiles.Length)
         {
            trackNumber = 1;
         }
         Debug.Print("player_onMusicFinished " + trackNumber + " of " + MusicFiles.Length);

         player.Filename = TrackFilename;
      }

      static void previousTrack_OnInterrupt(uint data1, uint data2, DateTime time)
      {
         trackNumber -= 1;

         if (trackNumber < 1)          {             trackNumber = MusicFiles.Length;          }          Debug.Print("previousTrack_OnInterrupt " + trackNumber + " of " + MusicFiles.Length);          player.CancelPlayback();          player.Filename = TrackFilename;       }       static void nextTrack_OnInterrupt(uint data1, uint data2, DateTime time)       {          trackNumber += 1;          if (trackNumber > MusicFiles.Length)
         {
            trackNumber = 1;
         }
         Debug.Print("nextTrack_OnInterrupt " + trackNumber + " of " + MusicFiles.Length);

         player.CancelPlayback();
         player.Filename = TrackFilename;
      }

      static void playPause_OnInterrupt(uint data1, uint data2, DateTime time)
      {
         Debug.Print("playPause_OnInterrupt ");
         if (player.IsPaused())
         {
            player.Resume();
         }
         else
         {
            player.Pause();
         }
      }

      static void volumeDown_OnInterrupt(uint data1, uint data2, DateTime time)
      {
         Debug.Print("volumeDown_OnInterrupt " + volume);
         if (volume > 0)
         {
            volume -= 1;
         }
         player.SetVolume(volume);
      }

      static void volumeUp_OnInterrupt(uint data1, uint data2, DateTime time)
      {
         Debug.Print("volumeUp_OnInterrupt " + volume);
         if (volume < 255)
         {
            volume += 1;
         }
         player.SetVolume(volume);
      }
   }

Next steps are to ignore contact bounce on the buttons and play MP3 files in a more consistent order
musicplayerv2

Netduino with Mp3 Shield and 5 button UI

Netduino Mp3 player with 5 button UI

NetMF MP3 Player Part 2

Building on the file listing code from the previous post in the next class we wrote the simplest possible NetMF code to play all of MP3 files on an SD Card. The Mp3 player shields I have all use a Vs1053B chip to decode the MP3 byte stream. This sample uses the driver code from softelectrotech.

public static void Main()
{
   Vs1053B player = new Vs1053B(Pins.GPIO_PIN_D2, Pins.GPIO_PIN_D6, Pins.GPIO_PIN_D7, Pins.GPIO_PIN_D8);
   string[] MusicFiles = Directory.GetFiles(@"\SD");
   player.SetVolume(180, 180);

   // Print a list of all the files on the SD card.
   foreach (string file in MusicFiles)
   {
      Debug.Print(file);
   }

   foreach (string file in MusicFiles)
   {
      Debug.Print("Play start " + file);

      player.Play(file, true);

      Debug.Print("Play finish " + file);
   }
}

Some of the students observed the order of the files was not what they were expecting. The order of the files appeared to depend on how they were copied to the memory card.

\SD\05 Sunday Bloody Sunday.mp3
\SD\06 Bad.mp3
\SD\07 Where the Streets Have No Name.mp3
\SD\08 I Will Follow.mp3
\SD\09 The Unforgettable Fire.mp3
\SD\10 Sweetest Thing [The Single Mix].mp3
\SD\11 Desire.mp3
\SD\12 When Love Comes to Town.mp3
\SD\13 Angel of Harlem.mp3
\SD\14 All I Want Is You.mp3
\SD\01 Pride (In the Name of Love).mp3
\SD\02 New Year's Day.mp3
\SD\03 With or Without You.mp3
\SD\04 I Still Haven't Found What I'm Looking For.mp3
Playback
Play start \SD\05 Sunday Bloody Sunday.mp3
Play finish \SD\05 Sunday Bloody Sunday.mp3
Play start \SD\06 Bad.mp3

All of the students observed that the tacks were being played synchronously which didn’t allow you to change the volume or interrupt the playback to pause the current track or change the track being played.

The next steps were to ensure the music files were sorted into a consistent order and that playback was not synchronous.

MusicPlayerSyncBasic code

NetMF MP3 Player Part 1

For one of my class projects the students build an NetMF MP3 player using a Netduino, MP3 shield, MicroSD card and some code. The first step is to learn about files, and directories by enumerating the contents of the MicroSD card.

public static void Main()
 {
    string[] musicFiles = Directory.GetFiles(@"\SD");

    foreach (string musicFile in musicFiles)
    {
       Debug.Print(musicFile);
    }
}

The NetMF implementation of GetFiles doesn’t support wildcards (unlike the full .Net Framework) so the list of files has to be manually filtered.

public static void Main()
{
   string[] musicFiles = Directory.GetFiles(@"\SD");

   foreach (string musicFile in musicFiles)
   {
      if (filePath.IndexOf(".mp3") != -1)
      {
         Debug.Print(musicFile);
      }
   }
}

The code above displayed
\SD\01 Pride (In the Name of Love).mp3
\SD\02 New Year’s Day.mp3
\SD\03 With or Without You.mp3
\SD\04 I Still Haven’t Found What I’m Looking For.mp3
\SD\05 Sunday Bloody Sunday.mp3
\SD\06 Bad.mp3
\SD\07 Where the Streets Have No Name.mp3
\SD\08 I Will Follow.mp3
\SD\09 The Unforgettable Fire.mp3
\SD\10 Sweetest Thing [The Single Mix].mp3
\SD\11 Desire.mp3
\SD\12 When Love Comes to Town.mp3
\SD\13 Angel of Harlem.mp3
\SD\14 All I Want Is You.mp3

For this project Directory.GetFiles was used (rather than Directory.EnumerateFiles) because the list files on the MicroSD will be used in other parts of the application.

The parsing and processing of file paths is important and can if done wrong can introduce hard to find issues(e.g. directory traversal attacks)

Debug.Print(musicFile .Substring( 0, musicFile.LastIndexOf(".mp3")));

Updating the code to use the built in System.IO.Path functionality

public static void Main()
{
   string[] MusicFiles = Directory.GetFiles(@"\SD");

   foreach (string musicFile in MusicFiles)
   {
      if (Path.GetExtension(musicFile) == ".mp3" )
      {
         Debug.Print(Path.GetFileNameWithoutExtension(musicFile));
      }
   }
}

The next step is to load and play the MP3 files using a provided library.