Verwenden von Diensten und Behandeln ihrer Ergebnisse in Xamarin

Lassen Sie uns weiterhin die verschiedenen Aufgaben für Xamarin diskutieren, denen wir uns regelmäßig stellen müssen, da Artikel zu diesem Thema nicht sehr häufig erscheinen. Dieser Artikel ist für unerfahrene Entwickler nützlicher, aber auch erfahrene können interessant sein.





Warum also so ein Thema? Nachdem ich an verschiedenen Projekten gearbeitet hatte, dachte ich, dass bei jedem von ihnen völlig unterschiedliche Ansätze verwendet werden, um Dienste aufzurufen und Fehler zu behandeln. In diesem Artikel habe ich beschlossen, alles zu sammeln, was mir bevorsteht, zu zeigen, welche Optionen es gibt, und darüber nachzudenken, welche Vor- und Nachteile die einzelnen haben.





Betrachten wir verschiedene Ansätze anhand eines einfachen Beispiels, bei dem wir eine Liste mit Standardmodellen aus dem Backend anfordern und diese dann in eine Liste mit Ansichtsmodellen konvertieren, um die Sammlung anzuzeigen. Wir werden den UI-Teil hier nicht berücksichtigen, sondern uns nur auf die Arbeit der Dienste und das Ansichtsmodell beschränken.





Also unser einfaches Modell, das wir vom Backend anfordern werden:





public class ItemModel
{
    public string Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public string CreatedDate { get; set; }
    public string ModifiedDate { get; set; }
}
      
      



Und das entsprechende Ansichtsmodell, in dem wir nur 2 Felder aus dem Modell für die nachfolgende Anzeige benötigen:





public class ItemViewModel : ViewModel
{
    public ItemViewModel(ItemModel item)
    {
        Title = item.Title;
        Description = item.Description;
    }

    public string Title { get; }

    public string Description { get; }
}
      
      



, -:





public interface IDataService
{
    Task<IEnumerable<ItemModel>> LoadItemsAsync();
}
      
      



RequestService, :





public interface IRequestService
{
    Task<T> GetAsync<T>(string url);
}
      
      



- ItemViewModel. - ObservableCollection MvvmCross, AddRange()



, UI.





public class MainViewModel : ViewModel
{
    private readonly IDataService _dataService;

    public MainViewModel(IDataService dataService)
    {
        _dataService = dataService;
    }

    public MvxObservableCollection<ItemViewModel> Items { get; set; } = new();
}
      
      



- MainViewModel . -.





, :





public async Task Initialize()
{
    var result = await _dataService.LoadItemsAsync();
    var itemModels = result.ToList();
    if (itemModels.Any())
    {
        var items = new List<ItemViewModel>();
        itemModels.ForEach(m => items.Add(new ItemViewModel(m)));
        Items.AddRange(items);
    }
}
      
      



LoadItemsAsync()



- :





public Task<IEnumerable<ItemModel>> LoadItemsAsync()
{
    var url = "https://customapiservice/v1/items";
    return _requestService.GetAsync<IEnumerable<ItemModel>>(url);
}
      
      



, , , - 400- 500- . , crash. , , :





public async Task Initialize()
{
    try
    {
        var result = await _dataService.LoadItemsAsync();
        var itemModels = result.ToList();
        if (itemModels.Any())
        {
            var items = new List<ItemViewModel>();
            itemModels.ForEach(m => items.Add(new ItemViewModel(m)));
            Items.AddRange(items);
        }
    }
    catch (Exception e)
    {
        //      
    }
}
      
      



, . .





:





  • , , -





  • , ,





:





  • try-catch, -





  • , -





, - try-catch, . LoadItemsAsync()



:





public async Task<IEnumerable<ItemModel>> LoadItemsAsync()
{
    IEnumerable<ItemModel> result;
    try
    {
        var url = "https://customapiservice/v1/items";
        result = await _requestService.GetAsync<IEnumerable<ItemModel>>(url);
    }
    catch (Exception e)
    {
        result = new List<ItemModel>();
    }

    return result;
}
      
      



- , , - . , - . - null, , . , api null, .





:





  • - , breakpoints





  • try-catch, -





:





  • try-catch





  • , exception,





. , :





public class ServiceResult<TResult, TError>
{

    public ServiceResult(TResult result)
    {
        IsSuccessful = true;
        Result = result;
    }

    public ServiceResult(TError error)
    {
        IsSuccessful = false;
        Error = error;
    }

    public bool IsSuccessful { get; }
    public TResult Result { get; }
    public TError Error { get; }
}
      
      



LoadItemsAsync()



, :





public interface IDataService
{
    Task<ServiceResult<IEnumerable<ItemModel>, Exception>> LoadItemsAsync();
}
      
      



public async Task<ServiceResult<IEnumerable<ItemModel>, Exception>> LoadItemsAsync()
{
    try
    {
        var url = "https://customapiservice/v1/items";
        var result = await _requestService.GetAsync<IEnumerable<ItemModel>>(url);
        return new ServiceResult<IEnumerable<ItemModel>, Exception>(result);
    }
    catch (Exception e)
    {
        return new ServiceResult<IEnumerable<ItemModel>, Exception>(e);
    }
}
      
      



, - , - , try-catch:





