Nordes – HoNoSoFt https://blog.honosoft.com Blog & Roll Mon, 02 Nov 2020 02:19:26 +0000 en-CA hourly 1 https://wordpress.org/?v=6.8.11 https://blog.honosoft.com/wp-content/uploads/2018/06/logo.png Nordes – HoNoSoFt https://blog.honosoft.com 32 32 Observability of a platform with Instana https://blog.honosoft.com/2020/11/01/observability-of-a-platform-with-instana/?utm_source=rss&utm_medium=rss&utm_campaign=observability-of-a-platform-with-instana https://blog.honosoft.com/2020/11/01/observability-of-a-platform-with-instana/#respond Sun, 01 Nov 2020 19:56:33 +0000 https://blog.honosoft.com/?p=679 Continue Reading]]> Recently, I was investigating for a good APM solution. I came across many and tried only a few of them in the end. Instana was one of those solution that I wanted to go a bit deeper in my evaluation.

In this article, I will be using Azure Kubernetes Service (AKS) with a simple Dotnet core application. The Ingress controller is more or less the default one (Nginx Ingress Controller).

The flow below gives an overview of how everything gets pushed to Instana. Keep in mind that the instana-agent is also taking information from the infrastructure itself (Kubernetes, nodes, …) and do also some auto-discovery. The view below is quite simplified.

General idea of the flow

What is the meaning of APM?

APM stands for Application Performance Monitoring (or sometimes Management). Basically, it helps to understand how your platform is doing and help you investigates more deeply when an error occurs. This is a part of the observability of a platform.

If you wish to know more about observability, I suggest you to go read also the following articles:

Installation of Instana

As I was going to use it with a Kubernetes Infrastructure, I decided to follow the step by step from the website. It worked great. That being said, you should probably use the Helm 3 chart instead in order to make it easier for integration and update of the system. I discovered the Helm chart a bit after I installed it using the generated YAML from the website. Keep in mind that the repository is actually in the “general” helm repository and will be moved within the Instana site repository.

Once the installation completed, you will start seeing your entire infrastructure in Instana without having doing much. So the namespaces, pods, services, etc. will be displayed. In case you have a non dotnet service, you might as well be already seeing some details from your applications within the screens.

Sample of K8s auto-discovery (Top Status Bar)

Deploying/Using a Dotnet application

Basically, to get the things working, you simply have to follow the documentation on the site (Instana Doc). Basically, instead of adding a package in your Dockerfile, you use a library. The idea is pretty much the same, but at least it’s more predictable and it’s a no brainer.

NuGet:

  • Instana.Tracing.Core – Basic thing to add. This communicate with the agent on the infrastructure
  • Instana.Tracing.Core.Sdk – If you want to create custom spans and better tracing
  • Instana.Tracing.Core.Rewriter.Linux (Linux, not Alpine) – This is the package adding the tracing C library (.so) and creates a folder for some settings and all. Just use the default, it will work just fine. A different package exist for Alpine or other (see the doc.)

Probably, most people will use only the Core and the Rewriter in order to send the basic data. The SDK is if you wish to let’s say, add the CustomerId as part of information within the request tracing.

Once running, your dashboard will start receiving the requests:

Dashboard of FakeApp Service

You can also easily see the communication from your service to other services by having an automatic-dependency graph (Below you can see my 2 services interaction, if you had a database, it would also show):

Service dependency call graph

In Instana it’s also easy to see our performances metrics since they also show based on the services. You can also track the frontend application by adding a small snippet.

Instana also offer some automatic monitoring and generate alerts based on some metrics. Such alerts can be reconfigured. It can also send message to your MS Teams group/channel. Which mean, that you could even add some flow to your issues (Microsoft Flow/Power Automate).

Single agent per node

It’s important to note that we have 1 agent per node. So our application require to call our “actual” node agent in order to send the data. In Kubernetes you will probably have a deployment file with something similar to this:

        env:
        - name: INSTANA_AGENT_HOST
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP

This is a different model than, let’s say, New-Relic. In New-Relic, we have 1 agent per host AND our containers (dotnet) will be also having an agent sending data directly to New-Relic.

Pricing model

The pricing model can be quite attractive for most company. In my case, it was not attractive enough since we would need agents on multiple nodes and server (on premise). If your infrastructure is well-known it will be easy to calculate the cost since it’s not based on the consumption of logs nor users. It is solely based on the number of hosts. So if you have a cluster of 5, you do 79$*5.

This mean that you won’t lose any logs and won’t be afraid to simply ship everything over there. That’s a big win if you compare to the complex pricing of DataDog.

Some UI bugs or improvement to be made at the moment of writing

(Bug) The “Live” update was not always working for me and I had to refresh the page. Maybe this was due to my browser, who knows. The refresh was also sometimes removing the live option and I had to push it back for some reason.

(Improvement) I was searching how to create a custom dashboard. The main dashboard is easy to find. It’s the first button in the menu on the left. However, once there, we need to click on the Instana button (top left) in order to see that we can create our own dashboard. I wish it was clearer to add a new dashboard. I must have skipped the welcome screen, so that’s why I didn’t notice at first.

Conclusion

Depending on your need, this solution could be a game changer in terms of pricing, observability and much more.

]]>
https://blog.honosoft.com/2020/11/01/observability-of-a-platform-with-instana/feed/ 0
How to have more fun with a SAFE Stack https://blog.honosoft.com/2020/03/17/how-to-have-more-fun-with-a-safe-stack/?utm_source=rss&utm_medium=rss&utm_campaign=how-to-have-more-fun-with-a-safe-stack https://blog.honosoft.com/2020/03/17/how-to-have-more-fun-with-a-safe-stack/#respond Tue, 17 Mar 2020 12:01:34 +0000 https://blog.honosoft.com/?p=649 Continue Reading]]> While watching some video from London NDC’20 on YouTube, some older video appeared within the suggestion box and I clicked on it due to my interest in the matter. Basically, it was a video talking about how to create a Office 365 Excel like F# |> Elmish |> React app. It’s quite interesting and the guy build something incredible in only 1 hour. (Link here)

By watching that video I started to search what he used and then stumbled on the official fable elmish repository, but also I found out an another one which is more to my liking and it was SAFE Stack (SAFE stands for Saturn Azure Fable and Elmish). A nice article have been written not long ago by Isaac Abhrams (MSDN Link), so I won’t try to repeat what he already wrote.

In this article, we will simply explore how to create your first application.

Why is it so interesting

Basically, if we use the SAFE Stack, everything is more or less working together. You write your back-end in F#, your front-end in F# and then you can share domain objects and basic functions between the two since all is compiled (or transpiled depending where you look at). If you run all within VS Code, it’s going to be a nice experience since you can save in back or front and then see the new results on the interface (back-end needs a page refresh in such a case or a new call to the server).

When putting breakpoints in the F# file, you can debug your front or backend directly. Also, if you know React JS and it’s plugin in Chrome, you know that you have a time machine for your front-end. It’s also working out of the box, so it’s great to debug or receive an “how to reproduce” script.

Requirements

  • NodeJs
  • Yarn
  • Dotnet Core 3.1
  • Crome with Redux extension (Didn’t work with Brave Browser due to some linking from VS Code)

More details at https://safe-stack.github.io/docs/quickstart/

Let’s install SAFE Stack

We’re in March 2020 and it’s .Net Core 3.1 era.

Add a new template to your dotnet new

This will allow you to scaffold template project. The project being quite active, I suggest you to update once in a while by retyping the same command. It will download the latest version while re-installing. (It’s based on a NuGet template package which you can follow).

