Fire and Forget (异步) ASP.NET 方法调用

7
我们有一个服务,可以将客户信息更新到服务器。每次服务调用正常情况下需要几秒钟的时间。
现在我们有一个新页面,一个实例可以同时更新大约35-50个客户的信息。在这个阶段改变服务接口来接受所有客户是不可能的。
我需要调用一个方法(比如“ProcessCustomerInfo”),该方法将循环遍历客户信息并调用Web服务35-50次。异步调用服务没有太多意义。
我需要异步地调用方法“ProcessCustomerInfo”。我正试图使用RegisterAsyncTask来实现。网上有各种各样的例子,但问题是,一旦启动此调用,如果我离开这个页面,处理就会停止。
是否可能实现“Fire and Forget”方法调用,以便用户可以从页面移开(重定向到另一个页面)而不停止方法处理?
5个回答

8

关于: http://www.codeproject.com/KB/cs/AsyncMethodInvocation.aspx 的详细信息:

基本上,您可以创建一个指向要异步运行的方法的委托,然后使用BeginInvoke启动它。

// Declare the delegate - name it whatever you would like
public delegate void ProcessCustomerInfoDelegate();

// Instantiate the delegate and kick it off with BeginInvoke
ProcessCustomerInfoDelegate d = new ProcessCustomerInfoDelegate(ProcessCustomerInfo); 
simpleDelegate.BeginInvoke(null, null);

// The method which will run Asynchronously
void ProcessCustomerInfo()
{
   // this is where you can call your webservice 50 times
}

谢谢Joel!我之前看到过这个方法,但当时忽略了它,因为MethodInvoker是System.Windows.Form的一部分。尽管我需要进行更多测试,但似乎在重定向方面运行良好。但是,我应该在ASP.NET中使用这种方法吗?还是有任何Web替代方法? - BinaryHacker
哦,是的,对不起。它在ASP.NET中可以正常工作,但如果您不必要包含System.Windows.Form在您的项目中,那将是一件遗憾的事情。相反,您可以创建自己的委托并使用它来代替MethodInvoker。我已经更新了上面的代码示例。 - Joel Beckham
1
MethodInvoke只是一个已经为您创建的委托,没有参数或返回值,因此您不必花时间创建自己的委托。我们刚刚创建的ProcessCustomerInfoDelegate也是完全相同的方式工作。 - Joel Beckham
2
有关调用BeginInvoke而不调用EndInvoke是否是一个坏主意的讨论已经存在了一段时间 - 主要是因为在某些委托上不调用EndInvoke操作可能会导致内存泄漏。我可以建议使用ThreadPool.QueueUserWorkItem(cb=>ProcessCustomerInfo())来代替。 - Chris

4

这只是我为了做这件事而匆忙制作的...


    public class DoAsAsync
    {
        private Action action;
        private bool ended;

        public DoAsAsync(Action action)
        {
            this.action = action;
        }

        public void Execute()
        {
            action.BeginInvoke(new AsyncCallback(End), null);
        }

        private void End(IAsyncResult result)
        {
            if (ended)
                return;

            try
            {
                ((Action)((AsyncResult)result).AsyncDelegate).EndInvoke(result);
            }
            catch
            {
                /* do something */
            }
            finally
            {
                ended = true;
            }
        }
    }

接着,

    new DoAsAsync(ProcessCustomerInfo).Execute();

还需要在页面指令中设置Async属性 <%@ Page Async="true" %>

我不确定这个方法的可靠性,但它对我所需的功能有效。我大约一年前写的。


我真的很喜欢这个解决方案。自从你似乎已经使用它一段时间以来,是否有任何更新或新发现的难点呢? - John Livermore
我不记得有任何问题。当这个答案已经在生产中使用时,它仍然存在。/耸肩 - David

0

我认为问题在于您的Web服务期望客户端返回响应,而服务调用本身不是单向通信。

如果您正在使用WCF进行Web服务,请查看http://moustafa-arafa.blogspot.com/2007/08/oneway-operation-in-wcf.html以进行单向服务调用。

我的建议:在我看来,无论谁告诉您不能更改服务接口以添加新的服务方法,都是在提出不合理的要求。即使您的服务是公共API,添加新的服务方法也不应影响任何现有的消费者。


问题不在于无法从服务中获取响应,而是需要调用服务50次。单向调用服务对我没有帮助,我需要找到一种调用实际进行服务调用的方法......更改接口是一个问题,因为这个服务是由另一个供应商提供的,并且他们目前不愿意更改它。 - BinaryHacker
单向服务调用可以解决您的问题,您不需要将它们全部异步地解雇,因为它们会打开请求、发送数据并关闭连接,这样当您点击提交或者页面执行其他操作时,它只需要在一秒钟内完成即可。但是,如果您不拥有该服务,则无法将其更改为单向。 - Chris Marisic

0

谢谢。这是我目前正在尝试的方法。但问题在于电影已经离开了页面。如果用户单击任何链接以转到另一页,则异步处理也会停止。 - BinaryHacker
@ExpertSoul - 看起来异步处理在您更改页面时停止的可能性不大,因为根据Restuta提供的文档,异步任务必须在页面呈现之前(在传递给浏览器之前)完成。您是否记得添加了一个带有Async="true"属性的Page指令或将Page的AsyncMode属性设置为"true"?有些事情告诉我您的异步任务可能根本没有执行。 - Chris Shouts
@paper1337 - 我再次验证了一下。使用重定向语句时,“OnBegin”方法被调用,但操作超时后会返回到页面。但是,“OnBegin”会一直处理到结束。使用重定向语句(我在异步方法调用之后放置)时,“OnBegin”永远不会被调用。此外,虽然到处都提到要指定属性Async="true",但我没有看到有或没有它的处理有任何区别。 - BinaryHacker

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接