|
@@ -1,4 +1,4 @@
|
|
|
-# Получение списка материалов выбранного продукта
|
|
|
|
|
|
|
+# HTTP запросы в C#. Получение списка материалов выбранного продукта
|
|
|
|
|
|
|
|
Возвращаемся к проекту на C#.
|
|
Возвращаемся к проекту на C#.
|
|
|
|
|
|
|
@@ -26,7 +26,7 @@ Authorization: Basic esmirnov 111103
|
|
|
var client = new HttpClient();
|
|
var client = new HttpClient();
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-В АПИ мы использовали "базовую" авторизацию. В C# я не нашёл встроенных библиотек для облегчения формирования заголовка для "базовой" авторизации (вероятно они есть в сборке для веб разработки, но мы должны пользоваться только тем, что есть в обычной)
|
|
|
|
|
|
|
+В АПИ мы использовали "базовую" авторизацию. В C# я не нашёл встроенных библиотек для облегчения формирования заголовка для "базовой" авторизации
|
|
|
|
|
|
|
|
Формируем base64-кодированную строку:
|
|
Формируем base64-кодированную строку:
|
|
|
|
|
|
|
@@ -55,20 +55,13 @@ private string GetString(string url){
|
|
|
|
|
|
|
|
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", basic);
|
|
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", basic);
|
|
|
|
|
|
|
|
- // тут самое интересное - клиент возвращает не строку, а "задачу", которая по выполнении вернёт строку
|
|
|
|
|
- Task<string> task = client.GetStringAsync(url);
|
|
|
|
|
-
|
|
|
|
|
- // методом Wait мы превращаем нашу функцию в синхронную
|
|
|
|
|
- task.Wait();
|
|
|
|
|
-
|
|
|
|
|
- // и возвращаем результат ВЫПОЛНЕННОЙ задачи
|
|
|
|
|
- return task.Result;
|
|
|
|
|
|
|
+ return client.GetStringAsync(url).Result;
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
## Разбор JSON
|
|
## Разбор JSON
|
|
|
|
|
|
|
|
-Теперь допишем интерфейс нашего поставщика данных:
|
|
|
|
|
|
|
+Сначала допишем интерфейс нашего поставщика данных:
|
|
|
|
|
|
|
|
```cs
|
|
```cs
|
|
|
interface IDataProvider
|
|
interface IDataProvider
|
|
@@ -78,7 +71,9 @@ interface IDataProvider
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Здесь я класс назвал не **Material**, а **MaterialTC**, потому что АПИ возвращает не весь объект материал, а только название и количество (**T**itle**C**ount).
|
|
|
|
|
|
|
+Здесь я класс назвал не **Material**, а **MaterialTC**, потому что АПИ возвращает не весь объект Material, а только название и количество (**T**itle**C**ount).
|
|
|
|
|
+
|
|
|
|
|
+### Классический вариант
|
|
|
|
|
|
|
|
И реализуем его:
|
|
И реализуем его:
|
|
|
|
|
|
|
@@ -118,13 +113,104 @@ public IEnumerable<MaterialTC> GetMaterials(int ProductId) {
|
|
|
using (var sr = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(resp))))
|
|
using (var sr = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(resp))))
|
|
|
{
|
|
{
|
|
|
var answer = (Answer)Serializer.ReadObject(sr.BaseStream);
|
|
var answer = (Answer)Serializer.ReadObject(sr.BaseStream);
|
|
|
-
|
|
|
|
|
foreach (MaterialTC material in answer.notice.data)
|
|
foreach (MaterialTC material in answer.notice.data)
|
|
|
{
|
|
{
|
|
|
result.Add(material);
|
|
result.Add(material);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ return result;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Вариант с регулярками
|
|
|
|
|
|
|
|
|
|
+Стандартный вариант слишком монстрообразный, на мой взгляд. Можно тоже самое реализовать через регулярки:
|
|
|
|
|
+
|
|
|
|
|
+Класса нам достаточно одного:
|
|
|
|
|
+
|
|
|
|
|
+```cs
|
|
|
|
|
+internal class MaterialTC
|
|
|
|
|
+{
|
|
|
|
|
+ public string Title { get; set; }
|
|
|
|
|
+ public int Count { get; set; }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Реализация метода **GetMaterials**:
|
|
|
|
|
+
|
|
|
|
|
+```cs
|
|
|
|
|
+public IEnumerable<MaterialTC> GetMaterials(int ProductId) {
|
|
|
|
|
+ var result = new List<MaterialTC>();
|
|
|
|
|
+
|
|
|
|
|
+ var resp = GetString($"http://localhost:8080/Material?product_id={ProductId}");
|
|
|
|
|
+
|
|
|
|
|
+ Regex regex = new Regex(@"\{""Title"":""(.*?)"",""Count"":(.*?)\}", RegexOptions.Singleline);
|
|
|
|
|
+ MatchCollection matches = regex.Matches(resp);
|
|
|
|
|
+ if (matches.Count > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ foreach (Match match in matches)
|
|
|
|
|
+ res.Add(new MaterialTC {
|
|
|
|
|
+ Title = match.Groups[1].ToString(),
|
|
|
|
|
+ Count=Convert.ToInt32(match.Groups[2].ToString())
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Надо, конечно, ещё проверить валидность ответа (notice->data|notice->answer), но с регулярками это тоже проще - вообще не нужно рисовать новый класс.
|
|
|
|
|
+
|
|
|
|
|
+### Вариант с JavaScriptSerializer
|
|
|
|
|
+
|
|
|
|
|
+Оказывается на **WorldSkills** можно использовать не только "голый" **.NET Framework**, но и библиотеки из других компонентов **Visual Studio**.
|
|
|
|
|
+
|
|
|
|
|
+В пространстве имён **System.Web.Script.Serialization** есть класс **JavaScriptSerializer**, который выглядит попроще чем классическая реализация:
|
|
|
|
|
+
|
|
|
|
|
+```cs
|
|
|
|
|
+// целевые классы нам по прежнему нужны, но уже без всяких аннотаций
|
|
|
|
|
+internal class MaterialTC
|
|
|
|
|
+{
|
|
|
|
|
+ public string Title { get; set; }
|
|
|
|
|
+ public int Count { get; set; }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+internal class Notice
|
|
|
|
|
+{
|
|
|
|
|
+ public Material[] data;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+internal class Answer
|
|
|
|
|
+{
|
|
|
|
|
+ public Notice notice;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+// в месте, где нам нужно распарсить JSON создаем сериализатор и разбираем строку
|
|
|
|
|
+var serializer = new JavaScriptSerializer();
|
|
|
|
|
+var answer = serializer.Deserialize<Answer>("тут ваша JSON-строка");
|
|
|
|
|
+
|
|
|
|
|
+// и ВСЁ
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## POST запросы с JSON
|
|
|
|
|
+
|
|
|
|
|
+Возможно понадобится что-то послать в АПИ, разберём как это делается:
|
|
|
|
|
+
|
|
|
|
|
+```cs
|
|
|
|
|
+// сначала запихиваем объект в JSON-строку.
|
|
|
|
|
+
|
|
|
|
|
+// тут можно завести отдельный класс, а можно создать анонимный объект
|
|
|
|
|
+var obj = new {username="qq", password="ww"};
|
|
|
|
|
+
|
|
|
|
|
+// и тем же сериализатором превращаем в JSON-строку
|
|
|
|
|
+var jsonString = serializer.Serialize(obj);
|
|
|
|
|
+
|
|
|
|
|
+// создаём контент для запроса
|
|
|
|
|
+var json = new StringContent(jsonString, Encoding.UTF8, "application/json");
|
|
|
|
|
+
|
|
|
|
|
+// и вызываем POST-запрос
|
|
|
|
|
+var client = new HttpClient();
|
|
|
|
|
+var result = client.PostAsync("http://localhost:8080/echo", json).Result;
|
|
|
|
|
+
|
|
|
|
|
+Console.WriteLine(result.Content.ReadAsStringAsync().Result);
|
|
|
```
|
|
```
|