Last active
September 10, 2023 15:27
-
-
Save dmorosinotto/091fd87ffded98b773b1bbf22cf59b7f to your computer and use it in GitHub Desktop.
C# AsyncUtils utility to call an async method from a sincronous context IT WORKS!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Threading; | |
using System.Threading.Tasks; | |
/// <summary> | |
/// Helper class to run async methods within a sync process. | |
/// ORIGINAL CODE: https://www.ryadel.com/en/asyncutil-c-helper-class-async-method-sync-result-wait/ | |
/// </summary> | |
public static class AsyncUtil { | |
private static readonly TaskFactory _taskFactory = new TaskFactory(CancellationToken.None, | |
TaskCreationOptions.None, | |
TaskContinuationOptions.None, | |
TaskScheduler.Default); | |
/// <summary> | |
/// Executes an async Task method which has a void return value synchronously | |
/// USAGE: AsyncUtil.RunSync(() => yourMethodAsync()); | |
/// </summary> | |
/// <param name="task">Task method to execute</param> | |
public static void RunSync(Func<Task> task) => _taskFactory | |
.StartNew(task) | |
.Unwrap().GetAwaiter().GetResult(); | |
/// <summary> | |
/// Executes an async Task<T> method which has a T return type synchronously | |
/// USAGE: T result = AsyncUtil.RunSync(() => yourMethodAsync<T>()); | |
/// </summary> | |
/// <typeparam name="TResult">Return Type</typeparam> | |
/// <param name="task">Task<T> method to execute</param> | |
/// <returns></returns> | |
public static TResult RunSync<TResult>(Func<Task<TResult>> task) => _taskFactory | |
.StartNew(task) | |
.Unwrap().GetAwaiter().GetResult(); | |
/// <summary> | |
/// Force the current Thread/Task to temporary "loose processor" to give opportunity to other Thread/Task to execute. | |
/// ORIGINAL CODE BY @MircoVanini THE MASTER OF C# THREADING | |
/// </summary> | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public static void ThreadContextSwitching() { Task.Factory.StartNew(() => Thread.Sleep(0)).GetAwaiter().GetResult(); } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class GenericApiResult<TValue> | |
{ | |
public bool IsSuccessful { get; private set; } | |
public string ErrorMessage { get; private set; } | |
public TValue Value { get; private set; } | |
private GenericApiResult() | |
{ | |
IsSuccessful = false; | |
ErrorMessage = ""; | |
} | |
public static GenericApiResult<T> WithValue<T>(T value) => new GenericApiResult<T>() | |
{ | |
IsSuccessful = true, | |
Value = value, | |
ErrorMessage = "" | |
}; | |
public static GenericApiResult<T> WithErrorMessage<T>(string error) => new GenericApiResult<T>() | |
{ | |
IsSuccessful = false, | |
ErrorMessage = error, | |
Value = default, | |
}; | |
public static implicit operator bool(GenericApiResult<TValue> res) | |
{ //USATO PER POTER SCRIVERE CONDIZIONI DEL TIPO if (!res) ... | |
return res.IsSuccessful; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Newtonsoft.Json; | |
using System; | |
using System.Collections.Generic; | |
using System.Configuration; | |
using System.Net.Http; | |
public class MyHttpService { | |
private readonly ILogger _logger; | |
public NeosService(ILogger logger) | |
{ | |
_logger = logger; | |
} | |
public Task<GenericApiResult<IEnumerable<INeosCollection>>> GetCollectionsAsync() | |
{ | |
return this.callApi<IEnumerable<INeosCollection>>("collections"); | |
} | |
public Task<GenericApiResult<IEnumerable<INeosTag>>> GetTagsAsync() | |
{ | |
List<string> parameterList = new List<string>(); | |
if (!string.IsNullOrEmpty(collectionIdentifier)) | |
{ | |
parameterList.Add($"collection={Uri.EscapeUriString(collectionIdentifier)}"); | |
} | |
string parameters = null; | |
if (parameterList.Count() > 0) | |
{ | |
parameters = "?" + string.Join("&", parameterList); | |
} | |
return this.callApi<IEnumerable<INeosTag>>("tags", parameters); | |
} | |
#region "Helper chiamata API Http" | |
private static string BaseUrl | |
{ | |
get | |
{ | |
return ConfigurationManager.AppSettings["ExternalAPI.BaseUrl"]; | |
} | |
} | |
private static string Token | |
{ | |
get | |
{ | |
return ConfigurationManager.AppSettings["ExternalAPI.Token"]; | |
} | |
} | |
private async Task<GenericApiResult<T>> callApi<T>(string method, string escapedParameters = null) where T : class | |
{ | |
const string defaultErrorMessage = "Error calling exteral API"; | |
try | |
{ | |
using (var http = new HttpClient()) | |
{ | |
//http.DefaultRequestHeaders.Add("ContentType", "application/json"); | |
http.DefaultRequestHeaders.Add("Authentication", $"Bearer {Token}"); | |
var url = $"{BaseUrl}/dam/api/{method}"; | |
if (!string.IsNullOrEmpty(escapedParameters)) | |
{ | |
url += escapedParameters; | |
} | |
var response = await http.GetAsync(url); | |
if (response.IsSuccessStatusCode) | |
{ | |
var content = await response.Content.ReadAsStringAsync(); | |
var val = JsonConvert.DeserializeObject<T>(content); | |
return GenericApiResult<T>.WithValue<T>(val); | |
} | |
else | |
{ | |
string errorDetail = defaultErrorMessage; | |
if (response.StatusCode == System.Net.HttpStatusCode.BadRequest) | |
{ | |
var content = response.Content.ReadAsStringAsync().Result; | |
var res = JsonConvert.DeserializeObject<INeosErrorResponse>(content); | |
errorDetail = res.detail; | |
} | |
return GenericApiResult<T>.WithErrorMessage<T>(errorDetail); | |
} | |
} | |
} | |
catch (Exception e) | |
{ | |
_logger.Error<NeosService>("callNeosApi Error calling " + method, e); | |
return GenericApiResult<T>.WithErrorMessage<T>(defaultErrorMessage + method); | |
} | |
} | |
#endregion | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
public class SampleUsage { | |
private readonly _myHttpService: MyHttpService; | |
void ThisIs_SYNCRONOUS_Context() | |
{ | |
var cols = Utility.RunSync(() => _myHttpService.GetCollectionsAsync()); | |
if (!cols) throw new Exception("error getting collections!"); | |
foreach(c in cols.Value) { | |
var tags = Utility.RunSync(() => _myHttpService.GetTagsAsync(c)); | |
if (tags) Console.WriteLine(string.Join(tags.Value, ", ")); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment