2009-12-11 3 views
6

У меня есть приложение WPF, которое я сейчас работаю над разделением на клиентскую и серверную стороны - с использованием WCF. Мне не понравился беспорядок, который я изначально получил с прямым решением, так что теперь я реструктурирую следующие рекомендации в скринкасте Мигеля Кастро, WCF Extreme. Если вы не знакомы с видео, он в основном настраивает все сообщение вручную - без использования ссылок на службы. Это включает в себя:Реализация службы async WCF

  • Общий договор со всеми контрактами услуг и данных - ссылка клиентом и сервером
  • Консоль хостинг приложений службы
  • прокси-классы на отображение клиента до службы и прохождения вызовов (используя ClientBase или ClientFactory)

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

При добавлении ссылки на службу я могу установить флажок «Сгенерировать асинхронные операции», и я получаю MyServiceCompleted и MyServiceAsync. Тем не менее, я думаю, это то, что было создано при добавлении ссылки на службу, а не какая-то магия в классы, на которых это происходит?

Итак, могу ли я как-то получить асинхронные операции с ClientBase или ClientFactory? Или мне нужно определить, какие службы на стороне сервера будут асинхронными? Если да - может кто-нибудь, пожалуйста, дайте мне несколько советов или примеров о том, как начать работу с простой службой асинхронного обслуживания? Я читал в MSDN по этому вопросу, но это оставило меня все смущенное чувство, как идиот, для того, чтобы не получить это уже.

ответ

5

Реализация асинхронных операций на стороне сервера довольно проста. Убедитесь, что имена методов совпадают, и они начинаются с начала и конца. GetImageAsyncResult - это обычная реализация IAsyncResult (множество примеров в Интернете).

public class MapProvider : IMapProvider //implementation - belongs to server 
    { 
     public IAsyncResult BeginGetImage(int level, int x, int y, string[] layers, AsyncCallback callback, object state) 
     { 
       GetImageAsyncResult asyncResult = new GetImageAsyncResult(level, x, y, layers, callback, state); 
       ThreadPool.QueueUserWorkItem(Callback, asyncResult); 
       return asyncResult; 
     } 

     private void Callback(object state) 
     { 

       GetImageAsyncResult asyncResult = state as GetImageAsyncResult; 
       asyncResult.Image = TileProvider.GetImage(asyncResult.Level, asyncResult.X, asyncResult.Y, asyncResult.Layers); 
       asyncResult.Complete(); 
     } 

     public System.Drawing.Bitmap EndGetImage(IAsyncResult result) 
     { 
       using (GetImageAsyncResult asyncResult = result as GetImageAsyncResult) 
       { 
        asyncResult.AsyncWait.WaitOne(); 
        return asyncResult.Image; 
       } 
     } 
    } 

    public class MapProviderProxy : ClientBase<IMapProvider>, IMapProvider, IDisposable 
    { 
     public IAsyncResult BeginGetImage(int level, int x, int y, string[] layers, AsyncCallback callback, object state) 
     { 
       return Channel.BeginGetImage(level, x, y, layers, callback, state); 
     } 

     public System.Drawing.Bitmap EndGetImage(IAsyncResult result) 
     { 
       return Channel.EndGetImage(result); 
     } 

     public void Dispose() 
     { 
       if (State == CommunicationState.Faulted) 
       { 
        Abort(); 
       } 
       else 
       { 
        try 
        { 
         Close(); 
        } 
        catch 
        { 
         Abort(); 
        } 
       } 
     } 
    } 
+0

Спасибо! И IMapProvider будет иметь функции BeginGetImage и EndGetImage, определенные с тегом «[OperationContract (AsyncPattern = true)]»? И мне нужно определить конкретный результат из этого, GetImageAsyncResult? – stiank81

+0

Правильно - я нашел базовый класс AsyncResult в Интернете. GetImageAsyncResult вытекает из этого. – Goran

+0

Хорошо - это отвечает на мой вопрос. Однако я понял, что не хочу, чтобы служба была асинхронной, но я хочу синхронно вызывать синхронную службу. То есть Я обработаю его на стороне клиента. Я легко решаю это с помощью AsyncMethodCaller. Спасибо, в любом случае! – stiank81

3

Когда вы выбираете «Сгенерировать операции асинхронности», как вы отметили, нет магия: Begin... начнет ваше общение, сервер начнет обрабатывать материал, но вы не сможете ничего использовать, пока не назовете End....

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

Вы, вероятно, думая, что это должно быть сложным, но это не;)

EDIT: Вот идут пример:

using (Service.SampleClient client = new Service.SampleClient()) 
{ 
    client.AddCompleted += 
     (object sender, Service.AddCompletedEventArgs e) 
      { 
       Console.WriteLine(e.Result); // 2 
      }; 
    client.AddAsync(1, 1); 

    // wait for async callback 
    Console.ReadLine(); 
} 

[ServiceContract] 
public interface ISample 
{ 
    [OperationContract] 
    int Add(int a, int b); 
} 

Вы можете также явно запрограммировать сервис для работы асинхр , как описано здесь: Synchronous and Asynchronous Operations, используя [OperationContract(AsyncPattern=true)]

+0

Ehr .. Не могли бы вы рассказать? Вы говорите, что я могу оставить сервисы нетронутыми и реализовать обработку async на стороне клиента? Да, есть высокий риск, я вижу это более сложным, чем это: -P – stiank81

+0

ОК, я работаю над примером, держись =) –

+0

Спасибо, оцените его :-) – stiank81

3

Альтернативный способ для достижения асинхронных операций на стороне клиента без использования SvcUtil заключается в создании интерфейса (ServiceContract) локально на стороне клиента, который реализует операцию асинхронной.

Контракт на стороне сервера:

[ServiceContract] 
public interface IServerContract 
{ 
    [OperationContract] 
    string GetData(int value); 
} 

Асинхронный контракт на стороне клиента

[ServiceContract(Namespace = "http://tempuri.org/", Name = "IServerContract")] 
public interface IClientContractAsync 
{ 
     [OperationContract] 
     Task<string> GetDataAsync(int value); 
} 

Обратите внимание, что имя и пространство имен по умолчанию должно быть установлено на контракте клиента, чтобы соответствовать пространство имен контрактного сервера. Итак, теперь у вас есть асинхронная операция (без новых новых потоков). Таким образом, вам не нужно выполнять какую-либо конкретную реализацию на стороне сервера. Конечно, это похоже на то, что делает SvcUtil, но SvcUtil генерирует много дополнительного кода, и иногда я нахожу svcutil, вызывающий проблемы, например. с повторным использованием классов.

ClientProxy

public class ClientProxy : ClientBase<IClientContractAsync> 
{ 
    public IClientContractAsync ChannelOut 
    { 
     get 
     { 
      return Channel; 
     } 
    } 
} 

Использование клиента:

static void Main(string[] args) 
{ 
    var client = new ClientProxy(); 
    client.Open(); 
    var asyncReadValue = client.ChannelOut.GetDataAsync(45).Result; 
    Console.WriteLine(asyncReadValue); 
    Console.ReadLine(); 
} 

хозяина класса

public class ServerService : IServerContract 
{ 
    public string GetData(int value) 
    { 
     return string.Format("You entered: {0}", value); 
    } 
} 

Сервер Сервер

static void Main(string[] args) 
{ 
    var server = new ServiceHost(typeof(ServerService)); 
    server.Open(); 
    Console.WriteLine("started"); 
    Console.ReadLine(); 
} 
Смежные вопросы