Blog from Saravanan Arumugam

Let us talk about Technologies

Category Archives: WCF

Error: Schema with target namespace could not be found.


I was debugging a WSDL by downloading it and its reference XSDs in to my local machine. I got the following exception when I used SVCUtil

Exception

Error: Schema with target namespace ‘http://xmlns.oracle.com/Common/schemas/GetEmployeesPayrateRequest.V1′ could not be found.

Solution

We get this exception because the svcutil for some reason is not finding the referenced schema in the local disk. To solve it, try copying the xsd contents and place them as inline schema under <wsdl:types /> tag.

  <wsdl:types>
    <!--<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:import namespace="http://xmlns.oracle.com/Common/schemas/GetEmployeesPayrateRequest.V1" 
                  schemaLocation="GetEmployeePayrateRequest.v1.xsd"/>
      <xsd:import namespace="http://xmlns.oracle.com/Common/schemas/GetEmployeesPayrateResponse.V1" 
                  schemaLocation="GetEmployeePayratesResponse.v1.xsd"/>
    </xsd:schema>-->
    <xsd:schema elementFormDefault="unqualified" targetNamespace="http://xmlns.oracle.com/Common/schemas/GetEmployeesPayrateRequest.V1"
            xmlns="http://xmlns.oracle.com/Common/schemas/GetEmployeesPayrateRequest.V1" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:element name="GetEmployeesPayrateRequest">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="EMPLID" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
 
    <xsd:schema elementFormDefault="qualified"
            targetNamespace="http://xmlns.oracle.com/Common/schemas/W_GENERIC_RESPONSE8.v1"
            xmlns="http://xmlns.oracle.com/Common/schemas/W_GENERIC_RESPONSE8.v1"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:element name="GetEmployeePayratesResponse">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element maxOccurs="unbounded" minOccurs="0" name="JobRow">
              <xsd:complexType>
                <xsd:sequence>
                  <xsd:element name="EmployeeId" type="xsd:string"/>
                  <xsd:element name="EmployeeName" type="xsd:string"/>
                  <xsd:element minOccurs="0" name="EffectiveDate" type="xsd:date"/>
                  <xsd:element name="HourlyRt" type="xsd:string"/>
                  <xsd:element name="DepartmentId" type="xsd:string"/>
                </xsd:sequence>
              </xsd:complexType>
            </xsd:element>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
  </wsdl:types>

Note that usually the WSDL will generate the <xsd:schema/> tag inside <wsdl:types /> element, and will fill it with multiple imports for every reference types. This has to be replaced by the actual schema definitions. I have just commented it out to show where the replacement has to happen.

Entity Object as Data Contracts in WCF service


I have come across an interesting issue recently while I used Entity Objects in WCF. Before explaining the actual issue, let me explain a few concepts of serialization.

Entity Object vs. WCF

Entity objects are designed so rich, so that if it is chosen to be used in WCF, WCF would not require additional classes to serve as Data Contracts because the entity objects are usually decorated with the following attributes.

    [EdmEntityTypeAttribute(NamespaceName = "IntradoModel", Name = "ICRecord")]
    [Serializable()]
    [DataContractAttribute(IsReference = true)]
    public partial class ICRecord : EntityObject

EdmEntityTypeAttribute links the class to the conceptual model. It helps the Linq to Entity to recognize this type as a legal entity object. SerializableAttribute says that the object of this type can be serialized if needed. DataContractAttribute on the other hand also means that the the type is seriablizable but, by a special serializer – DataContractSerializer.

Note that the classes are partial, so just incase we need more members in the Data Contract, we can always write the partial class with additional members and extend it.

 

Some Concepts of Serialization

There are differences in the way the regular serializers (XmlSerializer, BinaryFormatter, SoapFormatter) and the DataContractSerializer chose the members to serialize. For example consider the following class.

public class SampleClass
{
    public int Number1 { get; set; }
    public int Number2 { get; set; }
    public int Number3 { get; set; }
 
    public int Sum { get; set; }
    public int Product { get; set; }
}

