📜 ⬆️ ⬇️

Client-server work with tabular data for beginners

Instead of a start.

Recently I had to start writing an application for work. Previously, I worked exclusively with PHP and web snouts, but there was a requirement to make a full-fledged windows-application with authorization, using forms and other parsley. I am writing this article on an abstract abstract example with the goal of making mana accessible and simple. Actually, the course of action itself is important here, rather than the application itself.

The task was to work with the tabular data received from the server without a web interface. Available tools: Apache + PHP + MySQL web server and C # application on the client side.

Professionals are unlikely to be interesting. But for beginners, it seems to me, it can be useful. I really hope that I did not overthink the embodiment of the idea.
Who is interested in the implementation of the bundle - please under the cat.

To begin, I will describe the part of the code that provides data exchange with the server, as well as work with strings in the messages sent and received.
I have implemented this in ready-made classes, but here I will give only the necessary methods, and not the entire listings of all classes.
')
The client, I remind you, is written in C #. From WPF it was necessary to refuse, since in our office more than the standard version with Windows Forms. The server part was created in PHP, because it simply turned out to be faster than writing a full-fledged CGI client for Mono Complete, although in the future we plan to abandon the fucking PHP in favor of a demon written in C #.

I want to say that this is my first experience with VisualStudio (using VS2013 with ReSharper) and C #. Therefore, if somewhere it was possible to make it more convenient, do not judge strictly - I’m happy to read the comments and take it into account in further developments.
Data encryption

Based on the Base-64 format because of its versatility on various platforms.
//    Base64  public static string Base64Encode(string inputString) { return Convert.ToBase64String(Encoding.UTF8.GetBytes(inputString)); } 

 //    Base64  public static string Base64Decode(string inputString) { return Encoding.UTF8.GetString(Convert.FromBase64String(inputString)); } 

Request to server