dotnet new -i SAFE.Template

Create a new folder and then scaffold a first app

Details on command line arguments at https://safe-stack.github.io/docs/template-overview/

dotnet new SAFE --layout fulma-cover --deploy docker

Restore the whole app (takes a bit of time)

dotnet tool restore

Run without VS Code (No nice debugging experience)

Use the following to see if all is working as expected (Takes time on the first launch since it downloads everything).

dotnet fake build --target run

Run within VS Code (Integrated and nice experience)

Open VS Code in the current folder code .. If the extension required to run are not installed it will pop-up the following message. Simply agree

Once installed, if not already go on the debug icon on the left menu bar and look at the targets:

Click on Debug SAFE App. This will start both front-end and back-end server and watch/attach process in VS Code. This will allow to do live debug. After you click and wait, you should have 2 process attached

If you look at your source code from the F# view (default it after you have installed the plugin and opened a folder with FS files). You will see that you have only a few files, while in reality you have many. Simply go in the folder view to see everything. You will also see there’s a shared folder with a file. That file is shared through the FSProj file.

Default view after starting the application

Application created, let’s explore quickly the files

Front-end

All the front-end is build using react/redux. Since it’s the case and it’s quite nice, you can use the time machine to play around.

The code to generate the UX is something that looks like bellow:

let containerBox (model : Model) (dispatch : Msg -> unit) =
    Box.box' [ ]
        [ Field.div [ Field.IsGrouped ]
            [ Control.p [ Control.IsExpanded ]
                [ Input.text
                    [ Input.Disabled true
                      Input.Value (show model) ] ]
              Control.p [ ]
                [ Button.a
                    [ Button.Color IsPrimary
                      Button.OnClick (fun _ -> dispatch Increment) ]
                    [ str "+" ] ]
              Control.p [ ]
                [ Button.a
                    [ Button.Color IsPrimary
                      Button.OnClick (fun _ -> dispatch Decrement) ]
                    [ str "-" ] ] ] ]

Most of the UX is created using Fulma functions (Control.p, Field.div, etc.). In case you would like to have a line break, you could add a line with br []. It’s not because it’s using most likely Fulma that you cannot use the Fable.React.Standard html controls.

The first [] are for the style (class and stuff like that) and the second [] is the content.

The default project put all within one file, but nothing does not allow you to split across multiple file. Even the tutorial SAFE-Dojo is built using a bit more separation of concerns.

Back-end

Like the front-end, I would have loved to have a better separation within the template scaffolding. Right now, only one file is created and it’s up to you to know what to do.

Since the back-end is built around Saturn and Giraffe, you can see at the doc to understand more how to split your files (Which I highly recommend).

Otherwise, for the back-end, it’s the usual. You use your code and favorite libraries. Don’t forget that you can share some logic and types between your back and front.

Next step

I will try to come back on this, but, it will be about moving the file around and going a bit deeper with a bigger scenario. At the moment, the samples on the website are not all up to date and you might experience some issue by running them. That being said, enjoy playing around until the next post.

Thank you for reading!

]]>
https://blog.honosoft.com/2020/03/17/how-to-have-more-fun-with-a-safe-stack/feed/ 0
kubeadm – How to “upgrade” (update) your configuration https://blog.honosoft.com/2020/01/31/kubeadm-how-to-upgrade-update-your-configuration/?utm_source=rss&utm_medium=rss&utm_campaign=kubeadm-how-to-upgrade-update-your-configuration https://blog.honosoft.com/2020/01/31/kubeadm-how-to-upgrade-update-your-configuration/#respond Fri, 31 Jan 2020 03:57:37 +0000 https://blog.honosoft.com/?p=628 Continue Reading]]> As you may know, you can easily configure a Kubernetes master or high availability (HA) cluster using kubeadm. All the instruction are on the kubernetes.io website. However, there’s no details about how to play with the configuration or how to apply a modification to the configuration. After a bit of searching on google I was not able to find how to update my current cluster configuration “the proper way” using kubeadm and it’s configuration.

After you run the kubeadm tool in order to install your cluster (or server) generate a kubeadm-config within the ConfigMap on the kube-system namespace. If you edit that ConfigMap, the changes won’t be propagated on the master nodes. If you want to apply the changes, you will have to apply the configuration yourself master by master.

In this article, I will explain how to apply such changes.

Get your configuration in kubeadm format

The command is simple and easy to find all over the internet. Basically you want to view the current configuration and save it into a file. In linux, you simply type the following command:

kubeadm config view > kubeadm-config.yaml

Now that you have the configuration applied during the kubeadm init (or join) phase you can now edit and do your changes. I would absolutely not recommend to change your CIDR here. In my case, the kube-apiserver does not run using the first network interface. This bring some issues since kubeadm take for granted that you will be using your first network interface. For example, in vagrant, it means that it can access the kubernetes network using the enp0s8 which is the second NIC. The first NIC is used by vagrant itself during the installation and to connect to it using the NAT on the enp0s3. To ensure that the reconfiguration will be working, I absolutely need to inject the advertise-address in the configuration.

Edit your configuration

Bellow, you will see that I’ve added some legacy API (deprecated) used by let’s say Gitlab-ce and the advertise-address. Beware that the advertise-address should be different on each master you reconfigure.

apiServer:
  extraArgs:
    advertise-address: 192.168.5.102
    authorization-mode: Node,RBAC
    runtime-config: apps/v1beta1=true,apps/v1beta2=true,extensions/v1beta1/daemonsets=true,extensions/v1beta1/deployments=true,extensions/v1beta1/replicasets=true,extensions/v1beta1/networkpolicies=true,extensions/v1beta1/podsecuritypolicies=true
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controlPlaneEndpoint: kube-lb:6443
controllerManager: {}
dns:
  type: CoreDNS
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: k8s.gcr.io
kind: ClusterConfiguration
kubernetesVersion: v1.17.2
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/12
scheduler: {}

Validate your changes

To verify if your configuration match what you want to do, you can do a diff with the current server.

kubeadm upgrade diff --config kubeadm-config.yaml

Apply your changes

Once you’re happy with your adjustments, you can then apply them. In the following command I’ve enabled the verbose mode to give all the output of what it is doing. You can skip it if you wish. I personally like to see what’s happening.

kubeadm upgrade apply --config kubeadm-config.yaml --ignore-preflight-errors all --force --v=5

In case you are not so sure about what you’re going to do, you might want to do a –dry-run before applying it.

Once applied, the ConfigMap will be updated. The configuration there only represent the last “kubeadm” configuration you’ve applied. So, each time you re-apply a new version of that configuration will be shown.

Upgrade other master node

The upgrade does not update all your “master” on the cluster, it only upgrade the current one where you are. You will need to apply the config on each master by proceeding the last part of this article (change IP of advertise address in my case and then run the upgrade apply).

That’s it for today 😉

Featured image by: Fletcher Pride
]]>
https://blog.honosoft.com/2020/01/31/kubeadm-how-to-upgrade-update-your-configuration/feed/ 0
Dotnet Core : What can you do in case you wish to authorize without [Authorize] ? https://blog.honosoft.com/2019/07/09/dotnet-core-what-can-you-do-in-case-you-wish-to-authorize-without-authorize/?utm_source=rss&utm_medium=rss&utm_campaign=dotnet-core-what-can-you-do-in-case-you-wish-to-authorize-without-authorize https://blog.honosoft.com/2019/07/09/dotnet-core-what-can-you-do-in-case-you-wish-to-authorize-without-authorize/#comments Tue, 09 Jul 2019 12:47:21 +0000 https://blog.honosoft.com/?p=586 Continue Reading]]> In some cases, the [Authorize] attribute is not all you want. Sometimes, you wish that something else existed and that’s where the IAuthorizationFilter (or IAsyncAuthorizationFilter) come into play. Before going there, ensure that you don’t simply need a new Policy (See MSDN article or doc.). For more details about the Filter I will let you read the MSDN page which is always updated.

