одновременная обработка звонков в WCF

Я новичок в .net и очень мало знаю о WCF, так что терпите меня, если зададут какие-нибудь глупые вопросы. Мне интересно, как WCF обрабатывает одновременные вызовы в сценарии SELF-HOST, если мой код явно не порождает какой-либо поток. Поэтому, много читая о stackoverflow, я создал тестовое приложение, но оно, похоже, не работает. Пожалуйста, порекомендуйте. Большое спасибо.

Пожалуйста, обрати внимание ...

  1. Мой вопрос касается только WCF САМОХОСТИНГА, поэтому, пожалуйста, не ссылайтесь на какие-либо связанные с IIS.
  2. Я использую webHttpBinding.
  3. Я понимаю, что есть настройки maxConnection и регулирования служб, но меня интересуют только 2 одновременных вызова в моих настройках исследования. Таким образом, не должно быть проблем с максимальным подключением или пулом потоков.
  4. Моя тестовая служба НЕ использует сеанс.

Код, как показано ниже ...

namespace myApp
{
  [ServiceContract(SessionMode = SessionMode.NotAllowed)]
  public interface ITestService
  {
    [OperationContract]
    [WebGet(UriTemplate="test?id={id}")]
    string Test(int id);
  }

  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, 
                   ConcurrencyMode = ConcurrencyMode.Multiple)]
  public class TestService : ITestService
  {
    private static ManualResetEvent done = new ManualResetEvent(false);

    public string Test(int id)
    {
      if (id == 1)
      {
        done.Reset();
        done.WaitOne();
      }
      else
      {
        done.Set();
      }
    }
  } 
}

app.config ...

  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name = "TestEndpointBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service name = "myApp.TestService">
        <endpoint address = "" behaviorConfiguration="TestEndpointBehavior"
                  binding = "webHttpBinding"
                  contract = "myApp.ITestService">
        </endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8080/test/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
  <system.web>
    <sessionState mode = "Off" />
  </system.web>

Как я тестировал ...

После запуска приложения я открыл свой браузер, на всякий случай FF сделал один вызов http: // localhost: 8080 / test / test? Id = 1. Этот запрос заставляет приложение приостановить ожидание сигнала, то есть WaitOne. Затем сделал еще один вызов на другой вкладке браузера по адресу http: // localhost: 8080 / test / test? Id = 2. Ожидается, что этот запрос установит сигнал, и, следовательно, сервер вернется для обоих запросов.

Но я увидел, что приложение зависло, и функция Test не была введена для второго запроса. Так что, по-видимому, мой код не поддерживает одновременные / одновременные вызовы. Ничего плохого?


person W Si    schedule 30.01.2012    source источник
comment
Вы пробовали устанавливать точки останова в отладчике?   -  person John Saunders    schedule 30.01.2012
comment
Службы WCF не имеют состояния, по крайней мере, так должно быть. Это заставило бы меня поверить, что у каждого вызова есть отдельный ManualResetEvent.   -  person cadrell0    schedule 30.01.2012
comment
@ cadrell0 этот парень private static ManualResetEvent done имеет область действия AppDomain. Он распределяется между потоками и контекстами. WCF может работать как без сохранения состояния, так и с сохранением состояния. Сеансы, создание экземпляров и параллелизм   -  person oleksii    schedule 31.01.2012
comment
@ Джон Сондерс: Да, конечно. У меня была точка останова в самой первой строке в функции Test, то есть if (id == 1), и точка останова была достигнута только один раз при первом запросе.   -  person W Si    schedule 01.02.2012
comment
@ cadre110 объект done используется совместно между потоками и контекстами. Это можно легко проверить, изменив его на список и поместив идентификатор в список. После нескольких вызовов мы видим, что в списке есть все идентификаторы, полученные от вызовов.   -  person W Si    schedule 01.02.2012
comment
Тогда что-то еще должно быть не так. Я предполагаю, что вы нажали F5, чтобы пройти через точку останова. Тогда что-то еще должно удерживать вашу службу от повторного вызова.   -  person John Saunders    schedule 01.02.2012
comment
Я скопировал ваш код в консольное приложение и не могу описать ваше поведение при блокировке. Пожалуйста, предоставьте полный образец кода   -  person Robert Slaney    schedule 09.03.2012
comment
Это не имеет значения, но вы можете попробовать сделать InstanceContextMode = InstanceContextMode.Single и удалить статическое событие ManualResetEvent. 1 экземпляр на ServiceHost с режимом контекста экземпляра = Single. Вы размещены на консоли? Вы ожидаете, что максимальное количество одновременных запросов составит всего 2 запроса? ServiceThrottlingBehavior.MaxConcurrentCalls делает именно это, если вы установите для него значение 2. Снова выполните отладку, выводите значения для запроса и используйте что-то вроде dbgView из sysinternals, чтобы проверить выходные значения, если он не запущен в отладчике.   -  person Sajay    schedule 29.03.2012
comment
Попробуйте установить для ServiceBehaviorAttribute.UseSynchronizationContext значение false.   -  person JohnC    schedule 03.04.2012


Ответы (1)


Вы можете использовать один класс для настройки службы wcf и удаления интерфейса. Вам также необходимо добавить файл global.asax. После того, как вы сделаете второй вызов, все они вернутся «готово».

Эта конфигурация делает то, что вы хотите. Создайте TestService.cs с помощью:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
             ConcurrencyMode = ConcurrencyMode.Multiple)]
[ServiceContract(SessionMode = SessionMode.NotAllowed)]
public class TestService
{
    private static ManualResetEvent done = new ManualResetEvent(false);

    [OperationContract]
    [WebGet(UriTemplate = "test?id={id}")]
    public string Test(int id)
    {
        if (id == 1)
        {
            done.Reset();
            done.WaitOne();
        }
        else
        {
            done.Set();
        }
        return "finished";
    }


}

web.config:

<configuration>
<system.web>
  <compilation debug="true" targetFramework="4.0" />
</system.web>
<system.webServer>
 <modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
<system.serviceModel>
<standardEndpoints>
<webHttpEndpoint>
    <!-- 
        Configure the WCF REST service base address via the global.asax.cs file and the default endpoint 
        via the attributes on the <standardEndpoint> element below
    -->
<standardEndpoint name="" helpEnabled="false"  >    </standardEndpoint>


  </webHttpEndpoint>
</standardEndpoints>
<behaviors>
  <serviceBehaviors>
    <behavior>

      <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
      <serviceMetadata httpGetEnabled="true" />
      <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
      <serviceDebug includeExceptionDetailInFaults="false" />
    </behavior>
  </serviceBehaviors>
</behaviors>

<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>

Файл Global.asax:

public class Global : System.Web.HttpApplication
{

    protected void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.Add(new ServiceRoute("testservice", new WebServiceHostFactory(), typeof(TestService)));
    }
}
person Omer Cansizoglu    schedule 03.04.2012