If we serialize an object of the above type, we would get something like below.

<SampleClass>
  <Number1>2</Number1>
  <Number2>2</Number2>
  <Number3>2</Number3>
 
  <Sum>6</Sum>
  <Product>8</Product>  
</SampleClass>

Serialization is usually a costly process, in terms of size, space, or transmission overhead. So its usual that you’d try to ignore some of the members during serialization without losing information. In our example, the information is carried through Number1, Number2, and Number3. But Sum and Product can always be calculated from the numbers at any point of time. So we can ignore them during serialization to save space, size and transmission overheads.

 

Opt-in vs. Opt-out method of serialization

The usual serializers, XmlSerializer, BinaryFormatter, and SoapFormatter works in the Opt-Out method. This means that all the members would be a part of the serialization unless you particularly ignore some. XmlIgnoreAttribute, NonSerializedAttribute, SoapIgnoreAttributes are the ones used to opt-out a member from getting serialized.

[Serializable]
public class SampleClass
{
    public int Number1 { get; set; }
    public int Number2 { get; set; }
    public int Number3 { get; set; }
 
    [NonSerialized]
    [XmlIgnore]
    [SoapIgnore]
    public int Sum { get; set; }
    
    [NonSerialized]
    [XmlIgnore]
    [SoapIgnore]
    public int Product { get; set; }
}

On the other hand DataContractSerializer, works in the Opt-in method. This means that during the serialization only the members marked with DataMemberAttribute would be serialized. Members without the attribute would be ignored during the serialization. Here we are opting-in what we want.

[Serializable]
[DataContract]
public class SampleClass
{
    [DataMember]
    public int Number1 { get; set; }
    [DataMember]
    public int Number2 { get; set; }
    [DataMember]
    public int Number3 { get; set; }
 
    [NonSerialized]
    [XmlIgnore]
    [SoapIgnore]
    public int Sum { get; set; }
 
    [NonSerialized]
    [XmlIgnore]
    [SoapIgnore]
    public int Product { get; set; }
}

 

Possible Issue in using Entity Objects as Data Contracts

I found the following exception when I tried using the Entity Objects as Data Contracts.

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

Usually an Entity Object contains the following structure. (We can find the structure of the entity model in Entities.Designer.cs)

    • Factory Method to create an object of its own type.
    • Primary Properties
    • Navigation Properties

Here factory method is not going to be part of the serialization, since its not a property. Primary and Navigation Properties would be part of serialization.

Primary properties provide all the information that you might need from the object. Navigation properties are to help the entity users for accessing the related tables/objects. So it doesn’t have the significance in serialization.

So Navigation Properties need not take part in serialization. XmlSerializer, and SoapFormatter would ignore them, but DataContractSerializer would not (I guess it’s a miss from Microsoft developers group or may be intentional). This is due to the attributes placed on these Navigation properties.

[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("MyModel", 
    "FK_ICRun_ICFile", 
    "ICFile")]