What we will cover here:

Ordering of the filters within Dotnet Core

The request is processed through Authorization Filters, Resource Filters, Model Binding, Action Filters, Action Execution and Action Result Conversion, Exception Filters, Result Filters, and Result Execution. On the way out, the request is only processed by Result Filters and Resource Filters before becoming a response sent to the client.
Image from this MSDN article

Basically, most of the time we want to add some behavior within the ActionFilter area. But when it comes to authorization, the best is to stop the entire pipeline as soon as possible. That’s where the IAuthorizationFilter comes into play.

Sample of creating an IAuthorizationFilter

The IAuthorizationFilter only require us one method to implement (i.e.: OnAuthorization). There is also no need of doing any dependency injection for such attribute in order to activate it. The following code is only an example doing nothing special, but you should grasp the idea.

    public sealed class SpecialAuthorizeAttribute : Attribute, IAuthorizationFilter  // or IAsyncAuthorizationFilter  ...
    {
        private const string HEADER_SPECIAL_STUFF = "specialHeaderStuff";

        public void OnAuthorization(AuthorizationFilterContext context)
        {
            if (context != null)
            {
                var authCode = context.HttpContext.Request.Headers[HEADER_SPECIAL_STUFF];
                // Write your logic here.
                if (string.IsNullOrEmpty(authCode))
                {
                    context.Result = new UnauthorizedObjectResult($"{HEADER_SPECIAL_STUFF} is required");
                    return;
                }

                if (!authCode.Equals("IAmValid"))
                {
                    context.Result = new UnauthorizedObjectResult($"{HEADER_SPECIAL_STUFF} is invalid");
                    return;
                }

                // ===== if you're here, it's a success =====
                // DO STUFF
                //
                // ===== you can also use registered services =====
                // var someService = context.HttpContext.RequestServices.GetService<ISomeService>();
            }
        }
    }

Sample of using our custom IAuthorizationFilter

The following code is based on a new WebApi project.

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{

    // GET api/values/5
    [SpecialAuthorize]
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        return "value";
    }

    // ... other stuff
}

In order to execute, you can simply do a HTTP call using Curl.

nordes@Something:~$ curl https://localhost:5001/api/values/1 --insecure && echo ''
specialHeaderStuff is required
nordes@Something:~$ curl https://localhost:5001/api/values/1 -H 'specialHeaderStuff:IAmInvalid' --insecure && echo ''
specialHeaderStuff is invalid
nordes@Something:~$ curl https://localhost:5001/api/values/1 -H 'specialHeaderStuff:IAmValid' --insecure && echo ''
value

As you can see, when I use a Valid value, it is accepted and then process the Controller-Action. The attribute could also be put on the Controller and in such case will apply that rule to every actions.

Conclusion

As you can see, it’s not something complex to do. What you should ask yourself is if you need to use it? In my case, I had to use it for specific scenario, but most people will probably simply use the policy over the official Authorize attribute given by the framework.

]]>
https://blog.honosoft.com/2019/07/09/dotnet-core-what-can-you-do-in-case-you-wish-to-authorize-without-authorize/feed/ 1
#Slack |> App |> Smee |> My Local App |> #Slack Reply : How to interact when you’re behind Firewall/Proxy https://blog.honosoft.com/2019/05/24/slack-app-smee-my-local-app-slack-reply-how-to-interact-when-youre-behind-firewall-proxy/?utm_source=rss&utm_medium=rss&utm_campaign=slack-app-smee-my-local-app-slack-reply-how-to-interact-when-youre-behind-firewall-proxy https://blog.honosoft.com/2019/05/24/slack-app-smee-my-local-app-slack-reply-how-to-interact-when-youre-behind-firewall-proxy/#respond Fri, 24 May 2019 12:48:27 +0000 https://blog.honosoft.com/?p=562 Continue Reading]]> Introduction

All I wanted to do is simply have a way to connect to my local server on the network and then when receiving a specific request from #Slack. Once received act on it, do a some background work or send reports. This server is obviously not exposed on the internet and reside behind a firewall/proxy. For that reason, I had to be a bit more creative and think out of the box.

In the past I resolved this by using a WebSocket to an Heroku WebSite. It works but it was not perfect. So, I started to look around for a better way to stream a service where I a simple Webhook would be forwarded. In that manner, I could watch a service where it send me back the data. I recently came across Smee.io which use the Server Side Events (SSE) but as a streaming service on the HTTP port. Following is a story of how to make all that working together.

Before going further, I would have loved a solution like
ngrok, but it’s not possible behind a proxy/firewall such as where I work.

Step 1. Grab a new Smee URL

To get the URI, it’s deadly simple. Simply go on Smee.io and then click on create the big button in order to create a new Webhook. Keep the Webhook URL for the next step.

Step 2. Configure the #Slack App/Bot

In that App, we will setup a bot, a hook and a bot for commands.

Configure the App

Open your #Slack page and add an App and if you don’t know how, simply go on https://api.slack.com/ and click on Start Building button and fill the form. It should look like this:

Once you have created your app, you will need to enable “Bot” and give him a name, and then go into the Create a new command page and then add a new command like the following:

Install your app

For that, you go for example in OAuth & Permissions and click install app To Workspace. (Note, you might also have to add a permission File.Upload.User)

You can see the beginning of the token. The 4 first characters indicate what kind of token it is. (Documentation in slack documentation exists for more details)

Step 3. Keep it simple with a sample app in NodeJS or Dotnet Core

Due to some missing implementation in the original repository/server, I’ve added what’s missing in my fork within GitHub. I then use my Heroku account to generate automatically my Docker container with the service. In the future, the issues should be fixed (PR currently waiting to be approved).

The main issue with the Smee.IO website is that it does not yet forward the content if it’s using x-www-form-urlencoded. If you use my branch, for now you will be ok. You can even use it for building your docker service on heroku.

Sample receiving data using NodeJS (index.js + smee-client & express packages)

const SmeeClient = require('smee-client')

/// Smee client (websocket)
const smee = new SmeeClient({
  source: 'https://smee.io/5sFasdasdukH5VQidvpGv', // In case Smee is not updated, please use my repository + an heroku deployment. It is that easy.
  target: 'http://localhost:3000/events',
  logger: console
})
const events = smee.start()
/// WebServer
const express = require('express');
const app = express();
const router = express.Router();

