c# - WCF REST 不异步处理

标签 c# .net wcf rest asynchronous

我们目前正在为我们的站点在 IIS 中实现一个新的 WCF REST 服务,并且在许多页面上我们可能会使用 JQuery 异步进行一些 AJAX 调用。问题是 WCF(在服务器端)似乎正在同步执行。

在页面加载时,我们对 3 种不同的方法进行了 3 次单独调用。使用日志记录,我可以看到它们都在大约 5 毫秒内命中了 global.asax 文件。从那里,日志记录显示所有执行的顺序是它们退出 global.asax 的顺序(不一定是我们通过 javascript 从页面进行调用的顺序)。我希望每个调用都能收到自己的线程并单独返回。即使在附加调试器时,我也可以看到它不会执行下一个方法,直到我单步执行它打开的当前方法。

以下是我“认为”实现的使用异步模型的三种方法的操作契约。

    [OperationContract(AsyncPattern = true)]
    [WebInvoke(
        Method = "POST"
         , UriTemplate = "/ListUserPreferences"
        , BodyStyle = WebMessageBodyStyle.Wrapped
        , ResponseFormat = WebMessageFormat.Json
        , RequestFormat = WebMessageFormat.Json
    )]
    IAsyncResult BeginListUserPreferences(AsyncCallback callback, object state);
    Result<List<Data.EnumerationItem<UserPreferenceType>>> EndListUserPreferences(IAsyncResult asyncResult);

    [OperationContract(Name = "GetUserSecure", AsyncPattern = true)]
    [WebInvoke(
        Method = "POST"
         , UriTemplate = "/GetUser"
        , BodyStyle = WebMessageBodyStyle.Wrapped
        , ResponseFormat = WebMessageFormat.Json
        , RequestFormat = WebMessageFormat.Json
    )]
    IAsyncResult BeginGetUser(AsyncCallback callback, object state);
    Result<Data.User> EndGetUser(IAsyncResult asyncResult);

    [OperationContract(AsyncPattern = true)]
    [WebInvoke(
        Method = "POST"
         , UriTemplate = "/ListWithAttributes"
        , BodyStyle = WebMessageBodyStyle.Wrapped
        , ResponseFormat = WebMessageFormat.Json
        , RequestFormat = WebMessageFormat.Json
    )]
    IAsyncResult BeginListWithAttributes(int index, int pageSize, AsyncCallback callback, object state);
    Result<PagedCollection<Data.Attribute>> EndListWithAttributes(IAsyncResult asyncResult);

这是服务中实现之一的示例。

    public IAsyncResult BeginGetUser(AsyncCallback callback, object state)
    {
        var asyncResult = new CompletedAsyncResult<Result<Data.User>>(state);
        asyncResult.Result = new Result<Data.User>();

        asyncResult.Result.Value.UserId = Guid.Empty;
        asyncResult.Result.Value.DisplayName = "asdfasd";
        asyncResult.IsCompleted = true;           

        callback(asyncResult);

        return asyncResult;
    }

    public Result<Data.User> EndGetUser(IAsyncResult asyncResult)
    {
        return ((CompletedAsyncResult<Result<Data.User>>)asyncResult).Result;
    }

这是我们在服务实现类上的属性。

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]

任何人都可以提供一些关于为什么这些同步执行以及我需要做什么的见解,或者至少指出我需要做什么才能让它们异步执行的方向吗?

更新

我采纳了 Matt 的一些回答并将我的逻辑移至 End 函数调用,并关注了这篇关于他如何做到这一点的博文 Uploading Large Files To Self Hosted WCF Rest Service .但是,我无法使用他的技术调用 End 方法。我也开始认为我正在以错误的方式解决这个问题。因为查看日志,我的自定义身份验证服务在每次服务调用之前执行,这发生在任何异步方法操作甚至触发之前。经过进一步调查,我查看了进入 IIS 并执行操作的每个请求的 ThreadId。看来 WCF 只使用 1 个工作线程......期间。我一次向 IIS 发送多少请求并不重要。例如,如果我发送 3 个请求,我可以看到它们都在不同的时间(彼此相差几毫秒)进入,并且都有自己的线程。但似乎 WCF 只是将它们全部排队并按顺序执行它们,因为它们都在同一个线程上执行,包括身份验证服务调用。

最佳答案

在我看来,从您的示例来看,就像您在“开始”调用完成之前完成了所有工作;这是我在学习异步模式时发现的一个常见错误。

虽然我不熟悉它在 WCF 中的应用,但异步模型更典型的是一种 Begin 方法,该方法使用 IAsyncResult 对象启动一些新线程,该对象将由该新线程更新。要“完成”操作,当 IsCompleted 设置为 true 时,原始调用者应将原始 IAsyncResult 对象传回相应的对象返回结果的结束方法。一个简单的实现如下所示:

    static Func<string> getUser;
    public static IAsyncResult BeginGetUser(AsyncCallback callback, object state)
    {
        getUser = () =>
            {
                Thread.Sleep(2000);
                return "finished";
            };
        return getUser.BeginInvoke(callback, state);
    }

    public static string EndGetUser(IAsyncResult asyncResult)
    {
        return getUser.EndInvoke(asyncResult);
    }

对它的调用可能如下所示:

var result = BeginGetUser(null, null);
string value = EndGetUser(result);

当然,这是一个微不足道的案例:引用http://kennyw.com/work/indigo/258 , "如果你没有做一些“原生异步”的事情,那么你不应该使用 AsyncPattern=true。

幸运的是,随着 C# 5.0 或 Microsoft 发布的 Async CTP,.Net 异步模式可能会成为过去。

关于c# - WCF REST 不异步处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5959138/

相关文章:

每次调用时都会调用 WCF 服务类静态构造函数

c# - 绑定(bind)属性在更改时不更新

.net - 有关面向方面编程的帮助和信息

.net - 如何以编程方式更改端点的身份配置?

c# - 2 个 ObservableCollections 1 个组合框 WPF

c# - 在值后显示货币符号

wcf - WCF优质书籍推荐

c# - Asp net AJAX 在 MasterPage 中

C# 等待异步操作完成

c# - IRC聊天命令解析