(CORE) CORE (2019)

Informer - site colaboration with JS and simple NET Core ApiController.

1. What is informer.

This is very simple idea to show in one site some data from other site. In this page I want to show how to do this in example with one of my oldest customer votpusk.ru. This project has two types of informers - weather and news.

As you can see, informer looks as JS packed to ASP-file, this idea generate error because IIS write JS file with wrong type, but any browser handle this issue correctly.


   1:  <script language="javascript" src="https://www.votpusk.ru/informer/news.asp?cn=X
   2:  &tm=X
   3:  &pc=5
   4:  &w=200
   5:  &wt=1
   6:  &csp=1
   7:  &cpd=4
   8:  &bg=000000
   9:  &bg1=E7E3E7
  10:  &bg2=FFFFFF
  11:  &ffc=0
  12:  &fcl=000000
  13:  &fcl1=000000
  14:  &fsz=2
  15:  &fsz1=3
  16:  &fsz2=3"></script>

This is very old my site written about 2002 year, so it was use simple ASP technology and page news.asp looks as:



As you can see this page pack some data from database and write it as JS to site-customer. For example, look to this page:



Collaboration script look as:


   1:   
   2:   
   3:  var xmlhttp = new XMLHttpRequest();
   4:  xmlhttp.open("GET", "https://informer.votpusk.ru/domain");
   5:  xmlhttp.setRequestHeader("Authorization", window.location.hostname);
   6:  xmlhttp.send();
   7:   
   8:  document.write("<font face=Arial><table width=189 cellspacing=1 bgcolor=#000000><tr><td align='center' bgcolor=#FFFFFF><table width=100%><tr><td height=20 align='center'><font size='1' color=#000000><b>НОВОСТИ ТУРИЗМА</b></font></td></tr></table><table width=95% cellspacing=0 cellpadding=2>")
   9:   
  10:  document.write("<tr><td align=center bgcolor=#E7E3E7><font size='1' color=#000000>09.11.2021</font></td></tr><tr><td valign=top bgcolor=#FFFFFF>")
  11:   
  12:  document.write("<a target='_blank' href='http://www.votpusk.ru/news.asp?msg=575748'><font size='1' color=#000000 style='font-weight:normal;'>В Индонезии планируют изменить правила въезда в страну<br><br></font></a>")
  13:   
  14:  document.write("<tr><td align=center bgcolor=#E7E3E7><font size='1' color=#000000>14.10.2021</font></td></tr><tr><td valign=top bgcolor=#FFFFFF>")
  15:   
  16:  document.write("<a target='_blank' href='http://www.votpusk.ru/news.asp?msg=575635'><font size='1' color=#000000 style='font-weight:normal;'>На остров Бали разрешили въезжать туристам из пяти стран<br><br></font></a>")
  17:   
  18:  document.write("<tr><td align=center bgcolor=#E7E3E7><font size='1' color=#000000>12.10.2021</font></td></tr><tr><td valign=top bgcolor=#FFFFFF>")
  19:   
  20:  document.write("<a target='_blank' href='http://www.votpusk.ru/news.asp?msg=575626'><font size='1' color=#000000 style='font-weight:normal;'>Индонезия сокращает период обязательного карантина по прибытии<br><br></font></a>")
  21:   
  22:  document.write("</td></tr><tr><td align=right bgcolor=#E7E3E7><a href='http://www.votpusk.ru' target='_blank'><font size='2' color=#000000>в Отпуск.ру</font></a></td></tr></table><br></td></tr></table></font>")

As you can see, this script working with dedicated domain informer.votpusk.ru what realizing on Linux NET CORE ApiController.

So below we can see full steps to up Linux NET CORE ApiController handles this request from other sites.

2. Set Up Linux machine.

In this case I use Ubuntu 20.04, than I have upgrade it to 21.01.

I will install this Ubuntu behind firewall into DMZ with IP addr 192.168.4.15 with gateway 192.168.4.1



But firstly need to select right Ubuntu distribution.



There are one potential difficulties to configure Ubuntu in this network configuration, (1) no need proxy, because firewall is full transparent, need only set a correct gateway, (2) configure bridge, (3) select right bond mode.



So, this is our finally result of network configuring of our new VM.


# cat /etc/netplan/00-installer-config.yaml 

network:
  bonds:
    bond0:
      addresses:
      - 192.168.4.15/24
      gateway4: 192.168.4.1
      interfaces:
      - ens32
      nameservers:
        addresses:
        - 8.8.8.8
        - 8.8.4.4
        search: []
      parameters:
        mode: balance-rr
  ethernets:
    ens32: {}
  version: 2

Next step is first install and setup firewall and nginx.