public async Task Initialize()
{
    var result = await _dataService.LoadItemsAsync();
    if (result.IsSuccessful)
    {
        var itemModels = result.Result.ToList();
        if (itemModels.Any())
        {
            var items = new List<ItemViewModel>();
            itemModels.ForEach(m => items.Add(new ItemViewModel(m)));
            Items.AddRange(items);
        }
    }
    else
    {
        //      
    }   
}
      
      



:





  • , .





  • try-catch





  • - , , -





:





  • , , ServiceResult





  • -, - try-catch, ,





  • try-catch





OperationFactory FlexiMvvm. , Func OnSuccess OnError, , . DataService



:





public interface IDataService
{
    Task LoadItemsAsync(
        Func<IEnumerable<ItemModel>, Task> onSuccess = null,
        Func<Exception, Task> onError = null);
}
      
      



public async Task LoadItemsAsync(
    Func<IEnumerable<ItemModel>, Task> onSuccess = null,
    Func<Exception, Task> onError = null)
{
    try
    {
        var url = "https://customapiservice/v1/items";
        var result = await _requestService.GetAsync<IEnumerable<ItemModel>>(url);
        onSuccess?.Invoke(result);
    }
    catch (Exception e)
    {
        onError?.Invoke(e);
    }
}
      
      



- :





public async Task Initialize()
{
    await _dataService.LoadItemsAsync(HandleLoadSuccess, HandleLoadError);
}

private Task HandleLoadSuccess(IEnumerable<ItemModel> result)
{
    var itemModels = result.ToList();
    if (itemModels.Any())
    {
        var items = new List<ItemViewModel>();
        itemModels.ForEach(m => items.Add(new ItemViewModel(m)));
        Items.AddRange(items);
    }

    return Task.CompletedTask;
}

private Task HandleLoadError(Exception arg)
{
    //      
}
      
      



, - , Initialize()



, , .





, :





  • -









  • :





  • - OnSuccess OnError, , ,





  • try-catch





, OperationFactory. ServiceResult



. ServiceCall



, . 3 Func. - , - , - .





ExecuteAsync()



try-catch-finally. exception - ErrorHandler, try-catch, exception. - SuccessHandler, try-catch.





public class ServiceCall<TResult>
{
    private readonly Func<Task<TResult>> _callAction;

    public ServiceCall(Func<Task<TResult>> callAction)
    {
        _callAction = callAction;
    }

    public Func<TResult, Task> SuccessHandler { get; set; }

    public Func<Exception, Task> ErrorHandler { get; set; }

		public async Task ExecuteAsync()
    {
        TResult result = default;
        var isSuccess = false;

        try
        {
            result = await _callAction.Invoke();
            isSuccess = true;
        }
        catch (Exception e)
        {
            try
            {
                await ErrorHandler.Invoke(e);
            }
            catch (Exception)
            {
            }
        }
        finally
        {
            if (isSuccess)
            {
                try
                {
                    await SuccessHandler.Invoke(result);
                }
                catch (Exception)
                {
                }
            }
        }
    }
}
      
      



ServiceCallHandler



, , . , .





public interface IServiceCallHandler<TResult>
{
    IServiceCallHandler<TResult> OnSuccessAsync(Func<TResult, Task> handler);

    IServiceCallHandler<TResult> OnErrorAsync(Func<Exception, Task> handler);

    Task ExecuteAsync();
}
      
      



public class ServiceCallHandler<TResult> : IServiceCallHandler<TResult>
{
    private ServiceCall<TResult> _serviceCall;

    public ServiceCallHandler(ServiceCall<TResult> serviceCall)
    {
        _serviceCall = serviceCall;
    }

    public IServiceCallHandler<TResult> OnSuccessAsync(Func<TResult, Task> handler)
    {
        _serviceCall.SuccessHandler = handler;
        return this;
    }

    public IServiceCallHandler<TResult> OnErrorAsync(Func<Exception, Task> handler)
    {
        _serviceCall.ErrorHandler = handler;
        return this;
    }

    public Task ExecuteAsync() => _serviceCall.ExecuteAsync();
}
      
      







public interface IDataService
{
    IServiceCallHandler<IEnumerable<ItemModel>> LoadItems();
}
      
      



public IServiceCallHandler<IEnumerable<ItemModel>> LoadItems()
{
    var serviceCall = new ServiceCall<IEnumerable<ItemModel>>(LoadItemsAction);
    return new ServiceCallHandler<IEnumerable<ItemModel>>(serviceCall);
}

private Task<IEnumerable<ItemModel>> LoadItemsAction()
{
    var url = "https://customapiservice/v1/items";
    return _requestService.GetAsync<IEnumerable<ItemModel>>(url);
}
      
      



Initialize()



- , HandleLoadSuccess



HandleLoadError



.





public async Task Initialize()
{
    await _dataService
        .LoadItems()
        .OnSuccessAsync(HandleLoadSuccess)
        .OnErrorAsync(HandleLoadError)
        .ExecuteAsync();
}
      
      



:





  • , , , . OnSuccess OnError .





  • try-catch , -. ServiceCall.





, , :









  • , , IServiceCallHandler





  • ExecuteAsync()





, , . , . , .





Wenn Sie auch interessante Methoden haben, die in diesem Artikel nicht erwähnt werden - teilen Sie sie in den Kommentaren mit, vielleicht lernt jemand etwas Nützliches für sich.








All Articles