65.9K
CodeProject 正在变化。 阅读更多。
Home

WCF 中的基于任务的异步操作

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (16投票s)

2013年6月30日

CPOL

2分钟阅读

viewsIcon

116034

downloadIcon

1555

本文介绍了 WCF 的新功能“基于任务的异步操作”。

引言

虽然性能阻塞迟缓是任何应用程序的绊脚石,但我们可以通过使用异步编程轻松克服这些瓶颈。但传统的异步编程方式编写、调试和维护并不容易。那么当今的解决方案是什么呢?

在我看来,这是基于任务的异步编程,它通过使用关键字awaitasync在 .NET 4.5 中得到更新。但是asyncawait的作用是什么?asyncawait是控制延续的方式。当一个方法使用async关键字时,这意味着它是一个异步方法,其中可能包含一个await关键字,如果它包含一个await关键字,async将激活它。因此,简单地说,async激活了await,从那时起,异步操作就开始了。这里有一个很好的解释。

在 WCF 中,我们也可以考虑在服务操作创建延迟调用时进行异步操作。有三种实现异步操作的方法:

  • 基于任务的异步
  • 基于事件的异步
  • IAsyncResult异步

在本文中,我将使用基于任务的异步操作,因为这是最现代化的策略。

好的,让我们进入代码。

定义和实现服务

一个非常简单的服务契约,例如:

 [ServiceContract]
 public interface IMessage
 {
     [OperationContract]
     Task<string> GetMessages(string msg);
 }

有了这个简单的契约,实现起来就非常直接了。

 public class MessageService : IMessage
 {
    async Task<string> IMessage.GetMessages(string msg)
    {
       var task = Task.Factory.StartNew(() =>
                                      {
                                          Thread.Sleep(10000);
                                          return "Return from Server : " + msg;
                                      });
      return await task.ConfigureAwait(false);
    }
 }

这里,该方法使用async关键字标记,这意味着它可能在内部使用await关键字。这也意味着该方法能够在await点暂停然后异步恢复。此外,它指示编译器将方法的输出或可能发生的任何异常提升到返回类型中。

服务托管

 class Program
 {
     static void Main(string[] args)
     {
        var svcHost = new ServiceHost(typeof (MessageService));
        Console.WriteLine("Available Endpoints :\n");
        svcHost.Description.Endpoints.ToList().ForEach
         (endpoints=> Console.WriteLine(endpoints.Address.ToString()));
        svcHost.Open();
        Console.ReadLine();
     }
 }

服务配置

<?xml version="1.0"?>
 <configuration>
     <system.serviceModel>
       <services>
          <service name="Rashim.RND.WCF.Asynchronous.ServiceImplementation.MessageService">
             <host>
                 <baseAddresses>
                     <add baseAddress="net.Tcp://:8732/"/>
                     <add baseAddress="https://:8889/"/>
                 </baseAddresses>
             </host>
             <endpoint address="Tcp" binding="netTcpBinding" 
             contract="Rashim.RND.WCF.Asynchronous.Services.IMessage"/>
             <endpoint address="Http" binding="basicHttpBinding" 
             contract="Rashim.RND.WCF.Asynchronous.Services.IMessage">
                 <identity>
                      <dns value="localhost"/>
                 </identity>
             </endpoint>
             <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
             <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
          </service>
       </services>
       <behaviors>
          <serviceBehaviors>
             <behavior>
                 <serviceMetadata/>
             </behavior>
          </serviceBehaviors>
       </behaviors>
     </system.serviceModel>
     <startup><supportedRuntime version="v4.0" 
     sku=".NETFramework,Version=v4.5"/></startup>
</configuration>

配置服务后,我们需要配置客户端应用程序来使用该服务。

定义客户端

一个简单的控制台应用程序(客户端)

class Program
 {
    static void Main(string[] args)
    {
       GetResult();
       Console.ReadLine();
    }

    private async static void GetResult()
    {
       var client = new Proxy("BasicHttpBinding_IMessage");
       var task = Task.Factory.StartNew(() => client.GetMessages("Hello"));
       var str = await task;
       str.ContinueWith(e =>
       {
          if (e.IsCompleted)
           {
              Console.WriteLine(str.Result);
           }
       });
      Console.WriteLine("Waiting for the result");
    }
 }

客户端配置

<?xml version="1.0"?>
 <configuration>
   <system.serviceModel>
     <bindings>
       <basicHttpBinding>
         <binding name="BasicHttpBinding_IMessage" />
       </basicHttpBinding>
     </bindings>
     <client>
       <endpoint address="https://:8889/Http" binding="basicHttpBinding"
          bindingConfiguration="BasicHttpBinding_IMessage" 
          contract="Rashim.RND.WCF.Asynchronous.Services.IMessage"
           name="BasicHttpBinding_IMessage" />
     </client>
   </system.serviceModel>
 </configuration>

最后,以下是proxy类,客户端将通过它来使用服务。

public class Proxy : ClientBase<IMessage>, IMessage
 {
    public Proxy()
    {
    }
    public Proxy(string endpointConfigurationName) :
    base(endpointConfigurationName)
    {
    }
    public Task<string> GetMessages(string msg)
    {
      return Channel.GetMessages(msg);
    }
 }

就这样。虽然这很简单。

© . All rights reserved.