app.use(express.json()) // Instead of body-parser
app.use(express.urlencoded()) // Instead of body-parser
app.use(function(req, res, next) { // Allow CORS if you want.
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

console.log(app)

// from top level path e.g. localhost:3000, this response will be sent
app.get('/', (request, response) => response.send('Hello World'));
app.use('/events', router);

router.post('/', (request, response, next) => {
  console.log(request.body) // Raw data
  response.end();
});

app.listen(3000, () => console.log('Listening on port 3000'));

Sample receiving data using Dotnet Core

NuGet Package: Smee.IO.Client (That library simply do the SSE streaming for smee.io event types for you. So, if you want to use it for different SSE messages types, you will have to adapt the code).

The following code is also available in my Github repo (Demo).

using System;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Smee.IO.Client.ConsoleDemo
{
    class Program
    {
        private static CancellationTokenSource source;

        static async Task Main(string[] args)
        {
            source = new CancellationTokenSource();
            var token = source.Token;

            // This could also be done automatically, but since we expect some developer to test, let's
            // keep it this way.
            Console.WriteLine("Hi there, please get a valid url on https://smee.io/new (or your own server. In case of this demo, I will use my own instance)");
            Console.Write("Please enter a valid URI because no validation will be made: ");
            var smeeUri = new Uri(Console.ReadLine());

            Console.ForegroundColor = ConsoleColor.DarkRed;
            Console.WriteLine(" > Hit CTRL-C in order to stop everything.");
            Console.WriteLine();
            Console.ResetColor();

            var smeeCli = new SmeeClient(smeeUri);
            smeeCli.OnConnect += (sender, a) => Console.WriteLine($"Connected to Smee.io ({smeeUri}){Environment.NewLine}");
            smeeCli.OnDisconnect += (sender, a) => Console.WriteLine($"Disconnected from Smee.io ({smeeUri}){Environment.NewLine}");
            smeeCli.OnMessage += (sender, smeeEvent) =>
            {
                Console.Write("Message received: ");
                Console.ForegroundColor = ConsoleColor.DarkYellow;
                Console.Write(JsonConvert.SerializeObject(smeeEvent)); // This is a typed object.
                Console.ResetColor();
                Console.WriteLine();
                Console.WriteLine();
            };
            smeeCli.OnPing += (sender, a) => Console.WriteLine($"Ping from Smee{Environment.NewLine}");
            smeeCli.OnError += (sender, e) => Console.WriteLine($"Error was raised (Disconnect/Anything else: {e.Message}{Environment.NewLine}");

            Console.CancelKeyPress += (sender, eventArgs) =>
            {
                source.Cancel();
                eventArgs.Cancel = true;
            };

            await smeeCli.StartAsync(token);
            Console.WriteLine("Finish executing. Thank you!");
        }
    }
}

Example of what you can see in Smee.io console

Slack Webhook call (Command)

The command in the previous capture is using a different command, don’t worry. Anything will do.

If the payload is empty, it’s because the content type is application/x-www-form-urlencoded (Current limitation on Smee.io). If you use my branch, as said earlier, you will have the proper data.

We can receive, now let’s send

For this part, you have a few option. I will be using the Dotnet implementation from now on. However, know that you can either use a library or use raw HTTP command using the Slack API. Basically, you will do either HTTP post to a specific URL or to the response_url. The response_url is not something that stays forever. As of now, it stays 30 minutes alive, after that, normally, it won’t be usable. It can be useful to make a small dialog with options that needs to be selected. Here we will now focus to send a simple message back to say “Message received!”.

In Dotnet, but also in NodeJS, some people already have written some libraries (e.g.: SlackAPI). It’s up to you to use them. The following code will be using a raw lazy HTTP post. For that, let’s replace smeeCli.OnMessage += ... by the following (not fully completed, but you get the idea):

smeeCli.OnMessage += (sender, smeeEvent) =>
{
    IncomingMessage msgBody = null;
    if (e.Data.Body != null)
    {
        msgBody = (e.Data.Body as JObject)?.ToObject<IncomingMessage>();
    }

    // If it's for command listener, you could use a strategy pattern.
    // Some code is not in previous block, but you can easily find out what to put in order to make
    // it work.
    _slackHttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _slackConfiguration.BotOAuthToken);
    var msg = new
    {
        token = _slackConfiguration.BotOAuthToken,
        channel = msgBody.UserId,
        // response_type = "ephemeral", // See doc.
        text = "Message received!"
    };
    var content = new StringContent(JsonConvert.SerializeObject(msg), Encoding.UTF8, "application/json");
    var result = await _slackHttpClient.PostAsync("chat.postMessage", content).ConfigureAwait(false);
    // https://api.slack.com/methods/im.open/test (open)
    // send message to specific channel...
    // https://api.slack.com/methods/im.close/test (open)
    // Conversation could be created, but for now let's consider no conversation.
    // e.g.: https://api.slack.com/dialogs#select_elements <== create a select box...
};

What’s next?

  • Basically, if you wish, you could also link yourself with Luis.AI, TensorFlow or anything in order to make a Chat Bot more alive and more intelligent.
  • Create some command to interact with your servers
  • Link your slack account with some of your service in order to be notified when some jobs are completed for example.
  • Link/Sync/Send stuff between your #Slack and your MS Team
  • …the sky is the limit…

The limits are actually your limits and how secure you want your stuff to be (as usual).

Conclusion

I hope you’ve enjoyed that article ;). I don’t have much time recently, so it’s hard to write more often.

]]>
https://blog.honosoft.com/2019/05/24/slack-app-smee-my-local-app-slack-reply-how-to-interact-when-youre-behind-firewall-proxy/feed/ 0
F# or as some says F for Fun https://blog.honosoft.com/2019/03/30/f-or-as-some-says-f-for-fun/?utm_source=rss&utm_medium=rss&utm_campaign=f-or-as-some-says-f-for-fun https://blog.honosoft.com/2019/03/30/f-or-as-some-says-f-for-fun/#respond Sat, 30 Mar 2019 09:19:41 +0000 https://blog.honosoft.com/?p=552 Continue Reading]]> Welcome to the functional world. As someone who believe that we should learn everyday, I always look around for new technologies. Those technologies range from anything that could potentially touch software. It can be interacting with either something physical or simply an another program.

The language in itself

Maybe you know, maybe you don’t know. F# is the functional language from the Dotnet platform and has been developed quite a long time ago (see wiki). Functional is the rival to Object Oriented programming. In the MS stack, it is considered a first class citizen when it come to develop an application. While this language, in my opinion, is not used that often. If we are willing to have a mixed technology project, it could bring a lot of goods in the development. The domain could actually be driven by the architects and then the development made by the developers.

This language allow you to enforce your business rules at compile time. Since it’s under the Dotnet platform, it compiles in IL and can interop natively with the other languages such as C# or VB.

How I got to play around F#

I actually gave myself a challenge during the AdventOfCode 2018. That side actually create a story with puzzle games during the month of December. This allowed me to have a first impression on F#. I completed a bit more than the half of the problems. My two issues were that I had a lot of work and I had to read all the documentation online in order to understand how to use F#. Great resources can be found at https://fsharpforfunandprofit.com.

What are the advantages?

Strong typings

If you’ve written some code in ADA (which I doubt), you probably remember it’s a strongly typed language which does not allow you to do anything without typing. F# is no different, except that it allows you to have a bit less restriction on your types. For example you can easily redefine an int to something more meaningful (e.g.: PaperInTray: int). Which mean that you could talk about having a number associated to a tray.

let Printer = {
    Tray1: PaperInTray
    Tray2: PaperInTray
  }

This was a simple example. However, if you want to know more about the typings, I recommend you to read a book or the documentation found for F#.

There’s no Null

Basically, there’s no null within the language. Instead we have “option” in order to say if you have something or nothing (none). From there you can clean a collection having many none and keep only those with some data. This can also be used afterwards within the pattern matching.

If it compiles, it will most likely work as expected

Since it’s strongly typed, it will most likely works at first run. This is because it won’t compile if you mess around. If you miss some cases in your pattern matches, it will tell you.

Your records are automa-gically “equatable” and “comparable”

Yes, you’ve heard it, your records (a type of object which translate into either class or struct under the hood) allows you to do “=” or even some other operations.

If you don’t mess around, by default, what you write will be “Pure”

What is “pure” coding? An easy answer to that is that everything is immutable and that everything could work in a static world where you call over and over the same method in order to have over and over the same result.

