why I can't call the MK class from my main ?

Hello ,
I’m trying to build a simple windows foarm in C#
enter IP - press enter button - show my the uptime \ ROS of the unit

the enter IP and user\password is working
I can see I enter the router only after I press the button

but when I want to read information from it - “uptime”
I get error :
Severity Code Description Project File Line Suppression State
Error CS0103 The name ‘mikrotik’ does not exist in the current context WindowsFormsApplication1 C:\Users\Computer\Documents\Visual Studio 2015\Projects\WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs 125 Active


this is what I have :

using System;
using System.Windows.Forms;


using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net.Sockets;
using System.Net;
using System.Net.NetworkInformation;



namespace WindowsFormsApplication1
{

    
    public partial class Form1 : Form
    {
        string IP;
       
        string password;

        public Form1()
        {
            InitializeComponent();
        }

           private void textBox1_TextChanged(object sender, EventArgs e)
        {
            IP = textBox1.Text;
                                    
        }

        public void button1_Click(object sender, EventArgs e)
        {

            button1.Text = "Click Here"; //change the button name after press

            textBox2.Text = ("you have enter the router");
            //textBox2.Text = ("this is what you have press " + IP +password ); //display saved value in another textbox
            MK mikrotik = new MK(IP);
            if (!mikrotik.Login("admin", password))
            {
                textBox2.Text = ("Could not log in - Wrong Password");
                mikrotik.Close();
                return;
            }


        
     
       private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            password = "123456";
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            password = "MyPassword";
        }

       
      
        public void textBox3_TextChanged(object sender, EventArgs e)
        {
            mikrotik.Send("/system/resource/print");
            mikrotik.Send("=.proplist=version,uptime", true);
    
        }
    }


    class MK
    {
        Stream connection;
        TcpClient con;

