Как вы решаете проблему shared business logic между Xamarin и другими платформами (например, через .NET Standard, MAUI)?

Решение задачи повторного использования бизнес-логики между Xamarin и другими платформами — ключевой аспект построения кросс-платформенных решений. Важно структурировать проект таким образом, чтобы максимальная часть кода (модели, сервисы, бизнес-правила) могла быть переиспользована в других приложениях (например, .NET MAUI, WPF, ASP.NET Core или консольных утилитах), минимизируя дублирование и поддерживая единый источник правды.

.NET Standard как основа общего кода

До появления .NET 5/6 и MAUI, самым распространённым способом совместного использования бизнес-логики в Xamarin была библиотека на базе .NET Standard. Этот формат позволяет писать кросс-платформенные библиотеки, которые могут использоваться в проектах под iOS, Android, UWP, WPF, Blazor и другими .NET-ориентированными платформами.

Пример структуры проекта:

/MyApp.Solution
├── MyApp.Mobile (Xamarin.Forms UI)
├── MyApp.Web (ASP.NET Core)
├── MyApp.MAUI (MAUI UI)
├── MyApp.Shared (.NET Standard Library)
 ├── Models/
 ├── Services/
 ├── Interfaces/
 └── UseCases/

В .NET Standard библиотеке располагаются:

  • Модели данных (POCO): User, Product, Order и т.д.

  • Сервисы: например, IAuthService, IDataSyncService

  • Бизнес-логика / UseCase’ы: классы, реализующие логику (например, валидация заказа)

  • Интерфейсы и репозитории: используются для DI и абстрагирования от платформенной реализации

Преимущества .NET Standard:

  • Переиспользуемость на многих .NET-платформах.

  • Независимость от UI-фреймворков.

  • Совместимость с большинством популярных библиотек (JSON.NET, Polly и т.д.).

  • Простая интеграция в Xamarin, MAUI, WPF, Blazor.

Внедрение бизнес-логики в разные платформы

После вынесения логики в MyApp.Shared, она может быть внедрена через Dependency Injection или через сервис-локаторы:

Пример (в Xamarin.Forms):

public class LoginViewModel
{
private readonly IAuthService \_authService;
public LoginViewModel(IAuthService authService)
{
\_authService = authService;
}
public async Task LoginAsync(string username, string password)
{
var result = await \_authService.Login(username, password);
// дальнейшая логика
}
}  

IAuthService — определён в .NET Standard, но его реализация может быть разной для платформ Xamarin, MAUI или Web.

Реализация сервисов через Dependency Injection

Внутри UI-проекта (Xamarin.Forms, MAUI и т.д.) подключается DI-контейнер и регистрируются зависимости:

builder.Services.AddSingleton<IAuthService, AuthService>();

Таким образом, бизнес-логика в .NET Standard обращается к IAuthService, не зная, как и где он реализован — это зависит от платформы.

Поддержка разных платформ: Xamarin, MAUI, Web

Если бизнес-логика изначально написана в .NET Standard, то она с минимальными изменениями может быть использована:

  • В Xamarin.Forms через Xamarin.Forms UI и DependencyService или DI.

  • В .NET MAUI без миграции, так как MAUI полностью поддерживает .NET Standard 2.0/2.1 и .NET 6/7.

  • В Blazor WebAssembly или Server — через DI и вызовы методов сервисов.

  • В WPF и WinForms — UI-слой работает с той же бизнес-логикой через ViewModel’и.

  • В ASP.NET Core — например, для админки или REST API, использующей ту же логику валидации.

В будущем: переход на .NET 6/7 и MAUI Class Libraries

С появлением .NET 6/7 и MAUI, Microsoft рекомендует использовать вместо .NET Standard — .NET SDK-style библиотеки, которые поддерживают multi-targeting:

<TargetFrameworks>net7.0;net7.0-ios;net7.0-android</TargetFrameworks>  

Это позволяет:

  • Создавать библиотеки, которые включают платформо-специфические реализации.

  • Использовать #if ANDROID, #if IOS для разделения логики.

  • Всё ещё иметь общую бизнес-логику без зависимости от UI.

Подход через NuGet

Если планируется повторное использование логики в нескольких решениях, общий код можно вынести в NuGet-пакет:

  1. Создаётся .NET Standard или .NET библиотека.

  2. Собирается .nupkg и публикуется (в MyGet, Azure Artifacts, NuGet.org или GitHub Packages).

  3. Подключается как зависимость во всех нужных приложениях.

Это позволяет централизованно обновлять бизнес-логику и синхронизировать изменения.

Примеры бизнес-логики, выносимой в общий код

  • Авторизация и управление токенами.

  • Работа с моделями данных (например, Order, Inventory).

  • Сервис работы с API (например, через HttpClient).

  • Операции с кэшем, валидацией, форматированием, вычислениями.

  • Использование общих Command, RelayCommand, ViewModelBase.

Ограничения и особенности

  • В .NET Standard нельзя использовать платформенно-зависимые API напрямую (например, Bluetooth, GPS, Push). Для них нужно использовать абстракции + DependencyService/DI.

  • UI-компоненты (XAML, Custom Renderers) нельзя вынести в общую библиотеку без MAUI или специфичного таргетинга.

  • Сложные зависимости (например, Camera API) требуют делегирования их в слой конкретной платформы (через интерфейсы).

  • При переходе с Xamarin на MAUI, Shared библиотека может использоваться без модификаций, если она на .NET Standard 2.0/2.1.

Пример внедрения бизнес-логики с DI

// Shared: IOrderService.cs
public interface IOrderService
{
Task&lt;IEnumerable<Order&gt;> GetOrdersAsync();
}
// Shared: OrderService.cs
public class OrderService : IOrderService
{
private readonly IApiClient \_client;
public OrderService(IApiClient client)
{
\_client = client;
}
public async Task&lt;IEnumerable<Order&gt;> GetOrdersAsync()
{
return await \_client.GetAsync&lt;List<Order&gt;>("api/orders");
}
}

Регистрация в Xamarin.Forms:

services.AddSingleton<IOrderService, OrderService>();

ViewModel использует IOrderService, а конкретная реализация настраивается в UI-проекте.

Итоговая структура кросс-платформенной архитектуры

  • Весь общий код — в MyApp.Core (.NET Standard или multi-targeted library).

  • Интерфейсы и бизнес-логика — в Core.

  • Реализации сервисов — в Platform/Presentation слоях (Xamarin, MAUI, Web).

  • UI взаимодействует только с Core через ViewModel, сервисы и DI.

Такой подход позволяет не просто делить код между Xamarin и другими платформами, а выстраивать устойчивую и масштабируемую архитектуру для любых будущих кросс-платформенных сценариев.