By default, the language create everything immutable and only if you “really” want to, you can add the mutable keyword in order to have mutability of your values. (E.g.: let mutable myString = “abc” , this will allow you to do myString <- “hello” ).

Conclusion

I don’t want to enumerate everything here, because there’s great site already explaining what you can or cannot do (fsharp.org, fsharpforfunandprofit.com, and many others). But from a discussion I had with a colleague, it seems that C# is going slowly towards F# regarding a few points. In C# 8, just to name one feature, there’s the possibility to avoid having null going all around. Recently I saw that it is a nice language to even do your shell script in Linux (fsx) ;), how about you?

I hope you’ve enjoyed.

]]>
https://blog.honosoft.com/2019/03/30/f-or-as-some-says-f-for-fun/feed/ 0
Linux + Dotnet Core – GSettings (LibGio) directly from code https://blog.honosoft.com/2019/03/14/linux-dotnet-core-gsettings-libgio-directly-from-code/?utm_source=rss&utm_medium=rss&utm_campaign=linux-dotnet-core-gsettings-libgio-directly-from-code https://blog.honosoft.com/2019/03/14/linux-dotnet-core-gsettings-libgio-directly-from-code/#comments Thu, 14 Mar 2019 12:36:00 +0000 https://blog.honosoft.com/?p=518 Continue Reading]]> Some people like to execute shell commands for LibGio – GSettings using NodeJs (child_process) or Dotnet (Process). Personally, I prefer to use directly the C/C++ API from the compiled binaries. It helps to keep the performance and avoid spawning new process instances for no good reason.

In this article, we will talk about how to call the libgio (GSettings especially) from our Dotnet application. Obviously, this will work only from Linux having the library. People familiar with Linux/Gnome GUI already knows about the libgio by using C or C++, but what about using C#?

In case you want to know more about libgio, I recommend you to go on the Gnome Developer site and as extra resource you can also go on their blog post about the topic (First Step with GSettings). I will repeat myself later, but, the GSettings links configuration to your session using the DBUS session. If you don’t have any session, you will be able to read the default value, but not to modify them.

What are we going to experiment?

We will simply try to get the GSettings and set a new value. It means that we will be using only 3 API’s our of many. The full name of the library being used is libgio-2.0.so and those 3 API’s are:

As you can see, the GSettings is a database containing the key-value pairs of strongly typed documents. What is really under the hood for the schema is XML files. The XML is then compiled and the system will be using binary data instead of XML. The normal emplacement for the schemas is in /usr/share/glib-2.0/schemas. Some details about how to create your own schema (Python) can be found on that blog. In case you don’t want to have to specify the path on each request on your custom schema, simply update it by specifying the path directly in the schema element.

In the case you want to test using the command line, you can use the gsettings –help. In case you play in your subsystem (Windows10), you might want to install libglib2.0-bine and dconf-gsettings-backend.

Example of gsettings file for your application

The example bellow, is purely fictional, but if you wish you can look to existing schema available in /usr/share/glib-2.0/schemas/. If the path is part of the schema element, you won’t need to write the path at every request. Also note that the GSettings set won’t work if your dbus is not started for your user. The dbus bridge your settings with your current session.

<schemalist>
  <enum id="com.honosoft.sample.enum">
    <value nick="off" value="1"/>
    <value nick="warming" value="2"/>
    <value nick="on" value="3"/>
  </enum>

  <schema path="/usr/share/glib-2.0/schemas/" id="com.honosoft.sample">
 
    <key type="b" name="my-flag-is-active">
      <default>false</default>
      <summary>I am a boolean flag</summary>
      <description>A description of your boolean</description>
    </key>
    <key type="i" name="threshold">
        <range min="1" max="100"/>
        <default>50</default>
        <summary>Some threshold</summary>
        <description>Some threshold from 1 to 100 about something</description>
    </key>
 
    <key name="list-prime-numbers" type="ai">
      <default>[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43]</default>
      <summary>Some numbers</summary>
      <description>
        List of numbers
      </description>
    </key>
 
    <key name="list-my-pets" type="as">
        <default>['Captain', 'Scrooge', 'Mana', 'Saturn', 'Brutal']</default>
        <summary>Some array of strings</summary>
        <description>List my pet(s) name</description>
    </key>
 
    <key name="current-state" enum="com.honosoft.sample.enum">
        <default>'off'</default>
        <summary>display a state of my application</summary>
        <description>Using the enum allow only a few values pre-defined</description>
    </key>

    <child name="best-book" schema="com.honosoft.sample.book"/>
  </schema>
 
  <schema path="/usr/share/glib-2.0/schemas/" id="com.honosoft.sample.book">
      <key name="title" type="s">
          <default>'Clean Code'</default>
          <summary>Define the book title</summary>
      </key>
      <key name="author" type="s">
          <default>'Robert C. Martin'</default>
          <summary>Define the author name</summary>
      </key>
  </schema>
</schemalist>

After putting your file in the /usr/share/glib-2.0/schemas/ , you need to compile it. To compile and make it available, you have to execute glib-compile-schemas /usr/share/glib-2.0/schemas/ After, you will be able to access the key-value-pair. Note that the command exists simply for debugging purpose. More details can be found on that article.

Sample to retrieve an array of string

How do we call such library from C# (Dotnet)

It’s not as complex as you might think. There’s some gotcha, and if you have C/C++ knowledge it will help you to understand those (such as void pointers).

In Dotnet, we have the attribute DllImports which consists of doing the link between the “dll” (or compiled C/C++ .so) and the framework. The best practice for that would be to create a layer of abstraction over the layer mapping such commands. Here’s the 3 command that we will be using mapped in C# using the attribute:

[DllImport("libgio-2.0.so", EntryPoint = "g_settings_new")]
public static extern IntPtr New(string schema);

[DllImport("libgio-2.0.so", EntryPoint = "g_settings_get_int")]
public static extern int GetInt(IntPtr settings, string key);

[DllImport("libgio-2.0.so", EntryPoint = "g_settings_set_int")]
public static extern bool SetInt(IntPtr settings, string key, int value);

As you can see, the IntPtr is a reference to the GSettings schema.

Let’s experiment the whole process

  1. Request to the user what schema to retrieve
  2. Request to the user what key (int key) to retrieve from the schema
  3. Get the int value from the schema + key
  4. Request the user to give a new value
  5. Set or store the new value
class Program
{
    static void Main(string[] args)
    {
        Console.Write("Schema to look: ");
        var gsettingsSchema = Console.ReadLine();
        Console.Write("Key to look: ");
        var gsettingsKey = Console.ReadLine();

        var gsettings = DemoBindings.GSettings.New(gsettingsSchema);
        var result = DemoBindings.Bindings.GSettings.GetInt(gsettings, gsettingsKey);
        Console.WriteLine($"Value is: {result}");
        Console.Write("Please give me a new value to set: ");
        var newValue = Console.ReadLine();

        var intValue = int.Parse(newValue); // No validation, but you should ;)
        var success = DemoBindings.GSettings.SetInt(gsettings, gsettingsKey, intValue);
        Console.WriteLine($"The new value was set with {success ? string.Empty : "no "} success")
        Console.ReadKey();
    }
}

What does it mean for you?

In the eventually you would write an application that runs in the background triggering some event on the display, you could take advantage of the applications settings (listen even to those) and then maybe trigger some actions. For example:

  • Toggle the display of a virtual keyboard on a touch screen.
  • Get the current session details (windows)

I hope you’ve enjoyed, even if this is a really short blog.

]]>
https://blog.honosoft.com/2019/03/14/linux-dotnet-core-gsettings-libgio-directly-from-code/feed/ 2
Linux & Dotnet – Read from a device file https://blog.honosoft.com/2019/03/12/linux-dotnet-read-from-a-device-file/?utm_source=rss&utm_medium=rss&utm_campaign=linux-dotnet-read-from-a-device-file https://blog.honosoft.com/2019/03/12/linux-dotnet-read-from-a-device-file/#comments Tue, 12 Mar 2019 15:21:37 +0000 https://blog.honosoft.com/?p=491 Continue Reading]]> As you may know, Dotnet Core now runs within Linux. Let’s explore and play around enjoying the fact we can play in any environment now in Core.

Let’s consider that you have a touch panel where you would like to handle everything by yourself (touch, move, etc.). How in the world would you get the touch event?

Probably, if you never played around that low in the system, you probably don’t know. Interestingly, there’s the HID (Human Interface Devices). Most of the documentation is available if you search from your favorite engine. What you really want to know, is the binary data structure, once you have that, the fun can begin. In the case you can’t get any description anywhere, I guess the best choice is to do some reverse engineering (not recommended).

In this article we will only analyse a touch event generating a lot of binary data. I don’t want to cover the entire touch/move/etc of the binary data.

Let’s take the touch screen “touch” click event (KeyPress/Release)

Find the Screen Input Device

Within Linux system, there’s plenty of command in order to find your devices. The device files are usually located within the /dev/…. folder. In the past, we used to have all the existing device in the world in that folder. Nowadays, we simply have the bare minimum and that’s great. Most of the devices, if not all, are documented in the Linus repository. There’s many way to retrieve more details or at least the input device of your choice (touch panel).

One of those method consist in looking in all the USB (/proc/bus/usb/devices) or Input devices (/proc/bus/input/devices) in your system. The touch panel is usually linked to an “Event[1..5]” device.

An alternative is to configure your display to point towards your X-Server and then use the xinput command. If you fail to execute that command, it’s either not installed or you simply forgot to set your environment variable DISPLAY.

xinput --list

Second alternative. Without installing anything, you can use the device manager and look directly in the database and find your touch screen. The command for such a case is udevadm and of course you are required to run this as a root (sudo).

# Give all the devices available on your system. If you have a lot of
# devices connected, consider making the output redirected into a file.
# e.g.: udevadm info --export-db > myFile.txt
udevadm info --export-db 

An another alternative, just in case, is to simply look in the special folder “/dev/input/by-id” and “/dev/input/by-path“. The first give the currently connected device with input capabilities. So if you connect or disconnect an input device, you should be able to see it there. By doing a “ls -l” you will see which event file it’s using since it’s creating a symbolic link to it. For example in this output the event1 is my touchscreen:

myroot@mymachine:/dev/input/by-path# ls -l
total 0
lrwxrwxrwx 1 nobody nogroup 9 Mar  6 08:54 pci-0000:00:14.0-usb-0:13.1:1.1-event -> ../event1
lrwxrwxrwx 1 nobody nogroup 9 Mar  7 23:55 pci-0000:00:14.0-usb-0:13.4.2:1.0-event-kbd -> ../event2

Normally, from here, you know which device file correspond to your device. You might even have more details if you used the udevadm.

Read the binary content

Devices files are the raw data file. In order to be able to do something, you need to stream it as you would do for a TCP/UDP/File data. The structure of the content is structured following the driver rules. For example, the Keyboard and Mouse and a few other devices are considered as well known devices and are well documented all over the internet. You can even go directly in the Unix source code in order to see the .h file.

Let’s create a simple loop receiving the binary content while you touch the panel and then let’s output that raw data using an hex string.

