简体   繁体   English

C#中的多级异步方法调用模式

[英]Multilevel asynchronous method call pattern in c#

I have design problem regarding async calls to method. 我有关于方法异步调用的设计问题。

I'd like to know best/good pattern to call async method, which calls another async method, which calls another async method :) 我想知道最好/好的模式来调用异步方法,该方法调用另一个异步方法,该方法调用另一个异步方法:)

In other words, I have WCF service reference created with async methods and I want to call them from another async method which is called by other async method. 换句话说,我有使用异步方法创建的WCF服务引用,并且我想从另一个异步方法调用它们,而该异步方法由其他异步方法调用。 All this for non blocking GUI. 所有这些都是为了实现非阻塞的GUI。

Thanks! 谢谢!

If your only goal is to have a non blocking GUI then the multiple levels are unnecessary. 如果您的唯一目标是拥有不阻塞的GUI,则不需要多个级别。 Once your toplevel method runs in the background, your GUI is freed. 一旦您的顶级方法在后台运行,您的GUI将被释放。 Using multiple levels does bring extra complexity. 使用多个级别确实带来了额外的复杂性。

There can be other reasons (performance) to call the lower level methods async, but it depends. 调用低级方法异步可能还有其他原因(性能),但这要视情况而定。 Do you need to wait for results later on? 您是否需要稍后再等待结果?

So I don't think there is a 'pattern' here. 因此,我认为这里没有“模式”。

I recently developed implementation of ADFS attribute store that calls into backend web service to retrieve data. 我最近开发了ADFS属性存储的实现,该实现调用后端Web服务来检索数据。 I wanted to follow factory -> client approach rather than reusing client for each call, so I ended up in 2 level async calls as illustrated in simplified code sample below: 我想遵循工厂->客户端方法,而不是为每个调用重用客户端,因此我最终遇到了2级异步调用,如下面的简化代码示例所示:

public class IMyAttributeStore : IAttributeStore
{
    ChannelFactory<IMyBackendInterface> factory;
    public IMyAttributeStore()
    {
    }

    public IAsyncResult BeginExecuteQuery(string query, string[] parameters, AsyncCallback callback, object state)
    {
        AsyncResult queryResult = new TypedAsyncResult<string[][]>(callback, state);
        var client = factory.CreateChannel();
        CallState cs = new CallState(client, queryResult);

        Request rq = new Request();

        client.BeginGetUserRoles(rq, new AsyncCallback(AsyncCallCallback), cs);

        return cs.result;
    }

    public string[][] EndExecuteQuery(IAsyncResult result)
    {
        return TypedAsyncResult<string[][]>.End(result);
    }

    // Initialize state here.
    public void Initialize(Dictionary<string, string> config)
    {
        var endpoint = config["endpointConfigurationName"];
        factory = new ChannelFactory<IMyBackendInterface>(endpoint);
    }

    void AsyncCallCallback(IAsyncResult result)
    {
        CallState cs = (CallState)result.AsyncState;

        Response data = cs.client.EndGetUserRoles(result);
        List<string[]> claimData = new List<string[]>();
        foreach (var val in data.Values)
            claimData.Add(new string[1] { val });
        string[][] retVal = claimData.ToArray();

        TypedAsyncResult<string[][]> queryResult = (TypedAsyncResult<string[][]>)cs.result;
        queryResult.Complete(retVal, false);
    }
}

class CallState
{
    public IMyBackendInterface client;
    public AsyncResult result;

    public CallState(IMyBackendInterface c, AsyncResult r)
    {
        client = c;
        result = r;
    }
}

Wondering if this is a good pattern to follow, or someone found out better one meanwhile? 想知道这是一个好的模式,还是有人发现了更好的模式?

One example of when it would be good to have multiple levels would be when creating asynchronous controllers in a MVC framework like MonoRail or MS MVC. 最好具有多个级别的一个示例是在诸如MonoRail或MS MVC的MVC框架中创建异步控制器时。 The end thing that calls into something IO-blocking, such as SqlCommand from System.Data.SqlClient or some socket, would put the IO operand on an IO completion port: http://msdn.microsoft.com/library/aa365198 , which would save the managed/unmanaged thread's quanta for something more useful. 调用IO阻塞的最终内容(例如来自System.Data.SqlClient的SqlCommand或某些套接字)会将IO操作数放在IO完成端口上: http : //msdn.microsoft.com/library/aa365198 ,将保存托管/非托管线程的量子,以获取更多有用的信息。

If you write classes that return IAsyncResult, then you are not far away from implementing co-routines. 如果编写返回IAsyncResult的类,那么您就离实现协同例程不远了。 Here's a good article about how asynchronous programming can be used with coroutines: http://blogs.msdn.com/b/pfxteam/archive/2009/06/30/9809774.aspx . 这是一篇有关如何将协程程序与异步编程一起使用的好文章: http : //blogs.msdn.com/b/pfxteam/archive/2009/06/30/9809774.aspx

Caliburn, a WPF framework supports co-routines natively. Caliburn是一个WPF框架,它本地支持协同例程。 The task parallel library, released with .Net 4, has given its task the IAsyncResult interface. 与.Net 4一起发布的任务并行库已为其任务提供IAsyncResult接口。 [If you are at 3.5 then you might need to create your own implementation (they are pretty simple to make, just implement the interface).] Co-routines are a way of using the compiler re-writes of IEnumerable to push IAsyncResults to a stack of things to do (as seen from the "async manager"). [如果您是3.5岁,则可能需要创建自己的实现(它们非常简单,只需实现接口即可。)协程是使用IEnumerable编译器重写将IAsyncResults推送到一堆要做的事情(从“异步管理器”中可以看到)。

F# async (like seen in the down-voted answer) uses a monad (as monadic as they get on the CLR) to move the state of the asynchronous request from the Begin* to End* methods. F#异步(如投票否定的答案所示)使用monad(与CLR上的monad一样)将异步请求的状态从Begin *方法移动到End *方法。 The compilers both this into nested lambda expressions/SelectMany. 编译器都将其编译为嵌套的lambda表达式/ SelectMany。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM