Menggunakan layanan dan menangani hasil mereka di Xamarin

Mari terus membahas berbagai tugas untuk Xamarin yang harus kita hadapi secara rutin, karena artikel tentang topik ini tidak terlalu sering muncul. Artikel ini akan lebih berguna untuk pengembang pemula, tetapi yang lebih berpengalaman mungkin juga menarik.





Jadi mengapa topik seperti itu? Setelah mengerjakan proyek yang berbeda, saya mendapati diri saya berpikir bahwa pada masing-masing dari mereka pendekatan yang sama sekali berbeda digunakan untuk memanggil layanan dan menangani kesalahan. Dalam artikel ini, saya memutuskan untuk mengumpulkan semua yang harus saya hadapi, menunjukkan opsi apa yang ada, dan memikirkan tentang pro dan kontra apa yang dimiliki masing-masing.





Mari kita pertimbangkan pendekatan yang berbeda dengan contoh sederhana, di mana kita akan memiliki permintaan untuk daftar model standar dari backend, dan kemudian mengonversinya menjadi daftar model tampilan untuk menampilkan koleksi. Kami tidak akan mempertimbangkan bagian UI di sini, kami akan membatasi diri hanya untuk pekerjaan layanan dan model tampilan.





Jadi, model sederhana kami, yang akan kami minta dari backend:





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



Dan Model Tampilan yang sesuai, di mana kita hanya membutuhkan 2 bidang dari model untuk tampilan berikutnya:





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





, , . , . , .





Jika Anda juga memiliki metode menarik yang tidak disebutkan dalam artikel ini - bagikan di komentar, mungkin seseorang akan belajar sesuatu yang berguna untuk diri mereka sendiri.








All Articles