public void ReadDeviceStream(CancellationToken stoppingToken) 
{
  // Use the device file
  var targetFile = new FileInfo("/dev/inputs/event1");

  // Open a stream
  using (FileStream fs = targetFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
  {
    stoppingToken.Register(() => fs?.Close());
    int blockId = 1;

    // A big buffer, for simplicity purpose and to receive the entire touch report. We should use
    // the proper buffer size based on the event size. Note that we could also
    // use the binary reader
    var buffer = new byte[1024];

    // Read until the token gets cancelled
    while (!stoppingToken.IsCancellationRequested && fs.Read(buffer) > 0)
    {
      ShowBinaryContent(blockId, buffer);
      blockId++;
    }
  }
}

public void ShowBinaryContent(int blockId, byte[] buffer)
{
  Console.WriteLine($"Block #{blockId}");
  Console.WriteLine(BitConverter.ToString(bytes)); // Hex format: AB-1D...
  Console.WriteLine(string.Empty);
}

How to interpret the data

The result of the previous small program is displayed here

// Block #1
59-9A-74-5C-00-00-00-00-9C-C7-04-00-00-00-00-00-03-00-39-00-03-01-00-00-
59-9A-74-5C-00-00-00-00-9C-C7-04-00-00-00-00-00-03-00-35-00-31-01-00-00-
59-9A-74-5C-00-00-00-00-9C-C7-04-00-00-00-00-00-03-00-36-00-E8-01-00-00-
59-9A-74-5C-00-00-00-00-9C-C7-04-00-00-00-00-00-01-00-4A-01-01-00-00-00-
59-9A-74-5C-00-00-00-00-9C-C7-04-00-00-00-00-00-03-00-00-00-31-01-00-00-
59-9A-74-5C-00-00-00-00-9C-C7-04-00-00-00-00-00-03-00-01-00-E8-01-00-00-
59-9A-74-5C-00-00-00-00-9C-C7-04-00-00-00-00-00-04-00-05-00-00-00-00-00-
59-9A-74-5C-00-00-00-00-9C-C7-04-00-00-00-00-00-00-00-00-00-00-00-00-00

// Block #2
59-9A-74-5C-00-00-00-00-6F-40-05-00-00-00-00-00-03-00-35-00-2C-01-00-00-
59-9A-74-5C-00-00-00-00-6F-40-05-00-00-00-00-00-03-00-00-00-2C-01-00-00-
59-9A-74-5C-00-00-00-00-6F-40-05-00-00-00-00-00-04-00-05-00-10-27-00-00-
59-9A-74-5C-00-00-00-00-6F-40-05-00-00-00-00-00-00-00-00-00-00-00-00-00
            
// Block #3
59-9A-74-5C-00-00-00-00-5D-96-05-00-00-00-00-00-04-00-05-00-20-4E-00-00-
59-9A-74-5C-00-00-00-00-5D-96-05-00-00-00-00-00-00-00-00-00-00-00-00-00

// Block #4
59-9A-74-5C-00-00-00-00-7D-9A-05-00-00-00-00-00-03-00-39-00-FF-FF-FF-FF-
59-9A-74-5C-00-00-00-00-7D-9A-05-00-00-00-00-00-01-00-4A-01-00-00-00-00-
59-9A-74-5C-00-00-00-00-7D-9A-05-00-00-00-00-00-04-00-05-00-30-75-00-00-
59-9A-74-5C-00-00-00-00-7D-9A-05-00-00-00-00-00-00-00-00-00-00-00-00-00

As you can see, we receive many events at the same time and each block contains their own timestamp (few first bytes on each lines). A block here contains more than one instruction. For example, it tells you where you pushed and if it was a push event or release. Let’s focus on the data looking like the Block #1.

public static void Main()
	{
		// Release
		 var binaryStrings = 
		 new [] { "E3-00-75-5C-00-00-00-00-3F-72-09-00-00-00-00-00-03-00-39-00-0C-01-00-00",
                "E3-00-75-5C-00-00-00-00-3F-72-09-00-00-00-00-00-03-00-35-00-51-01-00-00",
                "E3-00-75-5C-00-00-00-00-3F-72-09-00-00-00-00-00-03-00-36-00-93-01-00-00",
                "E3-00-75-5C-00-00-00-00-3F-72-09-00-00-00-00-00-01-00-4A-01-01-00-00-00",
                "E3-00-75-5C-00-00-00-00-3F-72-09-00-00-00-00-00-03-00-00-00-51-01-00-00",
                "E3-00-75-5C-00-00-00-00-3F-72-09-00-00-00-00-00-03-00-01-00-93-01-00-00",
                "E3-00-75-5C-00-00-00-00-3F-72-09-00-00-00-00-00-04-00-05-00-00-00-00-00",
                "E3-00-75-5C-00-00-00-00-3F-72-09-00-00-00-00-00-00-00-00-00-00-00-00-00"};

		foreach (var bs in binaryStrings) {
			byte[] data = bs.Split('-').Select(b => Convert.ToByte(b, 16)).ToArray();

			Console.Write($"[Sec: {BitConverter.ToUInt32(data, 0)}]");
			Console.Write($"\t[USec: {BitConverter.ToUInt32(data, 8)}]");
			Console.Write($"\t[Type: {BitConverter.ToUInt16(data, 16)}]");
			Console.Write($"\t[Code: {BitConverter.ToUInt16(data, 18)}]");
			Console.Write($"\t[Value: {BitConverter.ToInt32(data, 20)}]");
			Console.WriteLine();
		}
	}
		/*
Ref: https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
Ref: https://www.kernel.org/doc/Documentation/input/event-codes.txt

[Sec: 1551171811]    [USec: 619071]    [Type: 3 EV_ABS]    [Code: 57 ABS_MT_TRACKING_ID]    [Value: 268]  Unique ID of initiated contact
[Sec: 1551171811]    [USec: 619071]    [Type: 3 EV_ABS]    [Code: 53 ABS_MT_POSITION_X]    [Value: 337] Center X touch position 
[Sec: 1551171811]    [USec: 619071]    [Type: 3 EV_ABS]    [Code: 54 ABS_MT_POSITION_Y]    [Value: 403] Center Y touch position
[Sec: 1551171811]    [USec: 619071]    [Type: 1 EV_KEY]    [Code: 330 BTN_TOUCH]    [Value: 1] 
[Sec: 1551171811]    [USec: 619071]    [Type: 3 EV_ABS]    [Code: 0 ABS_X]    [Value: 337] 
[Sec: 1551171811]    [USec: 619071]    [Type: 3 EV_ABS]    [Code: 1 ABS_Y]    [Value: 403]
[Sec: 1551171811]    [USec: 619071]    [Type: 4 EV_MSC]    [Code: 5 MSC_TIMESTAMP]    [Value: 0] 
[Sec: 1551171811]    [USec: 619071]    [Type: 0 EV_SYN]    [Code: 0 SYN_REPORT]    [Value: 0] Indicate the batch is completed and we can proceed
		*/

All the documentation about the types, code, etc. is available from source of Linux (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h).

The structure look like the following (4bit):

(C lang)

struct input_event {
	struct timeval time; // 2 unsigned uint32 or uint64
	unsigned short type; // 4 bit
	unsigned short code; // 4 bit
	unsigned int value;
};
Start PositionTypeName
0UINT32TSec (Timestamp seconds) – E3-00-75-5C + skip 4 bytes in 64bit arch
8UINT32TUsec (Timestamp microseconds) – 3F-72-09 + skip 4 bytes in 64bit arch
16UINT16Type – 4A-01
18UINT16Code – 01-00
20INT32Value – 00-00

The official documentation can be found at https://www.kernel.org/doc/Documentation/input/input.txt under the section 3.2.4 evdev and we can read the following:

The event codes are the same on all architectures and are hardware independent.

https://www.kernel.org/doc/Documentation/input/input.txt

How should we test?

It looks obvious, but in windows you might not be able to test/debug. You need a Linux system (Not subsystem). Since I use a touch panel with Linux, I simply logged the event output while I was experimenting the touch panel. I then replayed that same data while writing UT (TDD). After your TDD passes and that your event gets out as expected, you can then have the desired flow within your application. If you’ve never experimented, know that you can do remote debugging from Visual Studio (or code) to a Linux host. It works well and you might be able to debug more easily.

Existing library to support you

Here we go directly in the raw content, however, there’s a NuGet package that might help you realize what you need. As discussed in the beginning of the article, the HID is the keyword you want to look for, for such development. I haven’t played that much with the following library, but you should definitely use it in case you want to manage the devices from Dotnet. That library is OS agnostics and does not really care if you are on Windows, Linux or MacOS.

The only issue with that library is the lack of documentation. The best is to read the code itself or simply code everything by yourself.

]]>
https://blog.honosoft.com/2019/03/12/linux-dotnet-read-from-a-device-file/feed/ 1
Dotnet and Reflection – Exploration By Example https://blog.honosoft.com/2019/03/06/dotnet-and-reflection-exploration/?utm_source=rss&utm_medium=rss&utm_campaign=dotnet-and-reflection-exploration https://blog.honosoft.com/2019/03/06/dotnet-and-reflection-exploration/#respond Wed, 06 Mar 2019 14:21:00 +0000 https://blog.honosoft.com/?p=458 Continue Reading]]> Today, I will be talking about how to use reflection in order to generate code. The reflection in C# is quite strong and useful for many scenario. In this example I will simply use a dictionary created from a JSON object and then based on the “key” of that dictionary, I will create a special object if it applies, including the value. This could be useful if you receive a lot of data in from a third party, but where you would be interested only in a few keys in order to generate data somewhere in your system. Here we will not go through the performance part, but, simply know that you can alter the algorithm in order to cache the key.

What are we building?

The example will be simple and will be doing the following:

  • Take JSON input
  • Transform that JSON into an object (In this case, an object containing a dictionary)
  • Pass through all the items from the dictionary and match the key against an enum which will be used to generate code
  • Use reflection on the dictionary key enum (if it exists) and create a new special object with the dictionary value
  • Print out the generated data using JSON prettify option

Building block #1 – JSON input

The JSON input will be quite simple, it will be an object containing a simple dictionary.

{ "MyDictionary": { "Key1": 1, "Key2": 2, "Key3": 3.1416 } }

Building block #2 – Basic objects structure

We now know the JSON structure, so let’s create our basic objects. Here we go a bit further than simply creating objects, we also create the Attribute which will be used during the “Reflection”.

class SampleObject
{
    public Dictionary<string, decimal> MyDictionary { get; set; }
}
public class CustomAttribute : Attribute
{
    public string CustomValue { get; set; }

    public CustomAttribute(string customValue)
    {
        CustomValue = customValue;
    }
}
 enum MyDictionarySpecialKeys
 {
     [Custom("Simple Value")]
     Key1,
     [Custom("Another Simple Value")]
     Key3
 }
 class MySpecialItem
 {
     public string Special { get; set; }
     public string OriginalKey { get; set; }
     public string Value { get; set; }
 }

Dive in the reflection

Now that we have all the basic object, let’s talk about the Reflection. I will not repeat what you can find on the MSDN, but rather show you directly a possible usage. The Reflection, as the name indicate, can go and read through the assembly and see how the objects are made and give you useful information. Recently, I used it in order to take a JSON configuration (appsettings section) and then generate code to be executed in the background based on that. I will not explain further that application.

