很长的帖子..抱歉
我一直在阅读这篇文章并在几天内用不同的解决方案来回尝试,但我找不到最困难的选择。
关于我的情况;我向用户呈现一个页面,其中包含几个不同的中继器,根据几个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使线程池更大不是一个选择,因为这实际上会影响性能(因为我不能投入大量的硬件)。
您认为对我目前的情况最好的解决方案是什么?我真的不喜欢现在的那种(只有通过直觉但无论如何)
感谢您阅读这篇非常长篇文章..
答案 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
。
答案 2 :(得分:1)
尝试使用以下设置
[WebMethod]
[SoapDocumentMethod(OneWay = true)]
void MyAsyncMethod(parameters)
{
}
在您的网络服务中
但是如果你使用假冒,请小心,我们有问题。
答案 3 :(得分:0)
我鼓励采用不同的方法 - 一种不使用更新面板的方法。更新面板需要加载整个页面,并通过网络传输 - 您只需要单个控件的内容。
考虑做一个稍微定制的&优化方法,使用MVC平台。您的数据流可能如下所示:
这将减少您的服务器负载(可以有退避算法),减少通过网络发送的信息量,并仍然为客户提供良好的体验。