当前位置: 首页 > 面试题库 >

REST WCF服务在ASP.Net站点中使用AJAX调用时锁定线程

云凌
2023-03-14
问题内容

我使用AJAX从ASP.Net网站的页面中使用了WCF REST服务。

我希望能够从服务异步中调用方法,这意味着我将在JavaScript代码中包含回调处理程序,并且当方法完成时,输出将被更新。这些方法应在不同的线程中运行,因为每种方法将花费不同的时间来完成其任务

我的代码无法正常工作,但是发生了一些奇怪的事情,因为 在编译后 第一次执行代码时 ,它可以正常工作在不同的线程中运行每个调用,
但随后的调用将服务以一种使每个方法调用具有等待直到最后一个调用结束才能执行下一个。它们在同一线程上运行。在使用 Page Methods
之前,我曾遇到过同样的问题,我通过禁用页面中的会话来解决此问题,但是我没有弄清楚在使用WCF REST服务时该如何做。

注意:方法完成时间(异步运行它们仅需 7秒 ,结果应为: Execute1-Execute3-Execute2

  • Execute1 -> 2秒
  • Execute2 -> 7秒
  • Execute3 -> 4秒

编译后输出

编译后

输出后续调用(这是问题)

后续通话

我将发布代码…我将尽力简化它

服务合约

[ServiceContract(
    SessionMode = SessionMode.NotAllowed
)]
public interface IMyService
{
    // I have other 3 methods like these: Execute2 and Execute3
    [OperationContract]
    [WebInvoke(
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,
        UriTemplate = "/Execute1",
        Method = "POST")]
    string Execute1(string param);
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(
    InstanceContextMode = InstanceContextMode.PerCall
)]
public class MyService : IMyService
{
    // I have other 3 methods like these: Execute2 (7 sec) and Execute3(4 sec)
    public string Execute1(string param)
    {
        var t = Observable.Start(() => Thread.Sleep(2000), Scheduler.NewThread);
        t.First();

        return string.Format("Execute1 on: {0} count: {1} at: {2} thread: {3}", param, "0", DateTime.Now.ToString(), Thread.CurrentThread.ManagedThreadId.ToString());
    }
 }

ASPX页面

<%@ Page EnableSessionState="False" Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="RestService._Default" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script type="text/javascript">
        function callMethodAsync(url, data) {
            $("#message").append("<br/>" + new Date());
            $.ajax({
                cache: false,
                type: "POST",
                async: true,
                url: url,
                data: '"de"',
                contentType: "application/json",
                dataType: "json",
                success: function (msg) {
                    $("#message").append("<br/>&nbsp;&nbsp;&nbsp;" + msg);
                },
                error: function (xhr) {
                    alert(xhr.responseText);
                }
            });
        }
        $(function () {
            $("#callMany").click(function () {
                $("#message").html("");
                callMethodAsync("/Execute1", "hello");
                callMethodAsync("/Execute2", "crazy");
                callMethodAsync("/Execute3", "world");
            });
        });
    </script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <input type="button" id="callMany" value="Post Many" />
    <div id="message">
    </div>
</asp:Content>

Web.config(相关)

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true" />
      </webHttpEndpoint>
    </standardEndpoints>
  </system.serviceModel>

Global.asax

    void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.Ignore("{resource}.axd/{*pathInfo}");
        RouteTable.Routes.Add(new ServiceRoute("", 
          new WebServiceHostFactory(), 
          typeof(MyService)));
    }

编辑1

我尝试了几种组合,但是结果是相同的,我使用Visual Studio进行了测试,但是现在我在IIS 7上进行了测试,结果是相同的

我尝试了以下属性的组合:

[ServiceBehavior(
    InstanceContextMode = InstanceContextMode.PerCall,
    ConcurrencyMode = ConcurrencyMode.Multiple
)]

我也删除了Rx的使用,现在我只是在模拟长过程操作,如下所示:

Thread.Sleep(2000);

但是结果是相同的。…
编译并部署(第一个调用)服务后,该服务正常工作,该服务在不同的线程上执行,从而提供了所需的结果,但随后的调用在同一线程上运行。不明白

我只是在编译工作后的第一时间注意到了什么, 最后使用
的线程始终是后续调用中使用的线程,并且该线程被阻塞,这就像是否未处理其他线程或某些东西,或者如果最后一个线程是由于某种原因被封锁

编辑2

这是该项目的完整代码(RestWCF.zip)

http://sdrv.ms/P9wW6D


问题答案:

下载了您的源代码以自行进行一些测试。我设法通过将其添加到web.config中使其工作:

<sessionState mode="Off"></sessionState>

该问题似乎与Asp.Net会话处理有关(似乎与WCF会话不同)。

没有这个,Fiddler将显示WCF服务响应正在发送ASP.NET_SessionIdcookie。您的Page等级EnableSessionState="False"不会影响服务。

编辑 :我做了一些更多的测试,看看是否可以使它工作而不必关闭整个应用程序的会话状态。我现在开始工作了。我所做的是:

  • 在应用程序的根目录下创建一个新文件夹“ ServiceFolder”
  • 将服务接口和实现移至该文件夹

然后在Global.asax我更改了ServiceRoute注册:

