Сериализация делегатов в WCF с помощью суррогата? - PullRequest
3 голосов
/ 27 июня 2010

У меня есть идея, но мне нужна помощь в ее реализации.

WCF не поддерживает делегатов в своих контрактах.Вместо этого он имеет громоздкий механизм контрактов обратного вызова, и я ищу способ преодолеть это ограничение.

Я думал об использовании IDataContractSurrogate для замены каждого делегата в контракте токеном, который будет сериализованк удаленной конечной точке.Там токен будет десериализован в сгенерированный делегат.Этот сгенерированный делегат отправит общее сообщение обратного вызова, которое инкапсулирует все аргументы (с которыми был вызван делегат).

Общее сообщение обратного вызова достигнет первой конечной точки, и там исходный делегат будет вызван с аргументами.

Вот целевая (упрощенная) последовательность:

  1. A вызывает B-proxy.Foo (обратный вызов)
  2. обратный вызов сериализуется через DelegateSurrogate.
  3. DelegateSurrogate сохраняет делегата в выделенном хранилище делегатов и заменяет его токеном
  4. Сообщение поступает в конечную точку B
  5. токен десериализуется через DelegateSurrogate
  6. DelegateSurrogate создает сгенерированный делегат
  7. B.Foo (генерируется обратный вызов) вызывается
  8. Позже B вызывает генерируемый вызов возврата (аргументы)
  9. generateCallback (аргументы) вызывает выделенный общийконтракт на конечной точке A: CallbackContract-proxy.GenericCallback (args)
  10. CallbackContract.GenericCallback (args) вызывается в конечной точке A
  11. Исходный обратный вызов извлекается из хранилища и вызывается: callback (args)

Я уже реализовал это ранее, используя службуавтобус (NServiceBus), но я хочу адаптировать идею к WCF, и мне трудно.Я знаю, как реализовать шаги 3, 6, 9 и 11. Я пока не знаю, как связать все в WCF - особенно суррогатную часть.

Вот и все - надеюсь, мой вопрос имел смысл, и чтоКоллективная мудрость здесь сможет помочь мне построить это.

Вот пример использования моего желаемого решения:

// client side
remoteSvc.GetEmployeeById(17, emp => 
{
    employees.Add(emp);
    logger.log("Result received");
});

// server side
public void GetEmployeeById(int id, Action<Employee> callback)
{
    var emp = getEmpFromDb(id);
    callback(emp);
}

1 Ответ

2 голосов
/ 10 июля 2010

На самом деле, в этом сценарии я бы посмотрел на Expression API. В отличие от делегата, Expression может быть деконструирован во время выполнения. Вы не можете сериализовать их по умолчанию , но много работы было выполнено в этом пространстве. Это также немного похоже на , что делают многие поставщики LINQ в фоновом режиме, например, WCF Data Services.

Конечно, другой подход заключается в простом использовании лямбда-выражения в качестве ловушки для RPC, что я и описываю здесь . Код, который реализует это, свободно доступен в дереве protobuf-net. Вы можете настроить это, используя атрибут, чтобы связать ваш токен с методом и получить атрибут из MethodInfo.

IMO, проблема с делегатами заключается в том, что они слишком тесно связаны с реализацией, поэтому у вас не может быть разных реализаций на каждом конце (что является общим требованием).

Выражения имеют то преимущество, что лямбда-выражения по-прежнему поддерживают intellisense и т. Д., Поэтому вы можете делать такие вещи, как:

client.Invoke(svc => svc.Foo(123, "abc"));

и из этого получить Foo (MethodInfo), 123 и "abc" отдельно, включая захваченные переменные, ref / out и т. Д. Все это работает.

...