Мы используем службы wcf в приложении silverlight, создавая прокси с помощью ChanellFacotry.
Контракты «Операция» и «Данные» подвергаются сквозной сборке silverlight, которая состоит из общих файлов из серверной библиотеки «Контракты о данных и операциях». (О боже, я надеюсь, вы понимаете, о чем я говорю).
Таким образом, сервер и клиент используют одинаковые операции и контракты данных.
Silverlight wcf клиент lib имеет ограничение на невозможность синхронного вызова методов wcf, как вы знаете, поэтому файл контракта с общей операцией должен предоставлять асиновые версии каждой операции.
Написание асинхронной службы WCF имело бы некоторый смысл, если бы в ней не было операций блокировки, но, поскольку мы используем EF, асинхронность достигается путем делегирования блокирующей работы пулу потоков. Это то, что WCF делает для методов синхронизации в любом случае. И этот факт заставляет меня хотеть оторвать глаза (# @%! ^%! @%).
Наш консультант проекта может запретить генерировать динамические прокси на клиенте для вызова методов контракта операции синхронизации (google, Евгений Бобров, Части сервелата, если вам интересно). Поэтому мы должны написать бессмысленные реализации асинхронных методов на стороне сервера без какого-либо увеличения производительности (блокировка вызовов, как вы помните).
Можно ли вызвать синхронный метод веб-службы wcf из silverlight, используя контракт данных?
Вы когда-нибудь сталкивались с этой проблемой раньше? Если да, то как вы ее решили?
В данный момент я с нетерпением жду возможности создания асинхронных контрактов для клиентской стороны, используя только серверные контракты в качестве источника преобразования. Может быть, есть какой-нибудь шаблон t4, который может сделать это для меня?
Извините за стену текста, просто чтобы смешать некоторый код с моим вопросом, вот как выглядит реализация асинхронного контракта:
/// <summary>
/// Subscribes to users of the specified organization.
/// </summary>
/// <param name="organizationId">The organization id.</param>
public void Unsubscribe(int organizationId)
{
var clientId = this.OperationContext.GetClientId();
if (string.IsNullOrEmpty(clientId))
{
return;
}
this.InternalUnsubscribe(organizationId, clientId);
}
/// <summary>
/// Begins an asynchronous operation to Unsubscribe.
/// </summary>
/// <param name="organizationId">The organization id.</param>
/// <param name="callback">The callback.</param>
/// <param name="passThroughData">The pass through data.</param>
/// <returns>
/// An implementation of <see cref="IAsyncResult"/> that provides access to the state or result of the operation.
/// </returns>
public IAsyncResult BeginUnsubscribe(int organizationId, AsyncCallback callback, object passThroughData)
{
var clientId = this.OperationContext.GetClientId();
if (string.IsNullOrEmpty(clientId))
{
return null;
}
var asyncResult = new VoidAsyncResult(callback, passThroughData);
Task.Factory.StartNew(() =>
{
try
{
this.InternalUnsubscribe(organizationId, clientId);
asyncResult.SetAsCompleted(false);
}
catch (Exception ex)
{
asyncResult.SetAsCompleted(ex, false);
}
});
return asyncResult;
}
/// <summary>
/// Ends an existing asynchronous operation to Unsubscribe.
/// </summary>
/// <param name="result">The <see cref="IAsyncResult"/> provided by the BeginUnsubscribe operation.</param>
public void EndUnsubscribe(IAsyncResult result)
{
var response = result as VoidAsyncResult;
if (response != null)
{
response.EndInvoke();
}
}