Сервисная операция требует выполнения транзакции - PullRequest
1 голос
/ 09 ноября 2009

У меня странная проблема с нашим сервисом WCF. Тот же код работал нормально до недавнего времени, мы добавили больше OperationContracts (веб-методы).

У нас общая трехуровневая архитектура.

  • DAL (WCF)
  • BLL
  • Веб-интерфейс

Вот мой быстрый пример кода:

DAL (WCF):

[ServiceContract]
interface IPerson
{
   [OperationContract]
   [TransactionFlow(TransactionFlowOption.Mandatory)]
   int AddPerson(Person p);
}


// AddPerson is implemented in the service
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public int AddPerson(Person p)
{
  // LINQ DataContext stuff goes here
}

BLL:

public class EmployeeBLL 
{
   public void AddNewEmployee(Person p)
   {
       using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required))
            {
                try
                {
                   PersonClient perClient = new PersonClient();
                   int personId = perClient.AddPerson(p);
                   ts.Complete();
                }
                catch (Exception ex)
                {
                   // Log exception
                }
                finally
                {
                    ts.Dispose();
                }
            }
            perClient.Close();
   }
}

Использование в веб-интерфейсе:

EmployeeBLL empBLL = new EmployeeBLL ()
empBLL.AddNewEmployee(person);

Я получаю сообщение «Для операции службы требуется выполнение транзакции». в моем BLL при попытке вызвать метод AddPerson в службе. Не так много удачи после включения трассировки в web.config.

Подробная трассировка стека:

Server stack trace: 
   at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

Конфигурация клиента:

<system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_IEmployee" closeTimeout="00:01:00"
              openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
              bypassProxyOnLocal="false" transactionFlow="true" hostNameComparisonMode="StrongWildcard"
              maxBufferPoolSize="524288" maxReceivedMessageSize="5000000"
              messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
              allowCookies="false">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
              maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <reliableSession ordered="true" inactivityTimeout="00:10:00"
              enabled="false" />
          <security mode="Message">
            <transport clientCredentialType="Windows" proxyCredentialType="None"
                realm="" />
            <message clientCredentialType="Windows" negotiateServiceCredential="true"
            algorithmSuite="Default" establishSecurityContext="true" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:2882/Test.svc"
          binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IEmployee"
          contract="Test.IEmployee" name="WSHttpBinding_IEmployee">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>
</system.serviceModel>

Ответы [ 4 ]

2 голосов
/ 11 декабря 2009

Я наконец понял это! Я вручную сгенерировал прокси-класс Service Reference и файл конфигурации с помощью инструмента svcutil и использовал его в BLL. Работал нормально!

VS версия: 2008

Служба WCF в BLL упоминалась как «Ссылка на службу». После обновления WCF «Ссылка на службу» в OperationContracts недавно добавленного ServiceContract в Reference.cs (прокси-класс) отсутствовал атрибут TransactionFlow. В основном это происходит после добавления новых ServiceContracts к услуге. Одна интересная вещь, замеченная, была, у app.config было <CustomBinding> для недавно добавленного ServiceContract вместо <wsHttpBinding>. Кажется, является проблемой, поскольку VS 2008 генерирует Service Reference.

1 голос
/ 09 ноября 2009

Проблема не в вашем сервисе, а в коде вашего клиента. Операция службы, как вы ее определили, требует, чтобы вы вызывали ее с уже запущенной транзакцией на стороне клиента. Находится ли звонок на стороне клиента внутри TransactionScope?

0 голосов
/ 28 декабря 2012

Вы должны добавить параметрactionFlow в конфигурацию клиента вручную, так как добавление прокси-службы путем добавления ссылки на службу не будет включать в себя атрибутactionFlow.
Это по замыслу. Так что даже когда вы добавляете trasactionFlow = true в сервисе, он будет ложным в конфигурации клиента, если вы добавите его, добавив ссылку на сервис.

Что вам нужно сделать, вы просто найдете атрибут TransactionsFlow и установите его true .

Три необходимых шага для выполнения транзакции
1. Пометьте контракт на обслуживание с атрибутом [Транзакция (TransactionFlowOption.Allowed)] * ​​1010 *
2. Добавьте поддержку трансактино в код, т. Е. Операцию, поэтому установите для свойства атрибута OperationBehaviour значение [OperationBehaviour (TransactionScopeRequired = true)] .
3. Добавьте привязку конфигурации с помощью TransactionFlow = true как на сервере, так и на клиенте.

0 голосов
/ 10 ноября 2009

Вы пробовали добавить

[OperationBehavior(TransactionScopeRequired=true)] 

о реализации договора?

Edit: Вы просто пытались восстановить клиентский прокси?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...