С бизнес-логикой, инкапсулированной в синхронных сервисных вызовах, например ::10000 *
interface IFooService
{
Foo GetFooById(int id);
int SaveFoo(Foo foo);
}
Каков наилучший способ расширения / использования этих сервисных вызовов в асинхронном режиме ?
В настоящее время я создал простой класс AsyncUtils:
public static class AsyncUtils
{
public static void Execute<T>(Func<T> asyncFunc)
{
Execute(asyncFunc, null, null);
}
public static void Execute<T>(Func<T> asyncFunc, Action<T> successCallback)
{
Execute(asyncFunc, successCallback, null);
}
public static void Execute<T>(Func<T> asyncFunc, Action<T> successCallback, Action<Exception> failureCallback)
{
ThreadPool.UnsafeQueueUserWorkItem(state => ExecuteAndHandleError(asyncFunc, successCallback, failureCallback), null);
}
private static void ExecuteAndHandleError<T>(Func<T> asyncFunc, Action<T> successCallback, Action<Exception> failureCallback)
{
try
{
T result = asyncFunc();
if (successCallback != null)
{
successCallback(result);
}
}
catch (Exception e)
{
if (failureCallback != null)
{
failureCallback(e);
}
}
}
}
Что позволяет мне вызывать что-либо асинхронно:
AsyncUtils(
() => _fooService.SaveFoo(foo),
id => HandleFooSavedSuccessfully(id),
ex => HandleFooSaveError(ex));
Хотя это работает в простых случаях использования, он быстро становится сложным, если другим процессам необходимо согласовать результаты, например, если мне нужно асинхронно сохранить три объекта, прежде чем текущий поток может продолжиться, тогда я хотел бы подождать - в / присоединиться к рабочим потокам.
Опции, о которых я до сих пор думал, включают:
- с AsyncUtils возвращает WaitHandle
- если AsyncUtils использует AsyncMethodCaller и возвращает IAsyncResult
- переписывает API для включения Begin, End async call
например. что-то похожее:
interface IFooService
{
Foo GetFooById(int id);
IAsyncResult BeginGetFooById(int id);
Foo EndGetFooById(IAsyncResult result);
int SaveFoo(Foo foo);
IAsyncResult BeginSaveFoo(Foo foo);
int EndSaveFoo(IAsyncResult result);
}
Есть ли другие подходы, которые я должен рассмотреть? Каковы преимущества и потенциальные подводные камни каждого?
В идеале мне бы хотелось, чтобы уровень обслуживания был простым / синхронным, и чтобы было несколько простых в использовании утилит для вызова их асинхронно. Мне было бы интересно услышать о решениях и идеях, применимых к C # 3.5 и C # 4 (мы еще не обновились, но сделаем это в относительно ближайшем будущем).
Жду ваших идей.