Category Archives: Uncategorized

Article for Programmez – September 2018 – Writing a NoSQL Windows Web Service with C++

This article is available now in kiosks for Programmez.

Programmez221

Advertisements

Article for Programmez – July/August 2018 – Writing a Windows Service with C++

This article was available for the holidays edition of the magazine.

220

How to run SQL Server from Docker

Run a docker file that contains :
FROM microsoft/mssql-server-windows-developer

D:\Dev\DockerSQL>docker image build –tag myserversql d:\dev\dockersql

Sending build context to Docker daemon 3.072kB
Step 1/1 : FROM microsoft/mssql-server-windows-developer
latest: Pulling from microsoft/mssql-server-windows-developer 3889bb8d808b: Already exists
449343c9d7e2: Pull complete
08883151461d: Pull complete
bafeb45a72fc: Pull complete
f5c5aa235c5b: Pull complete
158fead2ffa0: Pull complete
746db9597cec: Pull complete
9e96edbd8781: Pull complete
c6dabab6234f: Pull complete
975d0dccd859: Pull complete
5b747cfb01b7: Pull complete
c77992bbfd0f: Pull complete
Digest: sha256:a3e77eb7ac136bf419269ab6a3f3387df5055d78b2b6ba2e930e1c6312b50e07
Status: Downloaded newer image for microsoft/mssql-server-windows-developer:latest
—> 19873f41b375
Successfully built 19873f41b375
Successfully tagged myserversql:latest

The, run the image:
docker run -d -p 1433:1433 -e sa_password=P@ssw0rd -e ACCEPT_EULA=Y -v C:/temp/:C:/temp/ -e attach_dbs=”[{‘dbName’:’NorthWind’,’dbFiles’:[‘C:\\temp\\NORTHWND.mdf’,’C:\\temp\\NORTHWND.ldf’]}]” myserversql

Obtain the ip address using:
docker ps -a

Take the first item and ask for IP :
D:\Dev\DockerSQL>docker inspect -f “{{ .NetworkSettings.Networks.nat.IPAddress }}” 7dfe63dd7615

Then open the SQL Server Management Studio and connect to this IP. You’re done !

It’s my birthday !

I turn 44 this September 1 so, on every Facebook notification I receive, I recall my friends I am a developer:

Did you say “it’s ugly ?” 😊

It’s C coded the ASM way ! 😊

Speaker at Meetup #2 for Programmez magazine

The September 11, we will be back in the 1993’s. I will speak about the Amiga OS features at the Programmez Meetup #2 located in Cellenza’s office in Paris:

https://www.programmez.com/content/meetup-2-une-histoire-dos-du-cp/m-aujourdhui

I will present the Amiga Workbench and the Intuition graphical interface, and how to create a Window using C SAS/C compiler 6.5.

I will also talk about AMOS basic and come with demos like Phenomena Enigma.

How to make a dockerfile for running Windows Services

To run a Windows Service into Docker for Windows, you have to take some actions…

First you need to create the service. Use the sc.exe command. Make your service starting as auto. It will be running automatically.

If you need to start as an administrator to have admin privileges, use the sc sdset command:

RUN sc sdset SCMANAGER D:(A;;CCLCRPRC;;;AU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;BA)S:(AU;FA;KA;;;WD)(AU;OIIOFA;GA;;;WD)

It’s weird and ugly but it works !

A tip & trick: ask docker to start an OS image that ships IIS to be able to see your custom log files. Else, you can’t see what’s happening…

If you run your docker image in Azure Container Instance, be carefull that your image need to be a Windows Server 1609…

So I start theses images in my various dockerfiles:

  • FROM microsoft/dotnet-framework:4.6.2-runtime-windowsservercore-ltsc2016
  • FROM microsoft/aspnet:4.6.2-windowsservercore-ltsc2016

My log file is written in c:\temp\logs so I make a custom WebApp on tis folder:

RUN powershell.exe New-WebVirtualDirectory -Site ‘Default Web Site’ -Name Logs -PhysicalPath ‘c:\temp\logs’

With this kind of dockerfile, I can see the log file of my Windows Service and communicate with him:

LMDBServiceNet coded in C# .NET

On Monday 3, I will make a demo in my company about Docker/Azure and I have decided to make a demo about C# .NET stuff because few people are interested in C++… So I have rewritten my service in C#. It was not very difficult:

  • Web Server provided by CPP Rest SDK is migrated with System.Net.Http
  • LMDBWindows64.dll is wrapped by LMDBNet.dll with C# bindings
  • C++ syntax is the same as C# syntax so all the code rebuild ok at 90%

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LMDBNet;
using Newtonsoft.Json;

namespace LMDBServiceNet
{
    class WebServer
    {
        HttpListener _listener;
        LMDBWrapper _wrapper;