For work you will need the library " Newtonsoft.Json ". Add it to the project References, otherwise it will not work. Just want to note that the server is running Debian Squeeze and UTF-8 encoding is used everywhere. Therefore, the code provides strings for compatibility. Nobody wants a grunt. I don’t see any point in commenting on such a code as it’s obvious.

 public static Dictionary<string, string> Response(string handlerString, string inputString = "") { try { //    var requestString = (inputString.Length > 0) ? "handler=" + handlerString + "&args=" + Base64Encode(inputString) : "handler=" + handlerString; //       HttpWebRequest. ,      -  ,       . // *   Properties.Settings.Default    ,        ,   , IMHO.         ,        . // Properties.Settings.Default.handlerUri = (string) "http://__/handler.php" var request = (HttpWebRequest) WebRequest.Create(Properties.Settings.Default.handlerUri); // Properties.Settings.Default.httpMethod = (string) "POST" request.Method = Properties.Settings.Default.httpMethod; request.Credentials = CredentialCache.DefaultCredentials; var encoding = new UTF8Encoding(); var bytes = encoding.GetBytes(requestString); // Properties.Settings.Default.httpContentType = (string) "application/x-www-form-urlencoded" request.ContentType = Properties.Settings.Default.httpContentType; request.ContentLength = bytes.Length; using (var newStream = request.GetRequestStream()) { newStream.Write(bytes, 0, bytes.Length); newStream.Close(); } var response = (HttpWebResponse) request.GetResponse(); var streamReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8); var responseString = streamReader.ReadToEnd().Trim(); //    JSON-,     Base-64   . ...     ,       .Trim('"').   ,    . return JsonConvert.DeserializeObject<Dictionary<string, string>>( Base64Decode(responseString.Trim('"'))); } catch (Exception exception) { //     ,     -   . // Properties.Settings.Default.errorMessageServerHandlerBug = (string) ",      .        .". // Properties.Settings.Default.msgboxCaptionError = (string) "". MessageBox.Show( Properties.Settings.Default.errorMessageServerHandlerBug + Convert.ToChar("\n") + exception.Message, Properties.Settings.Default.msgboxCaptionError, MessageBoxButtons.OK, MessageBoxIcon.Error); //       ,     -     , ..        . Application.Exit(); //    , VS    return',    .  , ,        :) return JsonConvert.DeserializeObject<Dictionary<string, string>>("{\"type\":\"error\",\"data\":\"-1\"}"); } } 


We now turn to the main topic of the article.
Let's look at the example of a useless contact table.

Let the fields (column headings) of the table be as follows:



To begin, I will describe the part in PHP (server side).

 define("DB_HOST", "localhost"); define("DB_USER", "__"); define("DB_PASS", "__"); define("DB_NAME", "___"); define("DB_CHARSET", "utf8"); define("ANSWER_SUCCESS", "success"); define("ANSWER_ERROR", "error"); function make_answer($type, $data) { print base64_encode(json_encode([ "type" => $type, "data" => $data ])); exit();//       . } $db = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASS); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db->exec("SET NAMES '".DB_CHARSET."'"); $query = $db->query("SELECT `Id`,`Title`,`PhoneNumber`,`Email`,`Messengers` FROM `contacts` WHERE 1"); $query->execute(); $query->setFetchMode(PDO::FETCH_ASSOC); $result = []; while ($current = $query->fetch()) { $result[] = [ "Id" => base64_encode($current["Id"]), "Title" => base64_encode($current["Title"]), "PhoneNumber" => base64_encode($current["PhoneNumber"]), "Email" => base64_encode($current["Email"]), "Messengers" => base64_encode($current["Messengers"]) ]; } if (count($result) > 0) { make_answer(ANSWER_SUCCESS, $result); } make_answer(ANSWER_ERROR, "  "); 


In outline. Here we connect to the database, get the necessary data (PDO is used) and form the answer in the form of an array. If there are no records, we return an error message.

The data array has the format:

Array [
0 => array ["Id" => "value", "Title" => "value", "PhoneNumber" => "value", "Email" => "value", "Messengers" => "value"] ,
1 => array ["Id" => "value", "Title" => "value", "PhoneNumber" => "value", "Email" => "value", "Messengers" => "value"] ,
...
N => array ["Id" => "value", "Title" => "value", "PhoneNumber" => "value", "Email" => "value", "Messengers" => "value"]
]

In the future, I consider this form most convenient for working with databases and sets of two-dimensional data of the “key-value” type.

The data exchange takes place via the HTTP protocol; therefore, the usual output “on the screen” of the received data and the completion of the script are sufficient.
The value of each field is encoded in Base-64 format, and the entire data array is converted to JSON-format and again encoded in Base-64. Enough safe and convenient for parsing in the client part of the application.

Now we analyze the client side.

I used a combination of the dataSet and dataGridView components .

There are two (to begin with) components on the form: dataSetContactsTable, dataGridViewContactsTable.

I advise you to immediately give all the components clear names - otherwise, then such a mess in the code will begin, that it is easier to write the software again than to refactor it.

When adding a dataSet component, I selected the “Untyped dataset” option.
Now configure the dataSet component. In the properties I set to him:



Click the button “Add” and set up the created table. Here are the parameters that I set:



The columns of the table should correspond to the data arriving from the server. Therefore, it was done like this:



It may be asked why all the columns are set to read only mode. This is due to the features of the softphone, when a double-click on a line should bring up a separate window in which work with the selected entry is performed.

Let's proceed to setting up the dataGrid component. And first I will describe those changes in the properties that I made for him.

Apparently, it does not make sense to describe the designer part of the config - everyone can have their own. I will touch only the question of columns and binding to the dataSet component.



All table fields, except the record ID, must be displayed to the application user. Therefore, the Id field is the only one that has the “Visible” parameter set to “False”. The rest of the settings are similar.



Everything. Mouse work is completed, you can now go to the code.

 private void FormContacts_Load(object sender, EventArgs e) { LoadContactsTable(); } 


For further work, we will immediately create a class that will help us parse the JSON array arriving from the server.

 public class ContactsList { public string Id { get; set; } public string Title { get; set; } public string PhoneNumber { get; set; } public string Email { get; set; } public string Messengers { get; set; } } 


Now you need to create a method that clears and reloads the data into a table on the form (it was already mentioned above in the FormContacts_Load code).

 //      ,    ,   - .       . public void LoadContactsTable(string args = "") { //   , ..        //    ,     -     . dataTableContactsView.Clear(); //     var contactsResponse = Response("getContactsTable", args); //  ,    -       if (contactsResponse["type"].Trim() == "success") { //      ContactsList,   var contactsJsonList = (List<ContactsList>) JsonConvert.DeserializeObject(contactsResponse["data"].Trim(), typeof (List<ContactsList>)); foreach (var key in contactsJsonList) { //      var row = dataTableContactsView.NewRow(); row[0] = Base64Decode(key.Id); row[1] = Base64Decode(key.Title); row[2] = Base64Decode(key.PhoneNumber); row[3] = Base64Decode(key.Email); row[4] = Base64Decode(key.Messengers); dataTableContactsView.Rows.Add(row); } } //   ,   ,    else { MessageBox.Show(contactsResponse["data"].Trim(), @"", MessageBoxButtons.OK, MessageBoxIcon.Error); } } 


That's basically it. Under all successful conditions (there is a server, a handler is written for the request, there is a response from the server, there is data in the database) the form will display the data we need.

By a similar principle, you can build any other table application. Look like that's it. I hope that I have not forgotten anything to describe and that the material is described fairly accessible and simple.

Thanks for attention.

Source: https://habr.com/ru/post/236029/


All Articles