        public MK(string ip)
        {
            con = new TcpClient();
            con.Connect(ip, 8728);
            connection = (Stream)con.GetStream();
        }
        public void Close()
        {
            connection.Close();
            con.Close();
        }
        public bool Login(string username, string password)
        {
            Send("/login", true);
            string hash = Read()[0].Split(new string[] { "ret=" }, StringSplitOptions.None)[1];
            Send("/login");
            Send("=name=" + username);
            Send("=response=00" + EncodePassword(password, hash), true);
            if (Read()[0] == "!done")
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        public void Send(string co)
        {
            byte[] bajty = Encoding.ASCII.GetBytes(co.ToCharArray());
            byte[] velikost = EncodeLength(bajty.Length);

            connection.Write(velikost, 0, velikost.Length);
            connection.Write(bajty, 0, bajty.Length);
        }
        public void Send(string co, bool endsentence)
        {
            byte[] bajty = Encoding.ASCII.GetBytes(co.ToCharArray());
            byte[] velikost = EncodeLength(bajty.Length);
            connection.Write(velikost, 0, velikost.Length);
            connection.Write(bajty, 0, bajty.Length);
            connection.WriteByte(0);
        }
        public List<string> Read()
        {
            List<string> output = new List<string>();
            string o = "";
            byte[] tmp = new byte[4];
            long count;
            while (true)
            {
                tmp[3] = (byte)connection.ReadByte();
                //if(tmp[3] == 220) tmp[3] = (byte)connection.ReadByte(); it sometimes happend to me that 
                //mikrotik send 220 as some kind of "bonus" between words, this fixed things, not sure about it though
                if (tmp[3] == 0)
                {
                    output.Add(o);
                    if (o.Substring(0, 5) == "!done")
                    {
                        break;
                    }
                    else
                    {
                        o = "";
                        continue;
                    }
                }
                else
                {
                    if (tmp[3] < 0x80)
                    {
                        count = tmp[3];
                    }
                    else
                    {
                        if (tmp[3] < 0xC0)
                        {
                            int tmpi = BitConverter.ToInt32(new byte[] { (byte)connection.ReadByte(), tmp[3], 0, 0 }, 0);
                            count = tmpi ^ 0x8000;
                        }
                        else
                        {
                            if (tmp[3] < 0xE0)
                            {
                                tmp[2] = (byte)connection.ReadByte();
                                int tmpi = BitConverter.ToInt32(new byte[] { (byte)connection.ReadByte(), tmp[2], tmp[3], 0 }, 0);
                                count = tmpi ^ 0xC00000;
                            }
                            else
                            {
                                if (tmp[3] < 0xF0)
                                {
                                    tmp[2] = (byte)connection.ReadByte();
                                    tmp[1] = (byte)connection.ReadByte();
                                    int tmpi = BitConverter.ToInt32(new byte[] { (byte)connection.ReadByte(), tmp[1], tmp[2], tmp[3] }, 0);
                                    count = tmpi ^ 0xE0000000;
                                }
                                else
                                {
                                    if (tmp[3] == 0xF0)
                                    {
                                        tmp[3] = (byte)connection.ReadByte();
                                        tmp[2] = (byte)connection.ReadByte();
                                        tmp[1] = (byte)connection.ReadByte();
                                        tmp[0] = (byte)connection.ReadByte();
                                        count = BitConverter.ToInt32(tmp, 0);
                                    }
                                    else
                                    {
                                        //Error in packet reception, unknown length
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                for (int i = 0; i < count; i++)
                {
                    o += (Char)connection.ReadByte();
                }
            }
            return output;
        }
        byte[] EncodeLength(int delka)
        {
            if (delka < 0x80)
            {
                byte[] tmp = BitConverter.GetBytes(delka);
                return new byte[1] { tmp[0] };
            }
            if (delka < 0x4000)
            {
                byte[] tmp = BitConverter.GetBytes(delka | 0x8000);
                return new byte[2] { tmp[1], tmp[0] };
            }
            if (delka < 0x200000)
            {
                byte[] tmp = BitConverter.GetBytes(delka | 0xC00000);
                return new byte[3] { tmp[2], tmp[1], tmp[0] };
            }
            if (delka < 0x10000000)
            {
                byte[] tmp = BitConverter.GetBytes(delka | 0xE0000000);
                return new byte[4] { tmp[3], tmp[2], tmp[1], tmp[0] };
            }
            else
            {
                byte[] tmp = BitConverter.GetBytes(delka);
                return new byte[5] { 0xF0, tmp[3], tmp[2], tmp[1], tmp[0] };
            }
        }

        public string EncodePassword(string Password, string hash)
        {
            byte[] hash_byte = new byte[hash.Length / 2];
            for (int i = 0; i <= hash.Length - 2; i += 2)
            {
                hash_byte[i / 2] = Byte.Parse(hash.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
            }
            byte[] heslo = new byte[1 + Password.Length + hash_byte.Length];
            heslo[0] = 0;
            Encoding.ASCII.GetBytes(Password.ToCharArray()).CopyTo(heslo, 1);
            hash_byte.CopyTo(heslo, 1 + Password.Length);

            Byte[] hotovo;
            System.Security.Cryptography.MD5 md5;

            md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();

            hotovo = md5.ComputeHash(heslo);

            //Convert encoded bytes back to a 'readable' string
            string navrat = "";
            foreach (byte h in hotovo)
            {
                navrat += h.ToString("x2");
            }
            return navrat;
        }
    }
}

I guess it’s something easy and stupid

Thanks,

The line

MK mikrotik = new MK(IP);

is where the connection and the variable holding it are created. The connection lasts as long as the object lasts.

Because that line is within the button click event, what this means is that your connection starts and ends within the button click. The “mikrotik” variable doesn’t exist outside of that event in any capacity, so when you later have

public void textBox3_TextChanged(object sender, EventArgs e)
        {
            mikrotik.Send("/system/resource/print");
            mikrotik.Send("=.proplist=version,uptime", true);
    
        }

that’s a non existent variable.

You need to create the variable at a place where it would be accessible to everyone who needs it, and reuse that particular variable when you’re about to connect for real, e.g.

        string password;

        MK mikrotik;
        
        public Form1()
        
        ....
        
        public void button1_Click(object sender, EventArgs e)
        {

            button1.Text = "Click Here"; //change the button name after press

            textBox2.Text = ("you have enter the router");
            //textBox2.Text = ("this is what you have press " + IP +password ); //display saved value in another textbox
            mikrotik = new MK(IP);

BTW, didn’t we already talked about your choice of a C# API client?

Ok - it’s working
so I need to write a sub program for each command i wnat to use and then put it the “enter” button" , right?

so 1 mre simple question
how do I create a subcode in C#?
somethinf like this?


public void button1_Click(object sender, EventArgs e)
{
ID = GetID();

}
public GetID (string)
{
mikrotik.Send(“/system/identity/print”);
mikrotik.Send(“=.proplist=name”, true);
foreach (string h in mikrotik.Read())
{
if (h == “!done”)
break;
else
identity = (h.Substring(9));
}

}

about the C# - I don;t think we talk about it -
I have start working with it beacuse of a example I found Online - and lean it as I write more
as this poit all my code is in C# and woring - so I don;t want to start a new onw

but for the next project I can start a new lang - what would you recommand?


Thanks,

I mean that instead of using that particular C# client, using this API client would be much better in the long run.

With it, you can easily form arbitrary requests, and retrieve all individual pieces of information related to the reply. Granted your current problem would also happen there, because having or not having a variable in scope is just a C# thing, not an API client thing.

For a moment there I thought I might’ve mistook you for someone else, but no… Here’s the topic in question that was on my mind.

Ohh - I understand
so yes we have talk about it :slight_smile:

but I found that that C# code is much more easy for me to understand the C# and what I’m getting (for me)
also , I’m doing only read data so it good for me.


and about my question -
how do I create a sub code in the code ? I get error again
this is what I have done

private void textBox2_TextChanged(object sender, EventArgs e)
        {
            
          string test = RouterID();
        }


 public string RouterID()
        {
            mikrotik.Send("/system/identity/print");
            mikrotik.Send("=.proplist=name", true);
            foreach (string h in mikrotik.Read())
            {
                if (h == "!done")
                    break;
                else
                    identity = (h.Substring(9));
            }
            return identity;
        }

See my last example code.

You need to define the variable as a Form1 property (as the code shows). That way, it would be accessible to all methods of the class.

The way I’ve made it there, if the text in textBox3 changes before you’ve clicked button1, the app will crash, but it should compile either way. There are several ways to prevent the crash (with my personal preference being to disable the control - in this case the text box - until interacting with it would not cause a crash), but one problem at a time - compiling it is a must.

sorry my mistake

it sould be like this :

 public partial class Form1 : Form
    {

        MK mikrotik;

        string IP;
       
        string password;

        string identity;
        string ROS;
        string uptime;

        public Form1()
        {
            InitializeComponent();
        }
        
        
  public void button1_Click(object sender, EventArgs e)
        {

            button1.Text = "Click Here"; //change the button name after press

            textBox2.Text = ("you have enter the router");
            //textBox2.Text = ("this is what you have press " + IP +password ); //display saved value in another textbox
            MK mikrotik = new MK(IP);
            if (!mikrotik.Login("admin", password))
            {
                textBox2.Text = ("Could not log in - Wrong Password");
                mikrotik.Close();
                return;
            }     
            
            string ID = RouterID(); 
        }
        
         public string RouterID()
        {
            mikrotik.Send("/system/identity/print");
            mikrotik.Send("=.proplist=name", true);
            foreach (string h in mikrotik.Read())
            {
                if (h == "!done")
                    break;
                else
                    identity = (h.Substring(9));
            }
            return identity;
        }
        
        
 }

The line

MK mikrotik = new MK(IP);

is still creating a new local variable (within the method), meaning that you’re not using the property.

To reference the class property, omit the type specifier, i.e.

mikrotik = new MK(IP);

Although then again… The app should compile since the property is there, but merely crash because the property is not initialized.

yes ! now it’s start to work as I want
Thanks ,

2 more small questions :

  1. how do I do a “quit” button?
    not like this?
private void button2_Click(object sender, EventArgs e)
        {
            Exit();
        }
  1. after I enter the device how can I make it run once every 5 sec ? to make a loop but just for what happand after the “enter”?
    I want my Application to be a monitor to the device until the user close it

Thanks ,

In general, it’s best to call a single command that continuously returns data. Said commands can be configured to only return on intervals or in the case of “print” with a “follow” argument, they would only return when there’s new stuff to be seen. With that in place, your app can react to incoming messages accordingly when they come, and continue to execute other things in the meantime, including accepting user input for example. The ability to set something for later is commonly known as “asynchronous” execution.

You can’t do that with your API client, but with danikf’s one, there’s support for asynchronous commands.

OK - I will start reading

and what about quit button?
how can i create a button that close me the APP ?
I ahve serch and saw all i need to do is

private void button2_Click(object sender, EventArgs e)
        {
           Exit();
        }

but it doesn’t work

what am I missing?

Thanks ,

Never mind foud it

private void button2_Click(object sender, EventArgs e)
        {
            this.Close();
        }