Xamarinでのサービスの使用とその結果の処理

このトピックに関する記事はあまり頻繁に表示されないため、定期的に直面する必要のあるXamarinのさまざまなタスクについて引き続き説明します。この記事は初心者の開発者にとってより役立つでしょうが、より経験豊富なものも興味深いかもしれません。





では、なぜそのようなトピックなのですか?さまざまなプロジェクトに取り組んできたので、それぞれのプロジェクトで、サービスの呼び出しとエラーの処理にまったく異なるアプローチが使用されていると思いました。この記事では、私が直面しなければならなかったすべてを収集し、そこにあるオプションを示し、それぞれの長所と短所について考えることにしました。





簡単な例でさまざまなアプローチを考えてみましょう。バックエンドから標準モデルのリストを要求し、それらをビューモデルのリストに変換してコレクションを表示します。ここではUIの部分については考慮せず、サービスの作業とビューモデルのみに限定します。





したがって、バックエンドから要求する単純なモデルは次のとおりです。





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; }
}
      
      



そして、対応するビューモデル。このモデルでは、後続の表示のためにモデルから2つのフィールドのみが必要です。





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()





, , . , . , .





この記事に記載されていない興味深い方法もある場合は、コメントで共有してください。おそらく誰かが自分に役立つ何かを学ぶでしょう。








All Articles