WCF异步返回多个函数结果?

时间:2011-12-21 18:50:59

标签: wcf web-services asynchronous wcf-ria-services

我一直在阅读如何做到这一点,但我很难理解它。

Synchronous and Asynchronous Operations

WCF: Working with One-Way Calls, Callbacks, An...

我的目标是在发现Silverlight的WCF服务时从多个函数返回结果。

有关如何使用此服务的一般概述如下。

用户输入的网址包含超链接中列出的许多大型csv文件。该服务获取初始用户输入的URL,发出该URL的Web请求,使用正则表达式获取csv文件名,服务将csv文件下载到服务器,文件转换为不同的格式。

目前所有这些都有效,但在整个操作完成之前不会显示任何响应。我想在每个功能期间提供反馈。

我在这个应用程序中使用VB,但如果有人提供代码建议,我会精通C#。

<ServiceContract(Namespace:="http://somemadeupurl")>
<SilverLightFaultBehavior()>              
<AspNetCompatibilityRequirements(RequirementsMode:=
             AspNetCompatibilityRequirementsMode.Allowed)>
Public Class GetCSV

  <OperationContract()>
  Public Function ProcessInitialLink(ByVal strInitialLink As String)
  'download the source html

  'do a webrequest and extract  csv links   
  'since dates are in the filenames I would like to send back most 
  'recent to user here

    Dim strMostRecentCSV As String=SomeRegexMatch
> 'problem here. Would like to return strMostRecentCSV and keep processing
    GetAndConvertBigCSV(strMostRecentCSV)   
    Return strMostRecentCSV
  End Function

  'actually a list but for brevity..
  Private Function GetAndConvertBigCSV(ByVal strMostRecentCSV as string) 
    'do a bunch of downloading
    'call a function to do a bunch of converting
    'call a function to clean up files
  End Function
End Class

如果这样做会返回strMostRecentCSV,但必须等到GetAndConvertBigCSV完成才会返回。

我已经尝试将GetAndConvertBigCSV作为一个新线程生成并且它可以正常运行,但不会返回任何可以绑定到Silverlight客户端的内容(e.Result)

至少我想提供第一个函数Return的反馈,然后继续服务。

万分感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

我认为您可能需要的是“轮询双工http服务” - 这意味着WCF将为您伪造双工式服务(通过轮询)。与常规异步服务相比,双工服务的优势在于可以轻松地多次回调客户端(因此您可以提供有关任务进度的反馈)。

实施起来非常容易。假设您有两个项目,一个Web应用程序和一个Silverlight应用程序......

Web应用程序

创建您的服务,例如:

[ServiceContract(CallbackContract = typeof(ICallback))]
public interface ILongRunningService
{
    [OperationContract]
    void StartLongRunningProcess(string initialParameter);
}

[ServiceContract]
public interface ICallback
{
    [OperationContract(IsOneWay = true)]
    void Update(string someStateInfo);
}

public class LongRunningService : ILongRunningService
{
    public void StartLongRunningProcess(string initialParameter)
    {
        // Get hold of the callback channel and call it once a second
        // five times - you can do anything here - create a thread,
        // start a timer, whatever, you just need to get the callback
        // channel so that you have some way of contacting the client
        // when you want to update it
        var callback = OperationContext
            .Current
            .GetCallbackChannel<ICallback>();

        ThreadPool
            .QueueUserWorkItem(o =>
                                   {
                                       for (int i = 0; i < 5; i++)
                                       {
                                           callback.Update("Step " + i);
                                           Thread.Sleep(1000);
                                       }
                                   });
    }
}

然后你需要一个包含它的svc文件(将service属性调整为你的服务实现类):

<%@ ServiceHost Service="SilverlightApplication.Web.LongRunningService" %>

最后,您将需要在web.config中进行此配置(这在配置根元素内部):

<system.serviceModel>
  <extensions>
    <bindingExtensions>
      <add name=
        "pollingDuplexHttpBinding"
          type="System.ServiceModel.Configuration.PollingDuplexHttpBindingCollectionElement,System.ServiceModel.PollingDuplex, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </bindingExtensions>
  </extensions>
  <services>
    <service name="SilverlightApplication.Web.LongRunningService">
      <endpoint
         address=""
         binding="pollingDuplexHttpBinding"
         bindingConfiguration="multipleMessagesPerPollPollingDuplexHttpBinding"
         contract="SilverlightApplication.Web.ILongRunningService">
      </endpoint>
      <endpoint
          address="mex"
          binding="mexHttpBinding"
          contract="IMetadataExchange"/>
    </service>        
  </services>
  <bindings>
    <pollingDuplexHttpBinding>
      <binding name="multipleMessagesPerPollPollingDuplexHttpBinding"
               duplexMode="MultipleMessagesPerPoll"
               maxOutputDelay="00:00:07"/>
    </pollingDuplexHttpBinding>        
  </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="">
                <serviceMetadata httpGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>

重要的部分是服务元素上的名称属性和端点元素上的合同属性。它们应该是您定义的类和接口(使用命名空间)。

重要您需要添加对C:\ Program Files(x86)\ Microsoft SDKs \ Silverlight \ v4.0 \ Libraries \ 服务器 \ System的引用。 ServiceModel.PollingDuplex.dll程序集(删除x86,如果不是64位操作系统)到Web应用程序项目。

Silverlight应用程序

您首先需要为您创建的服务添加服务引用,然后,假设您想从一个按钮调用该服务,您将拥有以下代码:

private void button1_Click(object sender, RoutedEventArgs e)
{            
    // Create the client proxy with the URL of the service
    var proxy = new LongRunningServiceClient(
        new PollingDuplexHttpBinding(
            PollingDuplexMode.MultipleMessagesPerPoll),
        new EndpointAddress(
            "http://localhost/WebApplication/LongRunningService.svc"));

    // Attach the handler to be called periodically and start the process
    proxy.UpdateReceived += Update;                        
    proxy.StartLongRunningProcessAsync("blah");
}

private void Update(object sender, UpdateReceivedEventArgs e)
{
    // Use the result from the e parameter here
}

重要您需要添加对C:\ Program Files(x86)\ Microsoft SDKs \ Silverlight \ v4.0 \ Libraries \ 客户端 \ System的引用。 ServiceModel.PollingDuplex.dll程序集(删除x86,如果不是64位操作系统)到silverlight客户端项目。

就是这样 - Update方法将被调用,在这种情况下每次调用一次。但你可以做任何你喜欢的事。

答案 1 :(得分:1)

由于它在服务器中的负载,我不建议使用轮询双工来解决此业务需求。我读到的是你需要将几个文件返回给客户端,并在下载文件时向客户端提供反馈。

由于下载文件似乎不是一个问题(应该是一个流),我想你问的是如何在下载文件的同时更新UI,或许可以捕获文件的实际数量被下载。至少,您应该在每个文件到达时更新UI。

后者很简单,只需将下载链接下载到客户端上的每个文件,逐个执行,并在文件下载之间更新UI。那将是single threaded approach

在后台线程执行时更新UI是一种更复杂的方法,但是更好的实现方式,因为客户端感觉&#34;他们在下载文件时仍然处于控制之中。这是downloading a file async的方法。

请记住,在SilverLight中,您实际上只有HTTP将信息传输到应用程序,而不能进行双工。 HTTP长池实现了相同的结果,但连接处于打开状态,并且极大地降低了扩展能力。

相关问题