调用webservice异步

时间:2010-08-31 19:22:30

标签: c# asp.net multithreading asynchronous

很长的帖子..抱歉

我一直在阅读这篇文章并在几天内用不同的解决方案来回尝试,但我找不到最困难的选择。

关于我的情况;我向用户呈现一个页面,其中包含几个不同的中继器,根据几个webservice调用的结果显示一些信息。我想用updatepanel引入数据(这将每两到三秒查询一次结果表,直到找到结果为止)所以我实际上想要渲染页面然后当数据是“准备好“它显示出来。

该页面要求控制器提供要呈现的信息,并且控制器检查结果表以查看是否有任何可以找到的内容。如果未找到特定数据,则会在WebServiceName.cs中调用方法GetData()。 GetData不会返回任何内容,但应该启动从Web服务获取数据的异步操作。控制器返回null,UpdatePanel等待下一个查询。

当该操作完成时,它会将数据存储在数据库的相关位置,控制器将在下次页面请求时找到它。

我现在的解决方案是启动另一个线程。我将在共享的网络服务器上托管页面,我不知道这是否会导致任何问题..

所以当前代码驻留在page.aspx:

Thread t = new Thread(new ThreadStart(CreateService));
        t.Start();
    }

    void CreateService()
    {
        ServiceName serviceName = new ServiceName(user, "12345", "MOVING", "Apartment", "5100", "0", "72", "Bill", "rate_total", "1", "103", "serviceHost", "password");

    }

起初我认为解决方案是使用Begin [Method]和End [Method],但这些似乎没有生成。我认为这似乎是一个很好的解决方案,所以当他们没有出现时我有点沮丧..我有可能在添加网络参考时错过了一个复选框或其他东西吗?

我不想使用[Method] Async,因为这会阻止页面呈现,直到从我理解的方式调用[Method] AsyncCompleted。

我要做的调用不是CPU密集型的,我只是在等待一个位于慢速服务器上的webService,所以我从这篇文章中理解:http://msdn.microsoft.com/en-us/magazine/cc164128.aspx使线程池更大不是一个选择,因为这实际上会影响性能(因为我不能投入大量的硬件)。

您认为对我目前的情况最好的解决方案是什么?我真的不喜欢现在的那种(只有通过直觉但无论如何)

感谢您阅读这篇非常长篇文章..

4 个答案:

答案 0 :(得分:2)

有趣。在您提出问题之前,我不知道在添加网络引用时,VS已从使用Begin / End更改为Async / Completed。我认为他们还会包含Begin / End,但显然他们没有。

您声明“GetData不返回任何内容,但应该启动从Web服务获取数据的异步操作”,因此我假设GetData实际阻塞,直到“异步操作”完成。否则,您可以同步调用它。

无论如何,有很简单的方法可以实现这一点(异步委托等),但它们为每个异步操作使用一个线程,但不会扩展。

Async / Completed阻止异步页面是正确的。 (旁注:我相信他们不会阻止同步页面 - 但我从未尝试过 - 所以如果你使用的是非异步页面,那么你可以尝试一下)。他们“阻止”异步页面的方法包含在SynchronizationContext中;特别是,每个异步页面都有一个挂起的操作计数,递增Async并在Completed之后递减。

你应该能够伪造这个数量(注意:我也没有试过这个;))。只需替换默认的SynchronizationContext,它会忽略计数:

var oldSyncContext = SynchronizationContext.Current;
try
{
  SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
  var serviceName = new ServiceName(..);
  // Note: MyMethodCompleted will be invoked in a ThreadPool thread
  //  but WITHOUT an associated ASP.NET page, so some global state
  //  might be missing. Be careful with what code goes in there...
  serviceName.MethodCompleted += MyMethodCompleted;
  serviceName.MethodAsync(..);
}
finally
{
  SynchronizationContext.SetSynchronizationContext(oldSyncContext);
}

我写了一个类来处理SynchronizationContext.Current库的临时替换using (new ScopedSynchronizationContext(new SynchronizationContext())) { var serviceName = new ServiceName(..); // Note: MyMethodCompleted will be invoked in a ThreadPool thread // but WITHOUT an associated ASP.NET page, so some global state // might be missing. Be careful with what code goes in there... serviceName.MethodCompleted += MyMethodCompleted; serviceName.MethodAsync(..); } 。使用该类可以将代码简化为:

{{1}}

此解决方案使用等待操作完成的线程。它只是注册一个回调并保持连接打开,直到响应到来。

答案 1 :(得分:1)

你可以这样做:

var action = new Action(CreateService);
action.BeginInvoke(action.EndInvoke, action);

或使用ThreadPool.QueueUserWorkItem

如果使用Thread,请务必设置IsBackground=true

http://consultingblogs.emc.com/jonathangeorge/archive/2009/09/10/make-methods-fire-and-forget-with-postsharp.aspx

上有一篇关于火灾和忘记线程的文章

答案 2 :(得分:1)

尝试使用以下设置

[WebMethod]
[SoapDocumentMethod(OneWay = true)]
void MyAsyncMethod(parameters)
{
}

在您的网络服务中

但是如果你使用假冒,请小心,我们有问题。

答案 3 :(得分:0)

我鼓励采用不同的方法 - 一种不使用更新面板的方法。更新面板需要加载整个页面,并通过网络传输 - 您只需要单个控件的内容。

考虑做一个稍微定制的&优化方法,使用MVC平台。您的数据流可能如下所示:

  1. 将原始请求发送到您的网页会产生一个消失的线程并使您的数据变暖。
  2. 将“骨架”页面返回给您的客户
  3. 在所述页面中,有一个javascript线程调用您的服务器询问数据。
  4. 使用MVC,让控制器操作返回局部视图,该视图仅限于您感兴趣的控件。
  5. 这将减少您的服务器负载(可以有退避算法),减少通过网络发送的信息量,并仍然为客户提供良好的体验。

相关问题