public ICFile ICFile
{
    get{

Reason for the exception

Usually the entity object uses the concept of Lazy Loading. In your code you’d be filling the object by using an object context, and close the context. But this would only fill the primary properties. Navigation properties would be filled only if you need them when you explicitly access them.

using (var context = new IntradoEntities())
{
    return context.ICFiles.Where(record =>
        (FileStatus)record.Status == FileStatus.Error).ToList();
}

When the DataContractSerializer encounters a navigation property, it would try to retrieve it during the runtime. But at the time of serialization Object Context would not be alive, so we end up with the exception.

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

Even the Eager Loading, the issue wouldn’t be over since there’s always a limit for the depth of objects during Soap transmission.

Solution

The solution is simple. Remove the DataMemberAttribute from the navigation properties.

To avoid any accidents of removing useful members from serialization, make sure you remove DataMemberAttribute only to those properties within the #region named as Navigation Properties.

I hope we’ll get a better Entity Framework version next time.

Simple Duplex Channel Implementation


In WCF, we have three modes of message exchange, called Message Exchange Patterns (MEP)

  • Request/Response mode
  • One way message transfer
  • Duplex communication

Any default WCF service use the Request/Response MEP.

In places where we don’t expect any reply to come back from the receiver and where we simply trust that the communication channel would do its job right, we go for One way message exchange. In such cases even if an exception occurs at the receiving end we won’t receive it at the calling end. Example for such communication could be calling a logging service, Message queues etc.

The last one is the point of our interest in this paper, Duplex communication. By definition a duplex communication is, a communication between two parties with equal ability to exchange information. In terms of WCF, the service and client can talk to each other independently through two different end points. Upon client’s request to a service’s contract, the service would respond by calling a contract implemented in the client application itself.

WCF provides methods of implementing the duplex communication in a non-difficult but a little tricky way of coding. Let’s have a look at the very simple implementation of duplex communication.

  •  

    Step 1: Declare two services contracts, one for the duplex service and another for callback

    The very first thing is to create two service contracts. One is for the duplex service, the other one is the callback.

    In my example, I am going to create a service which will send a greeting message and the service would respond to the client with an acknowledgment.

    I consider it is important to mention where do I write each code. So on top of each code snippet let me write down if that’s done on client or server side.

  • //Written on Server Side

    namespace DuplexChannel
    {
        [ServiceContract(CallbackContract = typeof(IGreetingCallback))]
        public interface IGreetingService
        {
            [OperationContract(IsOneWay=true)]
            void SendGreeting(string message);
        }
     
        [ServiceContract]
        public interface IGreetingCallback
        {
            [OperationContract()]
            void GreetingReceived (string message);
        }
    }

    Here IGreetingService is the service contract and IGreetingCallback is the callback contract.

    You can note that the ServiceContractAttribute takes the CallbackContract as the named parameter. This is a notification that the contract is a duplex service contract. CallbackContract parameter takes the type of the callback , in our example IGreetingCallback.

    Note that the duplex operations should be one way (Note that IsOneWay=true in SendGreeting operation). If we miss mentioning the operation as one way, we would end up in a time out exception.

  •  

    Step 2: Define the duplex service on the server side (not the callback)

    Next step is to write the definition or implement the duplex service contract into class.

    An important thing to notice here is that we write definition only for the duplex contract, not for the call back. Because callback is the one to be defined on the client side.

    In the step 1 we have declared the structure of the IGreetingService and IGreetingCallback, but in this step we implement only the IGreetingService.

    //Written on Server Side
    namespace DuplexChannel
    {
        [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
        public class GreetingService : IGreetingService
        {
            [OperationBehavior()]
            public void SendGreeting(string message)
            {
                IGreetingCallback callback = OperationContext.Current.
    GetCallbackChannel<IGreetingCallback>();
                callback.GreetingReceived("Received the message: " + message);
            }
        }
    }

    In the SendGreeting you can see that we are expecting an instance of callback class. This has to come from the client side. Here the OperationContext.Current.GetCallbackChannel<T>() method retrieves the instance of callback class defined on the client side.

     

    Step 3: Specify the service behavior

    In the code snippet specified in step 2 we have provided a Service Behavior. Here we have explicitly marked the ConcurrencyMode to be Multiple. By default for any WCF service, the concurrency mode is Single. This means that only a single request would be serviced at a time.

    In the duplex service you can see that the current request (SendGreeting) has to be held in the middle while the call back instance (GreetingReceived) is signaled. So to do this, it either has to have an ability to serve multiple requests (One for the service itself and another one for the callback) or to leave the service in the middle (SendRequest) unprocessed, serve the other request (callback) and then come back to the original request (SendRequest) to complete it.

    The choice of this workflow is up to the design of the service. The workflow of serving multiple requests at the same time can be achieved by setting the concurrency mode as Multiple. Leaving a operation incomplete, jumping to another operation and coming back to the original operation can be achieved through Reentrant concurrency mode.

    So in summary the service behavior of a duplex service may look like this.

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] 

    or

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]

    Step 4: Configure the duplex service

    In the configuration there is no need for any special coding except for the type of binding to use.

    Following is the list of  bingings that support duplex channel.

    1. WsDualHttpBinding (for Http protocol)
    2. NetTcpBinding
    3. NetTcpContextBinding
    4. NetNamedPipeBinding
    5. NetPeerTcpBinding
    6. PollingDuplexBinding (introduced with/for Silverlight 4)

    Note: For a complete list of inbuilt bindings and their capabilities refer to System-Provided Bindings.

    In my example, I am going to use WsDualHttpBinding.

  • <!—- Written on server side –><system.serviceModel>
        <services>
          <service name="DuplexChannel.GreetingService">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:54927/"/>          
              </baseAddresses>
            </host>
            <endpoint address="ws" binding="wsDualHttpBinding" 
             contract="DuplexChannel.IGreetingService" />
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <serviceMetadata httpGetEnabled="true" />
              <serviceDebug includeExceptionDetailInFaults="false" />
              <!--The default setting-->
              <serviceThrottling maxConcurrentCalls="16" 
                     maxConcurrentInstances="1" 
                     maxConcurrentSessions="10"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>

    Step 5: Create service proxy

    Use service reference or svcutil.exe to create the proxy for the duplex service. This is an usual step.

    Unlike regular proxies, you can find the following changes in the duplex proxy class.

    • Usually the proxy class’s (e.g. GreetingServiceClient) base class would be ClientBase. But for duplex service, the base class would be DuplexClientBase.
    • We cannot find any empty constructor in the proxy class. Every constructor of proxy class would have a InstanceContext parameter. This parameter is inevitable because it has to presents the instance of callback class to the service.
        [System.Diagnostics.DebuggerStepThroughAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
        public partial class GreetingServiceClient : 
            DuplexClientBase<Messenger.GreetingService.IGreetingService>, 
            Messenger.GreetingService.IGreetingService {
            
            public GreetingServiceClient(InstanceContext callbackInstance) : 
                    base(callbackInstance) {
            }
            
            public GreetingServiceClient(InstanceContext callbackInstance, 
                string endpointConfigurationName) : 
                    base(callbackInstance, endpointConfigurationName) {
            }
            
            public GreetingServiceClient(InstanceContext callbackInstance, 
                string endpointConfigurationName, string remoteAddress) : 
                base(callbackInstance, endpointConfigurationName, remoteAddress) {
            }
            
            public GreetingServiceClient(InstanceContext callbackInstance, 
                string endpointConfigurationName,  EndpointAddress remoteAddress) : 
                base(callbackInstance, endpointConfigurationName, remoteAddress) {
            }
            
            public GreetingServiceClient(InstanceContext callbackInstance, 
                System.ServiceModel.Channels.Binding binding, 
                System.ServiceModel.EndpointAddress remoteAddress) : 
                    base(callbackInstance, binding, remoteAddress) {
            }
            
            public void SendGreeting(string message) {
                base.Channel.SendGreeting(message);
            }
        }

    Step 6: Modify client configuration to include client base address

    If the client base address is not explicitly specified WCF would start using address similar to http://+:80/Temporary_Listen_Addresses/634f73f6-c612-4441-acf8-79ddd5c62f98/

    Port 80 is usually occupied by the IIS. So the run time might throw an exception such as HTTP could not register URL … because TCP port 80 is being used by another application.

    It is a safe procedure to provide the client base address ourselves while designing duplex channel. Client base address can be provided in the binding configuration as follows.

    <configuration>
      <system.serviceModel>
        <bindings>
          <wsDualHttpBinding>
            <binding name="WSDualHttpBinding_IGreetingService"
                     clientBaseAddress="http://localhost:8088/clientCallbackUrl">
              <security mode="Message">
                <message clientCredentialType="Windows"
                         negotiateServiceCredential="true"
                         algorithmSuite="Default" />
              </security>
            </binding>
          </wsDualHttpBinding>
        </bindings>
        <client>
          <endpoint address="http://localhost:54927/GreetingService.svc/ws"
            binding="wsDualHttpBinding" 
                     bindingConfiguration="WSDualHttpBinding_IGreetingService"
                      contract="GreetingService.IGreetingService" 
                     name="WSDualHttpBinding_IGreetingService">
            <identity>
              <userPrincipalName value="Saravanan-PC\Saravanan" />
            </identity>
          </endpoint>
        </client>
      </system.serviceModel>
    </configuration>

    Step 7: Start using the proxy

    In the previous section we have noticed that for initializing a proxy class we need to pass an instance of a class as a parameter. This parameter has to be the callback object which implements the callback contract declared in the server side. In my example IGreetingCallback.

    So typical declaration of a proxy would look like this.

    InstanceContext context = new InstanceContext(this);

    client = new GreetingServiceClient(context);

  •  

    Step 8: Build the Service Agent

    Though it is optional, its always a good practice to build a service agent which would act as wrapper to the service related activities. Service agent provides an extra layer with which we can isolate all the technical/formal tasks such as initializing proxy, providing callbacks, making asynchronous calls, closing proxies etc. This helps the client application to consider calling a service as easy of calling a simple C# method.

    Here is the Service agent I have written to handle both IGreetingService and IGreetingCallback.

        public class GreetingServiceAgent
            : IGreetingService,
              IGreetingServiceCallback,
            IDisposable
        {
            GreetingServiceClient client;
            public delegate void GreetingHandler(string message);
     
            public GreetingServiceAgent()
            {
                try
                {
                    InstanceContext context = new InstanceContext(this);
                    client = new GreetingServiceClient(context,
                                "WSDualHttpBinding_IGreetingService");
                    client.Open();
                }
                catch
                { client = null; }
            }
     
            public GreetingHandler GreetingRecievedHandler
            {
                get;
                set;
            }
     
            public void SendGreeting(string message)
            {
                if (client != null)
                    client.SendGreeting(message);
            }
     
            public void GreetingReceived(string message)
            {
                GreetingRecievedHandler(message);
            }
     
            public void Dispose()
            {
                if (client != null)
                    client.Close();
            }
        }

    Note that the GreetingServiceAgent implements both the IGreetingService and IGreetingServiceCallback.

    Since the ServiceAgent has implemented IGreetingServiceCallback, an instance of it becomes eligible candidate for the constructor of InsanceContext. That’s the reason we use ‘”this” object as the constructor parameter to InstanceContext. This instance context should be passed as a parameter to proxy initialization.

    It is also possible to create a different class for callback. In such a case the InstanceContext would be initiated with an instance of the callback class.

    Another thing is that GreetingReceivedHandler is provided as a public property which can be set as a delegate to any method that the client prefers.

    Client application has to write a method and set its delegate as GreetingReceivedHandler. When the service completes its operation, this delegate would be retrieved by the server and the server call this method as a callback.

  •  

    Step 9: Build the client application to call the service

    As a final step I have created a simple WPF application with a text block, text box and a send button. The text box would take the input message and text block would display the received message. The button would help calling the service with the message entered in the text box.

        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
     
            private void Send_Click(object sender, RoutedEventArgs e)
            {
                if (!string.IsNullOrWhiteSpace(SendMessageTextBox.Text))
                {
                    GreetingServiceAgent agent = new GreetingServiceAgent();
     
                    agent.GreetingRecievedHandler += GreetingReceived;
                    agent.SendGreeting(SendMessageTextBox.Text);
                }
            }
     
            void GreetingReceived(string message)
            {
                ReceivedMessageTextBlock.Text = message;
            }
        }

     

  • This operation would deadlock because the reply cannot be received until the current Message completes processing.


    I got the following exception when I attempted to create a Duplex channeled service.

    Exception

    This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on ServiceBehaviorAttribute.

    I got this exception because I didn’t change the concurrency mode of the service. By default the concurrency mode is single. But the duplex operation would require the service instance to be called concurrently.

    Solution

    As suggested in the exception message itself, when I set the Concurrency mode to Multiple it got resolved.

    Reentrant is also applicable for duplex services however the choice of Multiple or Reentrant concurrency is up to the design.

        [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]

        public class GreetingService : IGreetingService

    Know the Service and Operation Behaviors


    We usually get convinced with the default behavior of a WCF service and its operations. In scenarios where the simple is not sufficient, we tend to set the operation and service behaviors through code based on our need.

    Setting a behavior is achieved through ServiceBehaviorAttribute and OperationBehaviorAttribute. The config file is another place for defining Service, Binding and Endpoint behaviors. But in this paper, I limit the discussion to the behaviors that can be set though these two attributes.

    These attributes are applicable only on the Service definition not on the service declaration; in other words, use these attributes on the Service’s class definition, not on the Interface.

    The typical Service having implemented the behavior attributes would look like this.

        [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, 
            TransactionIsolationLevel = IsolationLevel.Serializable, 
            InstanceContextMode = InstanceContextMode.Single, 
            ReleaseServiceInstanceOnTransactionComplete = true)]
        public class BankingService : IBankingService
        {
            [OperationBehavior(ReleaseInstanceMode = ReleaseInstanceMode.None, 
                TransactionScopeRequired = true)]
            public double WithdrawMoney(int accountNumber, double amount) { }
        }

    To make a decision on weather the current behavior of Service and operation is sufficient for your service needs or you want to change them, it is important to know the place to check the current behavior during the runtime.

    The object useful to examine the behaviors is OperationContext. You can get the current context using OperationContext.Current.

     

    Service Behaviors

    The following list (screenshot) shows the configurable behaviors of the current service and their default values.

    image

    The service behavior is extracted with the following statement in Debug mode (with Quickwatch).

    OperationContext.Current.Host.Description.Behaviors[typeof(ServiceBehaviorAttribute)]

    Note: Besides the Host.Description, the service behavior can be found in various places of OperationContext.Current.EndpointDispatcher.DispatchRuntime. The list of service behaviors found in DispatchRuntime is listed at the end of this paper.

     

    OperationBehaviors

    The following list (screenshot) shows the configurable behaviors of a specified operation and their default values.

    image

    The operation behavior for a specific operation contract can be extracted using the following statement.

    OperationContext.Current.EndpointDispatcher.DispatchRuntime.Operations["Greeting"]

    Note: In the screenshot the IsOneway behavior is displayed as true since I have specified it explicitly. In reality, it’ll be false by default.

    List of Service Behaviors found in DispatchRuntime

    OperationContext.Current.EndpointDispatcher.DispatchRuntime.ConcurrencyMode

    OperationContext.Current.EndpointDispatcher.EndpointAddress

    OperationContext.Current.EndpointDispatcher.AddressFilter

    OperationContext.Current.EndpointDispatcher.DispatchRuntime.

    ReleaseServiceInstanceOnTransactionComplete

    OperationContext.Current.EndpointDispatcher.DispatchRuntime.

    TransactionAutoCompleteOnSessionClose

    OperationContext.Current.EndpointDispatcher.DispatchRuntime.ValidateMustUnderstand

    OperationContext.Current.EndpointDispatcher.DispatchRuntime.CallbackClientRuntime

    OperationContext.Current.EndpointDispatcher.ContractName

    OperationContext.Current.EndpointDispatcher.ContractNamespace

    OperationContext.Current.EndpointDispatcher.DispatchRuntime.MessageInspectors

    OperationContext.Current.EndpointDispatcher.DispatchRuntime.AutomaticInputSessionShutdown

    OperationContext.Current.EndpointDispatcher.DispatchRuntime.SingletonInstanceContext

    OperationContext.Current.EndpointDispatcher.DispatchRuntime.SynchronizationContext

    OperationContext.Current.EndpointDispatcher.ChannelDispatcher.TransactionIsolationLevel

    OperationContext.Current.EndpointDispatcher.ChannelDispatcher.TransactionTimeout