# sudo ufw allow 33306
# sudo ufw enable
# sudo ufw app list
# sudo ufw port list
# sudo  ufw status

3. Set Up and tune MySQL.

I have a lot of version of steps to correct install MySQL, last is Setup MariaDB on Ubuntu server (remote access, user privileges, upload database), so in this server : MySQL user has been installed, Database has been created, User access has been provided, external access has been provided, firewall port for external access has been opened.


# sudo ./mariadb_repo_setup
# https://mariadb.com/kb/en/mariadb/mariadb-package-repository-setup-and-usage/#platform-supporthttps://mariadb.com/kb/en/mariadb/mariadb-package-repository-setup-and-usage/#platform-support
# sudo apt-get install mariadb-server mariadb-client mariadb-backup
# sudo apt update
# sudo apt upgrade
# sudo mysql_secure_installation
# sudo systemctl start mariadb
# sudo systemctl enable mariadb
# sudo systemctl status mariadb
# mysqld --help --verbose
# sudo mariadb

4. Develop NET CORE ApiController

In this case code is extremally simple. I use only 3 packages and even store connection string in code. How to store connection string more carefully please read for example in this link https://stackoverflow.com/questions/70010727/access-to-appsettings-json-in-asp-net-core-5-0-linux. Of course, header name can be any, I have selected "Authorization" only for fun.



   1:  using Microsoft.AspNetCore.Http;
   2:  using Microsoft.AspNetCore.Mvc;
   3:  using Microsoft.Extensions.Configuration;
   4:  using MySqlConnector;
   5:  using System;
   6:  using System.Collections.Generic;
   7:  using System.Configuration;
   8:  using System.Linq;
   9:  using System.Threading.Tasks;
  10:   
  11:  namespace Informer
  12:  {
  13:      [ApiController]
  14:      [Route("[controller]")]
  15:      public class DomainController : ControllerBase
  16:      {
  17:          private readonly MySqlConnection CN;
  18:          private readonly IConfiguration _config;
  19:          public DomainController(IConfiguration config)
  20:          {
  21:              _config = config;
  22:              CN = new MySqlConnection(_config.GetValue<string>("ConnectionString"));
  23:          }
  24:          [HttpGet]
  25:          public string Index()
  26:          {
  27:              try
  28:              {
  29:                  CN.Open();
  30:              }
  31:              catch (Exception x)
  32:              {
  33:                  throw new Exception(x + "\n" + CN.ConnectionString);
  34:              }
  35:   
  36:              if (CN.State == System.Data.ConnectionState.Open)
  37:              {
  38:                  if (Request.Headers["Authorization"].Count > 0)
  39:                  {
  40:                      string DM = Request.Headers["Authorization"];
  41:                      MySqlCommand CMD = new MySqlCommand($"INSERT INTO `informers`.`domain` (`crdate`,`name`) SELECT now(),'{DM}' WHERE NOT EXISTS (SELECT '1' FROM `informers`.`domain` WHERE `name`= '{DM}' )", CN);
  42:                      CMD.ExecuteNonQuery();
  43:                      CN.Close();
  44:                      return "";
  45:                  }
  46:                  else
  47:                  {
  48:                      List<string> str1 = new List<string>();
  49:                      MySqlCommand CMD1 = new MySqlCommand("SELECT * FROM informers.domain;",CN);
  50:                      MySqlDataReader DR = CMD1.ExecuteReader();
  51:                      while (DR.Read())
  52:                      {
  53:                          str1.Add(DR["name"].ToString());
  54:                      }
  55:                      return string.Join(",", str1);
  56:                  }
  57:              }
  58:              else return "";
  59:          }
  60:      }
  61:  }

5. Setup NET CORE and deploy linux-X64 assembly to server.


# wget https://packages.microsoft.com/config/ubuntu/21.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
# sudo dpkg -i packages-microsoft-prod.deb
# rm packages-microsoft-prod.deb
# sudo apt-get update;   sudo apt-get install -y apt-transport-https &&   sudo apt-get update &&   sudo apt-get install -y aspnetcore-runtime-5.0

6. First start (directly in command line) and check response from ApiController.


# sudo mkdir /srv/informer
# chown proxyadmin /srv/informer
# sudo chown proxyadmin /srv/informer
# /usr/bin/dotnet /srv/informer/Informer.dll
# curl -v localhost:5000/domain


Unfortunately, first start this application has been unsuccessful despite correct working in developer computer, so best way to understand issue is install Remote debugger.

7. Install remote debugger.


Unfortunately, I have no time for this project to correct fix issue with config, customer want to see finally result immediately, so my solution for 5 second was simple store connection string to controller constructor.



8. Tune NGINX as reverse proxy and setup SSL.