        public WebServer(string uriPrefix)
        {
            _listener = new HttpListener();
            _listener.Prefixes.Add(uriPrefix);

            _wrapper = new LMDBWrapper();
            _wrapper.Init("cache_db");
        }
        public async void Start()
        {
            _listener.Start();
            while (true)
                try
                {
                    var context = await _listener.GetContextAsync();
                    Task.Run(() => ProcessRequestAsync(context));
                }
                catch (HttpListenerException) { break; } // Listener stopped.
                catch (InvalidOperationException) { break; } // Listener stopped.
        }
        public void Stop() { _listener.Stop(); }

        async void ProcessRequestAsync(HttpListenerContext context)
        {
            try
            {
                string request = Path.GetFileName(context.Request.RawUrl);
                string str = String.Format("you asked for: {0}", request);
                //Console.WriteLine(str);

                Dictionary<string, string> parameters = ExtractParameters(context);

                if (parameters.Count == 0)
                {
                    await WriteResponse(context, String.Empty, HttpStatusCode.OK);
                    return;
                }

                string verb;
                if ( parameters.TryGetValue("request", out verb) == false )
                {
                    await WriteResponse(context, String.Empty, HttpStatusCode.OK);
                    return;
                }

                if (context.Request.HttpMethod == "GET")
                {
                    if (verb == Constants.VerbPing)
                    {
                        await RequestVerbPing(context);
                        return;
                    }
                    else if (verb == Constants.VerbUsage)
                    {
                        await RequestUsage(context);
                        return;
                    }
                    else if (verb == Constants.VerbGetData)
                    {
                        await RequestVerbGetData(context, parameters);
                        return;
                    }
                    else if (verb == Constants.VerbSetData)
                    {
                        await RequestVerbSetData(context, parameters);
                        return;
                    }
                }

                await WriteResponse(context, String.Empty, HttpStatusCode.OK);
            }
            catch (Exception ex) { Console.WriteLine("Request error: " + ex); }
        }

        private Dictionary<string, string> ExtractParameters(HttpListenerContext context)
        {
            string request = Path.GetFileName(context.Request.RawUrl);
            string str = String.Format("Request: {0}", request);
            //Console.WriteLine(str);

            //http://192.168.175.241:7001/MyServer/LMDB/?request=set-data&key=toto0&value=toto1&name=cache2

            Dictionary<string, string> parameters = new Dictionary<string, string>();

            if (String.IsNullOrEmpty(request))
                return parameters;

            var strings = request.Split('&');

            if (strings == null)
                return parameters;

            if (strings.Length >= 1)
            {
                strings[0] = strings[0].Remove(0, 1);
            }
            else
            {
                return parameters;
            }

            foreach (string s in strings)
            {
                //Console.WriteLine(s);
                var data = s.Split('=');
                if( data.Length == 2)
                {
                    string values = String.Format("{0}:{1}", data[0], data[1]);
                    //Console.WriteLine(values);

                    parameters.Add(data[0], data[1]);

                }
            }

            return parameters;

        }

        private async Task WriteResponse(HttpListenerContext context, string message, HttpStatusCode code)
        {
            Logger.LogInfo(message);

            var enc = Encoding.UTF8;
            byte[] msg = enc.GetBytes(message);

            context.Response.StatusCode = (int)code;

            context.Response.ContentLength64 = msg.Length;
            using (Stream s = context.Response.OutputStream)
                await s.WriteAsync(msg, 0, msg.Length);
        }

        private async Task RequestUsage(HttpListenerContext context)
        {

            DataUsage usage = new DataUsage();
            usage.company = "NEOS-SDI";
            usage.developer = "Christophe Pichaud";
            usage.version = "August 2008 BETA 0.3 .NET C#";

            string str = JsonConvert.SerializeObject(usage);

            await WriteResponse(context, str, HttpStatusCode.OK);
        }

        private async Task RequestVerbPing(HttpListenerContext context)
        {
            DataPing ping = new DataPing();
            ping.ip = "localhost";
            ping.port = Constants.MasterNodePort;
            ping.server = Environment.MachineName;

            string str = JsonConvert.SerializeObject(ping);

            await WriteResponse(context, str, HttpStatusCode.OK);
        }

        private async Task RequestVerbSetData(HttpListenerContext context, Dictionary<string, string> parameters)
        {
            string key;
            string value;

            if (parameters.TryGetValue("key", out key) == false ||
                parameters.TryGetValue("value", out value) == false)
            {
                await WriteResponse(context, String.Empty, HttpStatusCode.OK);
                return;
            }

            _wrapper.SetData(key, value);

            Data data = new Data();
            data.Key = key;
            data.Value = value;

            string str = JsonConvert.SerializeObject(data);
            await WriteResponse(context, str, HttpStatusCode.OK);
        }

        private async Task RequestVerbGetData(HttpListenerContext context, Dictionary<string, string> parameters)
        {
            string key;
            string value;

            if (parameters.TryGetValue("key", out key) == false)
            {
                await WriteResponse(context, String.Empty, HttpStatusCode.OK);
                return;
            }

            _wrapper.GetData(key, out value);

            Data data = new Data();
            data.Key = key;
            data.Value = value;

            string str = JsonConvert.SerializeObject(data);
            await WriteResponse(context, str, HttpStatusCode.OK);
        }
    }
}