Содержание
На данный момент у меня есть приложение Blazor Hybrid .NET MAUI (клиент) для работы на смартфоне/планшете, которое сохраняет в локальную базу данных SQLite данные о местоположении пользователя, фотографии и т.д. А также приложение ASP.NET Core Web API, которое должно принимать от клиентов собранные данные, обрабатывать их и формировать единую базу данных. При попытке отправить данные с клиента Blazor Hybrid в приложение ASP.NET Core Web API я столкнулся с тем, что клиент постоянно выдает ошибку «Connection failure». Разберемся с тем, как отправить запрос из приложения Blazor Hybrid к ASP.NET Core Web API, используя протокол HTTP.
Причина ошибки Connection failure в Blazor Hybrid
Итак, следуя документации Microsoft по Blazor, для использования HttpClient
мы должны зарегистрировать сервис в нашем приложении и, используя директиву Razor @inject
запросить зависимость в необходимом нам компоненте. В приложении Blazor Hybrid эта рекомендация может выглядеть следующим образом:
в файле MauiProgram.cs регистрируем новый сервис:
var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); }); //добавляем сервис HttpClient builder.Services.AddScoped(sp => new HttpClient()); //здесь регистрация других зависимостей, настройка приложения и т.д. return builder.Build(); }
Теперь запросим сервис в любом компоненте Razor, например
@page "/tethering" @inject HttpClient client <Heading Size="HeadingSize.Is5">Связь с сервером</Heading> <Button Clicked="Connect">Передать данные</Button> @code { private int port = 1000; private string ipAddress = "192.168.143.133"; public async Task Connect() { string address = $"http://{ipAddress}:{port}/api/controller"; var orgs = await Context.Organizations.ToListAsync(); foreach (var org in orgs) { await client.PostAsJsonAsync(address, org); } } }
здесь мы пытаемся отправить POST-запрос по адресу http://192.168.143.133:1000/api/controller
, передав в теле запроса некий объект Organization
. Сервер ASP.NET Core Web API содержит необходимый контроллер, в приложении настроен в том числе и CORS, поэтому, по логике, такой запрос должен без проблем пройти. Однако, при попытке отправить запрос мы получаем ошибку:
Если посмотреть подробности этой ошибки в отладчике, то мы увидим:
Дело в том, что, начиная с версии Android 9 Pie по умолчанию для работы с ресурсами в сети необходимо использовать протокол HTTPS. Чтобы настроить работу приложения Android 9 и выше на работу с HTTP необходимо дополнительно настроить параметры безопасности сетевого подключения приложения (об этом ниже).
Вернемся к нашему приложению и попробуем отправить запрос по https:
@page "/tethering" @inject HttpClient client <Heading Size="HeadingSize.Is5">Связь с сервером</Heading> <Button Clicked="Connect">Передать данные</Button> @code { private int port = 1000; private string ipAddress = "192.168.143.133"; public async Task Connect() { string address = $"https://{ipAddress}:{port}/api/controller";//меняем протокол на https var orgs = await Context.Organizations.ToListAsync(); foreach (var org in orgs) { await client.PostAsJsonAsync(address, org); } } }
И здесь мы снова получим ту же ошибку «Connection failure» в консоли, однако причина этой ошибки будет иная:
Более того, после решения и этой ошибки я получил третью — недостоверный сертификат. В общем, для того, чтобы максимально быстро начать отладку приложений, я решил полностью отказаться от использования https и настроить работу как клиента, так и сервера на работу только с http.
Настройка приложения Blazor Hybrid для работы с HTTP в Android
По умолчанию, в Android 9 и выше мы должны настроить параметры безопасности сетевого подключения приложения, чтобы использовать протокол http. Сделать это можно двумя способами. Первый самый простой — добавить атрибут android:usesCleartextTraffic="true"
в элемент application
манифеста приложения:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application android:usesCleartextTraffic="true"....> </application> ... </manifest>
Второй способ немного сложнее, однако позволяет более тонко настраивать параметры безопасности. Для этого, создадим в папке Platforms/Android/Resources
папку xml
в которой разместим файл network_security_config.xml
:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true" /> </network-security-config>
и теперь изменим манифест приложения следующим образом:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application android:networkSecurityConfig="@xml/network_security_config" ...></application> здесь прочие настройки манифеста </manifest>
Результат будет тот же. что и в первом случае — приложение сможет отправлять запросы по http. Теперь нам необходимо обеспечить работу с http на сервере.
Настройка приложения ASP.NET Core Web API
Опять же, по умолчанию, приложение ASP.NET Core Web API перенаправляет все запросы с http на https. Для этого конвейер обработки запросов в приложении использует следующий компонент middleware:
app.UseHttpsRedirection();
Просто закомментируйте эту строку, чтобы отключить автоматическое перенаправление на https. Теперь, что клиент, что сервер будут работать по протоколу http без каких-либо ограничений и перенаправлений и отладка приложения будет проходить без каких-либо проблем:
Итого
Здесь мы настроили работу как приложения Blazor Hybrid в Android, так и ASP.NET Core Web API на работу с протоколом HTTPS. Как сказано в самом начале — такой подход небезопасен в готовом приложении и его рекомендуется использовать только для целей отладки.