Let’s begin, we will be taking our “Attribute” from the enum value and use the value provided. Then from that, instead of simply returning a simple string, let’s return a new Object. In this implementation, I will be using an extension method for simplicity. The same could be done using a simple method.

public static class CustomAttributeExtension
{
    internal static MySpecialItem GenerateEvent(this MyDictionarySpecialKeys myKey, decimal val)
    {
        // Get the member from the Enum
        var memberInfo = typeof(MyDictionarySpecialKeys)
            .GetMember(myKey.ToString())
            .FirstOrDefault();

        // If the enum member exists, then let's get the attribute
        if (memberInfo != null)
        {
            var attr = (CustomAttribute)memberInfo
                    .GetCustomAttributes(typeof(CustomAttribute), false)
                    .FirstOrDefault();

            if (attr == null)
            {
                // Should skip, if not exists
                return null;
            }

            // If enum contains the attribute let's create an object
            return new MySpecialItem
            {
                Special = attr.CustomValue,
                OriginalKey = myKey.ToString(),
                Value = val.ToString(CultureInfo.InvariantCulture)
            };
        }

        // Should skip
        return null;
    }
}

Let’s put all together in a program

If we take all of what we’ve done so far and put this into a program. We will have a JSON having 3 items in a dictionary. However, that dictionary will have only two entries mapped on the strongly typed enum. From that enum, the two enum members will be decorated with a custom attribute giving a special extra meaning to the value.

That put into code will give you something like this:

public class Program
{
    public static void Main()
    {
        var jsonInputSample = "{ \"MyDictionary\": { \"Key1\": 1, \"Key2\": 2, \"Key3\": 3.1416 } }";
        Console.WriteLine($"Input: {jsonInputSample}");

        var deserializedObject = JsonConvert.DeserializeObject<SampleObject>(jsonInputSample);
        var generatedSpecialItems = new List<MySpecialItem>();

        Console.WriteLine();
        Console.WriteLine("Content of [MyDictionary]:");

        foreach (var dictionaryItem in deserializedObject.MyDictionary)
        {
            Console.WriteLine($"\tDictionary [Key: {dictionaryItem.Key}] [Value: {dictionaryItem.Value}]");
            if (Enum.TryParse(dictionaryItem.Key, true, out MyDictionarySpecialKeys specialKey)
                && Enum.IsDefined(typeof(MyDictionarySpecialKeys), specialKey))
            {
                var specialItem = specialKey.GenerateEvent(dictionaryItem.Value);

                if (specialItem != null)
                {
                    generatedSpecialItems.Add(specialItem);
                }
            }
        }

        Console.WriteLine();
        Console.WriteLine("Result (Could be special items to be inserted in a DB):");
        Console.WriteLine("-----------------------------------------");
        Console.WriteLine(JsonConvert.SerializeObject(generatedSpecialItems, Formatting.Indented));
        Console.WriteLine("-----------------------------------------");
        Console.WriteLine("Completed");
        // Console.ReadKey(); // If you wish to wait when you run from Visual Studio and not command line.
    }
}

And the output result will be:

Input: { "MyDictionary": { "Key1": 1, "Key2": 2, "Key3": 3.1416 } }

Content of [MyDictionary]:
        Dictionary [Key: Key1] [Value: 1]
        Dictionary [Key: Key2] [Value: 2]
        Dictionary [Key: Key3] [Value: 3.1416]

Result (Events to be created):
-----------------------------------------
[
  {
    "Special": "Simple Value",
    "OriginalKey": "Key1",
    "Value": "1"
  },
  {
    "Special": "Another Simple Value",
    "OriginalKey": "Key3",
    "Value": "3.1416"
  }
]
-----------------------------------------
Completed
]]>
https://blog.honosoft.com/2019/03/06/dotnet-and-reflection-exploration/feed/ 0
Why would you do rapid prototyping with SQLite? https://blog.honosoft.com/2019/03/05/why-would-you-do-rapid-prototyping-with-sqlite/?utm_source=rss&utm_medium=rss&utm_campaign=why-would-you-do-rapid-prototyping-with-sqlite https://blog.honosoft.com/2019/03/05/why-would-you-do-rapid-prototyping-with-sqlite/#respond Tue, 05 Mar 2019 12:25:20 +0000 https://blog.honosoft.com/?p=440 Continue Reading]]> As someone who likes to do some hack and automate pretty much my daily routine, recently I changed a bit how I was making those prototype by using a super light no-dependent DB. I use it for caching my data and avoid hitting the official servers too often and give a better performance overall (UX).

In the past, I used a lot NodeJs, but found out that some things were missing in order to be really effective. Especially when you have to touch the Rest API’s (Express or alike), it’s becoming almost a hell for managing data contract, generating the Swagger API and etc. For most of my scenarios where I want something that can scaffold and be ready in one hour, I now tend to use more Dotnet Core. Since it now runs pretty much everywhere and that we can scaffold super quickly API’s and UI (creating some templates).

In fact, in order to become more efficient, I started to build a template project available on GitHub and also NuGet. It’s also the template I most likely use for the articles on this site. For information, the template project use Dotnet Core 2+ (2.2 as o now) and contains 2 projects template. One that is the most basic web application you could have with VueJS and the other one which contains all the ready to start pretty much anything (Swagger, VueJS, VeeValidate, etc.).

Why VueJS and not Angular or any others? That’s a legitimate question. I personally like to use VueJS for it’s simplicity, it’s easy to debug and to finish, it’s really easy to use (great documentation). Then added to that, I use instead of the mastodon of Bootstrap the super lightweight Picnic CSS. It contains all the thing I usually require (grid alike feature, buttons, tabs, etc.). Yes, NodeJS is not gone, it’s still part of the deal. I use WebPack (hot reloading) in order to have a nice lightweight front-end deployed in “production” cases. The hot-reload become really handy when you want to see your changes live.

To debug your API’s using REST calls become easy and you know how the pipeline goes and security is also part of the deal with Kestrel (Http/s).

Regarding the API’s call from the front-end, my personal choice is Axios since it’s also easy and in case I would build UT, the library is simple to mock.

Why Dotnet Core 2.2 (or higher)?

Dotnet Core is using the power of the C# and all the business logic. In case I have to use a database, instead of connecting to a big database, I will simply use EntityFramework Core code first approach with SQLite. Also, Dotnet Core create a simple way to have a well defined swagger API, creates API’s through controllers and also give possibilities to easily integrate with existing Authentication mechanisms. The syntax and data contracts are part of the language and for anyone will understand them. The serialization is usually using the camelCase, but in case you need something different, you simply have to change the data contract factory (Newtonsoft.Json library) to suits your needs.

SQLite?

I used to use SQL Express, PostgreSQL, etc. However, to be doing rapid prototyping without installing any DBMS, SQLite give you the power of a database in a single small file (Don’t forget to VACUUM ;)). I use the latest version where you have foreign keys and cascade delete availability. The only drawback when using SQLite is to access the data with a visualization tool. I recently found one tool which was worth using. It’s not so big to install and you can drag and drop your database in the tool for lazy people ;). The tool in question is SQLite Studio.

When doing prototyping, you want to take a minimum of time to setup an environment, and if you have to deploy let’s say on a Raspberry PI or docker. You might not want to have to install anything else than your application (self-contained). SQLite files are created wherever your project wants it to be. That way, you simply deploy your application. At the startup of the application, the migrations happens and everything is ready. In worst case, or best case, you simply download or upload the database from/to your PC.

]]>
https://blog.honosoft.com/2019/03/05/why-would-you-do-rapid-prototyping-with-sqlite/feed/ 0