WCF REST service blocks a thread on call using AJAX on ASP.Net

I have a WCF REST service consumed on an ASP.Net site from a page using AJAX.

I want to be able to call methods from my async service, which means that I will have callback handlers in my javascript code, and when the methods end, the output will be updated. Methods must run in different threads, because each method will take a different time to complete its task.

My code is semi-working, but something strange happens, because when I execute the code for the first time after compilation, it works by launching each call in different threads, but subsequent calls block the service so that every method call should wait end the last call to complete the next one. And they work on the same topic. I used to have the same problem when I used the page methods, and I solved it by disconnecting the session on the page, but I did not understand how to do this when using WCF REST services

Note. Full time methods (it takes only 7 seconds to start them async , and the result should be: Execute1 - Execute3 - Execute2 )

  • Execute1 β†’ 2 sec
  • Execute2 β†’ 7 seconds
  • Execute3 β†’ 4 sec

Exit After Compilation

after compiling

( )

subsequent calls

... ,

[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);

.... ( ) , , , ....

-, , , , , weren ' t - -

2

(RestWCF.zip)

http://sdrv.ms/P9wW6D

+5
4

, . , web.config:

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

, , Asp.Net(, WCF).

Fiddler , WCF cookie ASP.NET_SessionId. Page EnableSessionState="False" .

EDIT. , , , . . :

  • "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- , , cookie ASP.NET_SessionId, . Application_PostAcquireRequestState , .

:

  • Parallell
  • .

:

  • URL, cookie
  • .
+9

ReadOnly, SessionStateBehavior svc Global.asax.cs. .

protected void Application_BeginRequest(object sender, EventArgs e) {
   if (Request.Path.Contains("AjaxTestWCFService.svc")) {
      HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.ReadOnly);
   }
}

, , SessionStateBehavior.ReadOnly . null.

+4

, ConcurrencyMode Multiple, , :

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(
    InstanceContextMode = InstanceContextMode.PerCall,
    ConcurrencyMode = ConcurrencyMode.Multiple
)]
public class MyService : IMyService
{

}

-1

Reactive, - , .

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());
}

Thread.Sleep , First(). First() , Thread.Sleep(2000). . , , , .

ConcurrencyMode=ConcurrencyMode.Multiple, , . , ASP.Net Development Server, , , . IIS?

, , t.Take(1) .

. web.config aspNetCompatibilityEnabled="true". , . ( = false), . . false , , HttpContext ASP.NET.

** Further update ** If you disable aspNetCompatibilityEnabled, you will not be able to use routing. I tried several combinations, including various bindings and transferMode options, and they trick you into showing that they work for a while, and then return to using the same stream. I also checked work flows and ran out of ideas.

-1
source

All Articles