RouteTable.Routes.Add(new ServiceRoute("ServiceFolder/",
    new WebServiceHostFactory(),
    typeof(MyService)));

在Default.aspx中,我更改了:

$(function () {
    $("#callMany").click(function () {
        $("#message").html("");
        callMethodAsync('<%=this.ResolveUrl("~/ServiceFolder/Execute1") %>', "hello");
        callMethodAsync('<%=this.ResolveUrl("~/ServiceFolder/Execute2") %>', "crazy");
        callMethodAsync('<%=this.ResolveUrl("~/ServiceFolder/Execute3") %>', "world");
    });
});

然后,为了控制Cookie的处理,我创建了一个HttpModule

using System;
using System.Web;

namespace RestService
{
    public class TestPreventCookie : IHttpModule
    {
        public void Dispose()
        {
        }
        public void Init(HttpApplication application)
        {
            application.BeginRequest +=
                (new EventHandler(this.Application_BeginRequest));
            application.PostAcquireRequestState +=
                (new EventHandler(this.Application_PostAcquireRequestState));

        }
        private void Application_BeginRequest(Object source, EventArgs e)
        {
            //prevent session cookie from reaching the service
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            if (context.Request.Path.StartsWith("/ServiceFolder"))
            {
                context.Request.Cookies.Remove("ASP.NET_SessionId");
            }
        }
        private void Application_PostAcquireRequestState(Object source, EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            if (context.Request.Path.StartsWith("/ServiceFolder"))
            {
                var s = context.Session;
                if (s != null)
                    s.Abandon();
            }
        }
    }
}

然后我在web.config中注册了该模块:

<httpModules>
    <add name="TestPreventCookie" type="RestService.TestPreventCookie" />
</httpModules>

最后,我将Default.aspx更改为允许会话:

EnableSessionState="True"

这些更改之后,并行执行服务调用。强制性免责声明:

它可以在我的机器上工作

这个想法是当对服务的调用进入时,HttpModule会检查URL,并在必要时删除ASP.NET_SessionIdcookie,以使其无法到达服务。然后,Application_PostAcquireRequestState我们立即放弃创建的会话,这样就不必在大量空会话中不必要地消耗服务器内存。

使用此解决方案,您将获得:

  • 并行执行服务调用
  • 您仍然可以在应用程序的其他部分使用Session

以:

  • 但是您必须在不需要会话cookie的可识别URL上调用服务
  • 服务器将创建并放弃很多会话


 类似资料:
  • 问题内容: 现在,我试图调用已在ASP.NET MVC应用程序(即)中定义的启用AJAX的Web服务。但是该服务从未在我的javascript函数中调用。 如果我在非ASP.NET MVC应用程序中尝试该调用AJAX Web服务的相同技术,则可以正常工作,因此它使我怀疑ASP MVC路由在尝试进行AJAX Web服务调用时是否会以某种方式干扰事物。 您是否知道为什么没有调用我的Web服务?下面的代

  • 问题内容: 我将登录信息从jQuery AJAX调用发送到MVC 4控制器: 如果登录成功,我想根据用户类型将用户从服务器端重定向到适当的页面。如果登录失败,则会将字符串发送回用户: 但是有问题: 如果此方法返回“ ActionResult”,那么我将收到错误消息。 如果我使用“ void”,则无法返回任何内容。 即使我使用“ void”且没有返回值,由于jQuery AJAX调用的异步特性,我也

  • 我有一个Micronaut服务,它是使用jQuery中实现的AJAX调用从客户端调用的。Micronaut服务如下所示: 调用micronaut服务的Javascript如下: 不幸的是,尽管我告诉服务器和客户机处理纯文本,但AJAX调用失败,出现以下消息: 我是在Micronaut的控制器处理程序中发现了一个bug,还是在客户机或服务器代码中丢失了什么?有什么方法让这个AJAX调用工作吗? 更新

  • 问题内容: 我有一个现有的jQuery插件,可以进行很多AJAX调用(主要是JSON)。我想知道最快允许它进行跨站点调用的方法,即$ .get和$ .post URL不会来自同一域。 我听说过JSONP,但是想知道是否有人可以给我一个具体的例子来介绍整个过程。如果可能,我希望对脚本进行最少的更改。我应该使用某种proxy.php吗? 感谢您的时间。 问题答案: JSONP将允许您进行跨站点调用。请

  • 问题内容: 如何在ASP.net应用程序的服务器端检测请求是否为AJAX请求(来自jQuery)。我不想这样做:mypage.aspx?this_is_ajax = true … 例如 在服务器端,当请求是ajax请求时,我想做某些事情… 谢谢! 问题答案: ASP.NET MVC对此做了很大的扩展,可以与JQuery一起使用。它以这种方式检查它: 检查核心集合: 检查标头集合(确保其不为null

  • 问题内容: 我在aspx上有一个asp按钮: 如您所见,我正在调用一个使用AJAX调用C#方法的javascript函数。我这样做: 问题是,单击按钮时,我总是收到错误消息。我做错什么了吗? 编辑:C#方法。我已经设置了一个断点,以查看是否调用了该方法,但显然没有。 问题答案: 您的方法必须声明为,并用修饰。因此,您的方法应为: 编辑!!! 我看你用一些控制在你的代码(如,)。完成方法后,您将无法