Приветствую уважаемое сообщество.
Краткая вводная часть
Сейчас пишу небольшой WCF Restful сервис, возникла задача выполнять длительные запросы. Наиболее простым и понятным решением было принимать такие запросы на обработку, выдавая номер задания и соответствующий статус. Затем клиент обращается с номером задания по другому адресу с номером и получает свой ответ (если он уже готов). Идея не новая, очевидная и была подтверждена поисками:
-
billhiggins.us/blog/2011/04/27/resty-long-ops (очень хорошо описано)
-
lostechies.com/jimmybogard/2013/05/15/eventual-con...Что я пытался сделать
Вспомнив, что около года назад писал что-то подобное, посмотрел архивы кода. Оказалось, что в тот раз мне нужно было выполнять всего один длительный метод, так что решил я всё быстро и просто (подозреваю, что далеко не идеально, но работает) - долгий метод был обёрнут в класс, подобный этому:
using System;
using System.ComponentModel;
namespace Service
{
public class LongTermJob
{
public string JobId { get; private set; }
public bool IsCompleted
{
get { return !_worker.IsBusy; }
}
public string Result
{
get { return IsCompleted ? _result : null; }
}
private readonly BackgroundWorker _worker;
// Результаты выполнения, вместо string нужный тип.
private string _result;
public LongTermJob(string jobId, WorkerArgs args)
{
JobId = jobId;
_worker = new BackgroundWorker();
_worker.DoWork += _worker_DoWork;
_worker.RunWorkerCompleted += _worker_RunWorkerCompleted;
_worker.RunWorkerAsync(args);
}
private void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_result = "Результат выполнения метода";
}
private void _worker_DoWork(object sender, DoWorkEventArgs e)
{
var user = (WorkerArgs) e.Argument;
Console.WriteLine("Name: {0} Age: {1}", user.Name, user.Age);
}
}
public class WorkerArgs
{
public string Name { get; set; }
public int Age { get; set; }
}
}
Параметры запроса принимались, помещались в WorkerArgs, присваивался JobId (по которому потом осуществлялся возврат), создавался экземпляр LongTermJob и просто помещался в List<>. Затем при обращении проверялся статус задания и при надобности возвращался результат. Для того случая было удобно, даже процент выполнения при надобности можно выдавать.
Но в этот раз такой код не подходит. Требуется выполнять неопределённое время уже не один, а десятки самых разных методов, которые возвращают самые разные типы и имеют произвольное количество параметров.
Я начал читать и пробовать варианты с:
- делегатами, но они позволяют передать только конкретные параметры и возвращать один тип;
- Task'ами, но в него ещё надо как то передать метод;
- Func'ами, чтобы передавать их в Task'и, но у них перегрузки под каждое количество параметров, как передавать произвольное.
В общем, перепробовал всё, что смог. Сейчас остановится примерно на таком коде:
public class LongTermJob
{
public bool IsCompleted
{
get { return _task.IsCompleted; }
}
public TestClass Result
{
get { return IsCompleted ? _result : null; }
}
private readonly Task<TestClass> _task;
private readonly TestClass _result;
public LongTermJob(Func<TestClass> method)
{
_task = Task.Factory.StartNew((method));
_result = _task.Result;
}
}
public class WorkerArgs
{
public string Name { get; set; }
public int Age { get; set; }
}
Если бы вот такой код, но чтобы TestClass был
<T>
...
Возможно, надо подойти совсем с другой стороны или есть уже готовые решения для подобных ситуаций. Буду благодарен любому решению и предложению.