WCF возвращает результаты нескольких функций асинхронно? - PullRequest
0 голосов
/ 21 декабря 2011

Я читал о том, как это сделать, но мне тяжело разобраться с этим.

Синхронные и асинхронные операции

WCF: Работа с односторонними вызовами, обратными вызовами, An ...

Моя цель - возвращать результаты нескольких функций в службе WCF с поддержкой Silverlight по мере их обнаружения.

Общий обзор того, как эта служба должна работать, выглядит следующим образом.

Пользователь вводит URL, в котором много гиперссылок, перечисленных в гиперссылках. Служба получает начальный URL, введенный пользователем, выполняет веб-запрос этого URL, получает имена файлов 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 ]

2 голосов
/ 22 декабря 2011

Я думаю, что вам, вероятно, понадобится «опрос дуплексного http-сервиса» - это означает, что WCF подделает для вас сервис дуплексного стиля (путем опроса).Преимущество дуплексного сервиса по сравнению с обычным асинхронным сервисом заключается в том, что его легко перезванивать клиенту несколько раз (поэтому вы можете предоставить отзыв о ходе выполнения вашей задачи).

Это очень легко реализовать,Допустим, у вас есть два проекта: веб-приложение и приложение silverlight ...

Веб-приложение

Создайте свой сервис, например:

[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>

Важными частями являются атрибут name в элементе service и атрибут contract в конечной точке элемент.Это должны быть класс и интерфейс, который вы определили (с пространством имен).

ВАЖНО Необходимо добавить ссылку на C: \ Program Files (x86) \ Microsoft SDKs \ Silverlight \v4.0 \ Libraries \ Сервер \ System.ServiceModel.PollingDuplex.dll сборка (удалить 64-разрядную ОС, если не 64-разрядную) для проекта веб-приложения.

Приложение 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 голос
/ 22 декабря 2011

Я бы НЕ рекомендовал использовать дуплекс опроса для решения этого бизнес-требования из-за нагрузки, которую он размещает на сервере. Я прочитал, что вам необходимо вернуть клиенту несколько файлов и предоставить клиенту обратную связь по мере их загрузки.

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

Последнее легко: просто загрузите ссылки для загрузки каждого файла на клиенте, сделайте их одну за другой и обновите пользовательский интерфейс между загрузками файлов. Это был бы однопоточный подход .

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

Помните, в SilverLight у вас действительно есть только HTTP для передачи информации в приложение, которое не может выполнять дуплекс. Длинный пул HTTP достигает того же результата, но соединения остаются открытыми, что значительно снижает возможность масштабирования.

...