Estoy usando la biblioteca Refit en mi aplicación Xamarin, quiero establecer un tiempo de espera de 10 segundos para la solicitud. ¿Hay alguna manera de hacer esto en la reparación?
Interfaz:
interface IDevice { [Get("/app/device/{id}")] Task<Device> GetDevice(string id, [Header("Authorization")] string authorization); }Invocando la API
var device = RestService.For<IDevice>("http://localhost"); var dev = await device.GetDevice("15e2a691-06df-4741-b26e-87e1eecc6bd7", "Bearer OAUTH_TOKEN");La respuesta aceptada es la forma correcta de aplicar un tiempo de espera para una sola solicitud, pero si desea tener un único valor de tiempo de espera coherente para todas las solicitudes, puede pasar un HttpClient preconfigurado con su propiedad Timeout establecida:
var api = RestService.For<IDevice>(new HttpClient { BaseAddress = new Uri("http://localhost"), Timeout = TimeSpan.FromSeconds(10) });Aquí hay un proyecto de ejemplo .
Finalmente encontré una forma de configurar el tiempo de espera para una solicitud en Refit. CancelationToken . Aquí está el código modificado después de agregar CancelationToken
Interfaz:
interface IDevice { [Get("/app/device/{id}")] Task<Device> GetDevice(string id, [Header("Authorization")] string authorization, CancellationToken cancellationToken); }Invocando la API:
var device = RestService.For<IDevice>("http://localhost"); CancellationTokenSource tokenSource = new CancellationTokenSource(); tokenSource.CancelAfter(10000); // 10000 ms CancellationToken token = tokenSource.Token; var dev = await device.GetDevice("15e2a691-06df-4741-b26e-87e1eecc6bd7", "Bearer OAUTH_TOKEN", token);Funciona correctamente para mí. No sé si es la forma correcta o no. Si es un error, sugiera amablemente la forma correcta.
Otra solución: una de las pruebas en Refit utiliza este método. Agregue System.Reactive.Linq en nuget. Luego, en la especificación de la interfaz:
interface IDevice { [Get("/app/device/{id}")] IObservable<Device> GetDevice(string id, [Header("Authorization")] string authorization); }Y en la API:
try { await device.GetDevice("your_parameters_here").Timeout(TimeSpan.FromSeconds(10)); } catch(System.TimeoutException e) { Console.WriteLine("Timeout: " + e.Message); }+1 solución desde aquí :
Cree un método de extensión para sus tareas:
public static class TaskExtensions { public static async Task<TResult> TimeoutAfter<TResult>(this Task<TResult> task, TimeSpan timeout) { using (var timeoutCancellationTokenSource = new CancellationTokenSource()) { var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token)); if (completedTask == task) { timeoutCancellationTokenSource.Cancel(); return await task; // Very important in order to propagate exceptions } else { throw new TimeoutException("The operation has timed out."); } } } } La interfaz se puede dejar usando el valor de retorno Task<Device> . En la API:
try { await _server.ListGasLines().TimeoutAfter(TimeSpan.FromSeconds(10)); } catch(System.TimeoutException e) { Console.WriteLine("Timeout: " + e.Message); }