我一直在阅读如何做到这一点,但我很难理解它。
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
的反馈,然后继续服务。
万分感谢您的帮助。
答案 0 :(得分:2)
我认为您可能需要的是“轮询双工http服务” - 这意味着WCF将为您伪造双工式服务(通过轮询)。与常规异步服务相比,双工服务的优势在于可以轻松地多次回调客户端(因此您可以提供有关任务进度的反馈)。
实施起来非常容易。假设您有两个项目,一个Web应用程序和一个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>
重要的部分是服务元素上的名称属性和端点元素上的合同属性。它们应该是您定义的类和接口(使用命名空间)。
重要您需要添加对C:\ Program Files(x86)\ Microsoft SDKs \ Silverlight \ v4.0 \ Libraries \ 服务器 \ System的引用。 ServiceModel.PollingDuplex.dll程序集(删除x86,如果不是64位操作系统)到Web应用程序项目。
您首先需要为您创建的服务添加服务引用,然后,假设您想从一个按钮调用该服务,您将拥有以下代码:
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长池实现了相同的结果,但连接处于打开状态,并且极大地降低了扩展能力。