# sudo nano /etc/nginx/nginx.conf
# sudo service nginx restart
# journalctl -xe
# ps -aux
# kill -9 289321


   1:  user www-data;
   2:  worker_processes auto;
   3:  pid /run/nginx.pid;
   4:  include /etc/nginx/modules-enabled/*.conf;
   5:   
   6:  events {
   7:      worker_connections 768;
   8:      # multi_accept on;
   9:  }
  10:   
  11:  http {
  12:   
  13:      ##
  14:      # Basic Settings
  15:      ##
  16:   
  17:      sendfile on;
  18:      tcp_nopush on;
  19:      types_hash_max_size 2048;
  20:      # server_tokens off;
  21:   
  22:      # server_names_hash_bucket_size 64;
  23:      # server_name_in_redirect off;
  24:   
  25:      include /etc/nginx/mime.types;
  26:      default_type application/octet-stream;
  27:   
  28:      ##
  29:      # SSL Settings
  30:      ##
  31:   
  32:      ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
  33:      ssl_prefer_server_ciphers on;
  34:   
  35:      ##
  36:      # Logging Settings
  37:      ##
  38:   
  39:      access_log /var/log/nginx/access.log;
  40:      error_log /var/log/nginx/error.log;
  41:   
  42:      ##
  43:      # Gzip Settings
  44:      ##
  45:   
  46:      gzip on;
  47:   
  48:      # gzip_vary on;
  49:      # gzip_proxied any;
  50:      # gzip_comp_level 6;
  51:      # gzip_buffers 16 8k;
  52:      # gzip_http_version 1.1;
  53:      # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
  54:   
  55:      ##
  56:      # Virtual Host Configs
  57:      ##
  58:   
  59:      include /etc/nginx/conf.d/*.conf;
  60:      include /etc/nginx/sites-enabled/*;
  61:   
  62:   
  63:   
  64:  #mail {
  65:  #    # See sample authentication script at:
  66:  #    # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
  67:  #
  68:  #    # auth_http localhost/auth.php;
  69:  #    # pop3_capabilities "TOP" "USER";
  70:  #    # imap_capabilities "IMAP4rev1" "UIDPLUS";
  71:  #
  72:  #    server {
  73:  #        listen     localhost:110;
  74:  #        protocol   pop3;
  75:  #        proxy      on;
  76:  #    }
  77:  #
  78:  #    server {
  79:  #        listen     localhost:143;
  80:  #        protocol   imap;
  81:  #        proxy      on;
  82:  #    }
  83:  #}
  84:   
  85:         server {
  86:                listen 80;
  87:                listen 443 ssl;
  88:                server_name informer.votpusk.ru;
  89:                ssl_certificate /srv/cert/cert2019.crt;
  90:                ssl_certificate_key  /srv/cert/votpusk2019.key;
  91:   
  92:   
  93:              location / {
  94:                         #root   /srv/ftp;
  95:                         #index  index.html index.htm;
  96:                         proxy_pass         http://localhost:5000;
  97:                         proxy_http_version 1.1;
  98:                         proxy_set_header   Upgrade $http_upgrade;
  99:                         proxy_set_header   Connection keep-alive;
 100:                         proxy_set_header   Host $host;
 101:                         proxy_cache_bypass $http_upgrade;
 102:                         proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
 103:                         proxy_set_header   X-Forwarded-Proto $scheme;
 104:                              if ($request_method = 'GET') {
 105:                                  add_header 'Access-Control-Allow-Origin' '*';
 106:                                  add_header 'Access-Control-Allow-Credentials' 'true';
 107:                                  add_header 'Access-Control-Allow-Methods' 'GET';
 108:                                  add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
 109:                                 }
 110:                         }
 111:              }
 112:  }
 113:   

9. Setup CORS policy.


10. Demonize kestrel as Linux service.

# sudo nano /etc/systemd/system/kestrel-1.service
# systemctl enable kestrel-1.service
# sudo systemctl enable kestrel-1.service
# sudo systemctl start kestrel-1.service
# systemctl --full --type service --all


   1:  [Unit]
   2:  Description=kestrel apps daemon
   3:   
   4:  [Service]
   5:  WorkingDirectory=/srv/informer/
   6:  ExecStart=/usr/bin/dotnet /srv/informer/Informer.dll
   7:  Restart=always
   8:  RestartSec=10 
   9:  SyslogIdentifier=Informer
  10:  User=root 
  11:  Environment=ASPNETCORE_ENVIRONMENT=Development
  12:   
  13:  [Install]
  14:  WantedBy=multi-user.target 

11. Check finally result about informer client.

Finally result looks terrible, so many hard step need to receive one ugly string. But this is correct result of this program.




Comments ( )
Link to this page: http://www.vb-net.com/Informer/Index.htm
< THANKS ME>