Browse Source

C#+http+json

Евгений Колесников 4 years ago
parent
commit
ab5b181178
4 changed files with 153 additions and 11 deletions
  1. 19 11
      articles/api_php.md
  2. 130 0
      articles/cs_http.md
  3. BIN
      data/DockerPhp.zip
  4. 4 0
      readme.md

+ 19 - 11
articles/api_php.md

@@ -367,22 +367,20 @@ POST-запросы отличаются тем, что содержат дан
 
 В каталоге `data` этого репозитория лежит архив `DockerPhp.zip`, в нём настроены контейнеры PHP и NGINX.
 
-PHP проект складывать в подкаталог `www/yotc.kei` - он будет доступен на локальной машине по адресу localhost:8000, если будет более одного проекта, то нужно настроить NGINX:
+PHP проект складывать в подкаталог `www/yotc.kei` - он будет доступен на локальной машине по адресу `http://localhost:8080`. Если вам нужно более одного проекта, то нужно добавить в NGINX конфиг для нового проекта:
 
-* в каталоге `hosts` скопировать файл настроек и исправить в нём 2 строки (я их специально вынес в начало конфига)
+* в каталоге `hosts` скопировать файл настроек `yotc_kei.conf` в, например, `myproject.conf` и исправить в нём 2 строки (я их специально вынес в начало конфига)
 
     ```
     server {
-        listen 80;
-        root /var/www/myproject;
+        listen 8081;
+        root /var/www/html/myproject;
     ```
 
+    - **listen 8081;** - порты до 1024 считаются зарезервированными, поэтому используйте 8081 и т.д. (общепринятая практика)
+    - **root /var/www/html/myproject;** - путь к вашему проекту в каталоге `www` (**/var/www/html/** - на этот путь каталог монтируется в контейнере)
 
-    - **listen 80;** - установить другой порт (порты до 1024 считаются зарезервированными, поэтому используйте 8081 и т.д.)
-
-    - **root /var/www/myproject;** - путь к вашему проекту в каталоге `www`
-
-* в файле **docker-compose.yml** в секцию **nginx -> ports** добавьте порт вашего проекта
+* в файле **docker-compose.yml** в секцию **nginx -> ports** добавьте порт вашего нового проекта
 
     ```yml
     services:
@@ -391,8 +389,18 @@ PHP проект складывать в подкаталог `www/yotc.kei` - 
             image: nginx:latest
             # маршрутизируем порты
             ports:
-                - "8000:80"
+                - "8080:80"
                 - "8081:8081"
     ```
 
-Как запустить/остановить контейнеры написано в **read.me** (находится в архиве)
+Как запустить/остановить контейнеры написано в **read.me** (находится в архиве)
+
+<!-- 
+
+работу с датой добавить в шпаргалки
+
+нижнее меню
+
+горизонтальный список карт, смена свайпом
+
+-->

+ 130 - 0
articles/cs_http.md

@@ -0,0 +1,130 @@
+# Получение списка материалов выбранного продукта
+
+Возвращаемся к проекту на C#.
+
+Мы остановились на списке материалов.
+
+Реализуем получение списка материалов выбранного продукта с помощью HTTP-запроса к АПИ, которое мы реализовали в прошлой теме.
+
+Напоминаю, GET-запрос на локальный компьютер:
+
+```
+GET http://localhost:8080/Material?product_id=1
+Authorization: Basic esmirnov 111103
+```
+
+На C# нам надо решить две задачи:
+
+* получить JSON-строку с помощью GET-запроса
+* распарсить JSON-строку, получив массив материалов
+
+## HTTP-запросы
+
+Для HTTP-запросов будем использовать встроенный класс **HttpClient**
+
+```cs
+var client = new HttpClient();
+```
+
+В АПИ мы использовали "базовую" авторизацию. В C# я не нашёл встроенных библиотек для облегчения формирования заголовка для "базовой" авторизации (вероятно они есть в сборке для веб разработки, но мы должны пользоваться только тем, что есть в обычной)
+
+Формируем base64-кодированную строку:
+
+```cs
+var basic = Convert.ToBase64String(
+    ASCIIEncoding.ASCII.GetBytes("esmirnov:111103"));
+```
+
+И добавляем заголовок нашему http-клиенту:
+
+```cs
+client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", basic);
+```
+
+Теперь можно запрашивать данные. 
+
+У **HttpClient** все методы асинхронные, нужно понимать как работают async/await. Я для облегчения вашей работы нарисовал синхронную реализацию:
+
+```cs
+// в параметрах URL
+private string GetString(string url){
+    var basic = Convert.ToBase64String(
+        ASCIIEncoding.ASCII.GetBytes("esmirnov:111103"));
+        
+    var client = new HttpClient();
+
+    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", basic);
+
+    // тут самое интересное - клиент возвращает не строку, а "задачу", которая по выполнении вернёт строку
+    Task<string> task = client.GetStringAsync(url);
+
+    // методом Wait мы превращаем нашу функцию в синхронную
+    task.Wait();
+
+    // и возвращаем результат ВЫПОЛНЕННОЙ задачи
+    return task.Result;
+}
+```
+
+## Разбор JSON
+
+Теперь допишем интерфейс нашего поставщика данных:
+
+```cs
+interface IDataProvider
+{
+    ...
+    IEnumerable<MaterialTC> GetMaterials(int ProductId);
+}    
+```
+
+Здесь я класс назвал не **Material**, а **MaterialTC**, потому что АПИ возвращает не весь объект материал, а только название и количество (**T**itle**C**ount).
+
+И реализуем его:
+
+```cs
+[DataContract]
+internal class MaterialTC
+{
+    [DataMember]
+    public string Title { get; set; }
+    [DataMember]
+    public int Count { get; set; }
+}
+
+// В ответе у нас не сразу массив материалов, а два вложенных объекта, поэтому надо их тоже описать
+
+[DataContract]
+internal class Notice
+{
+    [DataMember]
+    public Material[] data { get; set; }
+}
+
+[DataContract]
+internal class Answer
+{
+    [DataMember]
+    public Notice notice { get; set; }
+}
+
+public IEnumerable<MaterialTC> GetMaterials(int ProductId) {
+    var result = new List<MaterialTC>();
+
+    var resp = GetString($"http://localhost:8080/Material?product_id={ProductId}");
+
+    var Serializer = new DataContractJsonSerializer(typeof(Answer));
+
+    using (var sr = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(resp))))
+    {
+        var answer = (Answer)Serializer.ReadObject(sr.BaseStream);
+
+        foreach (MaterialTC material in answer.notice.data)
+        {
+            result.Add(material);
+        }
+    }
+
+    return result;
+}
+```

BIN
data/DockerPhp.zip


+ 4 - 0
readme.md

@@ -148,6 +148,10 @@ http://sergeyteplyakov.blogspot.com/2014/01/microsoft-fakes-state-verification.h
 
 1. [API. PHP-сервер. GET-запрос.](./articles/api_php.md)
 
+## Тема 5.1.6. C#, HTTP-запросы, JSON
+
+1. [Получение списка материалов выбранного продукта](./articles/cs_http.md)
+
 <!-- 
 кнопки с картинками (нижнее или боковое меню)(фрагменты)
 поиск (фильтрация) - строка поиска и выпадающий список