tags:

views:

233

answers:

3

I am facing strange issue with our WCF service. The same code was working fine until recently we added more OperationContracts(Web Methods).

We have common 3 tier architecture.

  • DAL (WCF)
  • BLL
  • Web UI

Here is my quick sample code:

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

Usage in Web UI:

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

I get "The service operation requires a transaction to be flowed." in my BLL when trying to call AddPerson method in service. Not much luck after enabling tracing in web.config.

Detailed Stack Trace:

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)

Client Configuration:

<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>
A: 

The problem is not in your service, but in your client code. The service operation as you've defined it requires that you call it with a transaction already started on the client side. Is the call on the client side inside a TransactionScope?

Drew Marsh
Yes. The client side call is inside TransactionScope.Pardon me for formatting. I should have wrapped code inside <code>. Please refer to edited question.
vm79
Ah, yeah that's much better, I see it now. Hmm... very interesting, not sure why it wouldn't be flowing either. Can you include your client configuration as well? The logging configuration is less important.
Drew Marsh
I just added my client configuration. The same code was working fine until recently we added more OperationContracts(Web Methods). Few folks suggested splitting service into multiple services but not exactly sure why that's required.Thanks for your time. Appreciate it.
vm79
Yeah, adding more operations really shouldn't impact the others unless other service level settings were changed at the same time. Hmm... client config looks fine to me. I'm not sure what's going on here. I'd personally be digging into the App_tracelog.svclog right about now looking for why WCF is rejecting the request.
Drew Marsh
I started digging into app_tracelog.svclog.- Sent a message over a channel (Successful)- Received a message over a channel (Successful) ... Identity verification succeeded. The security protocol verified the incoming messsage A message was read (Action: http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/transactions/fault) And then exception is thrown (System.ServiceModel.ProtocolException, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089).
vm79
A: 

Have you tried adding

[OperationBehavior(TransactionScopeRequired=true)]

on the implementation of the contract ?

Edit: Just for kicks, have you tried regenerating the client proxy?

RandomNoob
Yes. [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
vm79
Yep. I did try. :-)
vm79
A: 

I finally figured it out! I manually generated Service Reference proxy class and config file using svcutil tool and used in BLL. Worked fine!

VS version: 2008

WCF service was referenced as "Service Reference" in the BLL. After updating WCF "Service Reference", OperationContracts of recently added ServiceContract in Reference.cs(proxy class) were missing TransactionFlow attribute. This is mainly started happening after adding new ServiceContracts to the service. One interesting thing noticed was, app.config had <CustomBinding> for newly added ServiceContract in lieu of <wsHttpBinding>. Appears to be issue the way with VS 2008 generates Service Reference.

vm79