Aracılığıyla paylaş


Taşıma: UDP üzerinden Özel İşlemler Örneği

TransactionMessagePropertyUDPTransport örneği, Windows Communication Foundation (WCF)Transport Genişletilebilirliği'ndeki Aktarım: UDP örneğini temel alır. UDP Aktarım örneğini özel işlem akışını destekleyecek şekilde genişletir ve özelliğinin TransactionMessageProperty kullanımını gösterir.

UDP Aktarım Örneğindeki Kod Değişiklikleri

İşlem akışını göstermek için, örnek için hizmet sözleşmesini ICalculatorContract için bir işlem kapsamı CalculatorService.Add()gerektirecek şekilde değiştirir. Örnek ayrıca işlemin sözleşmesine Add ek System.Guid bir parametre ekler. Bu parametre, istemci işleminin tanımlayıcısını hizmete geçirmek için kullanılır.

class CalculatorService : IDatagramContract, ICalculatorContract
{
    [OperationBehavior(TransactionScopeRequired=true)]
    public int Add(int x, int y, Guid clientTransactionId)
    {
        if(Transaction.Current.TransactionInformation.DistributedIdentifier == clientTransactionId)
    {
        Console.WriteLine("The client transaction has flowed to the service");
    }
    else
    {
     Console.WriteLine("The client transaction has NOT flowed to the service");
    }

    Console.WriteLine("   adding {0} + {1}", x, y);
    return (x + y);
    }

    [...]
}

Aktarım : UDP örneği, bir istemci ile hizmet arasında ileti geçirmek için UDP paketlerini kullanır. Aktarım : Özel Aktarım Örneği iletileri taşımak için aynı mekanizmayı kullanır, ancak bir işlem akışı yapıldığında kodlanmış iletiyle birlikte UDP paketine eklenir.

byte[] txmsgBuffer = TransactionMessageBuffer.WriteTransactionMessageBuffer(txPropToken, messageBuffer);

int bytesSent = this.socket.SendTo(txmsgBuffer, 0, txmsgBuffer.Length, SocketFlags.None, this.remoteEndPoint);

TransactionMessageBuffer.WriteTransactionMessageBuffer , geçerli işlem için yayma belirtecini ileti varlığıyla birleştirmeye ve bir arabelleğe yerleştirmeye yönelik yeni işlevler içeren bir yardımcı yöntemdir.

Özel işlem akışı aktarımı için istemci uygulamasının hangi hizmet işlemlerinin işlem akışı gerektirdiğini bilmesi ve bu bilgileri WCF'ye geçirmesi gerekir. Ayrıca, kullanıcı işlemini aktarım katmanına iletmek için bir mekanizma da olmalıdır. Bu örnek, bu bilgileri almak için "WCF ileti denetçileri" kullanır. Burada uygulanan ve adlı TransactionFlowInspectoristemci ileti denetçisi aşağıdaki görevleri gerçekleştirir:

  • Belirli bir ileti eylemi için bir işlemin akışa alınıp alınmayacağını belirler (bu işlem içinde IsTxFlowRequiredForThisOperation()gerçekleşir).

  • Bir işlemin akışı gerekiyorsa (bu işlemi içinde BeforeSendRequest()yapılır) kullanarak TransactionFlowPropertygeçerli ortam işlemini iletiye ekler.

public class TransactionFlowInspector : IClientMessageInspector
{
   void IClientMessageInspector.AfterReceiveReply(ref           System.ServiceModel.Channels.Message reply, object correlationState)
  {
  }

   public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
   {
       // obtain the tx propagation token
       byte[] propToken = null;
       if (Transaction.Current != null && IsTxFlowRequiredForThisOperation(request.Headers.Action))
       {
           try
           {
               propToken = TransactionInterop.GetTransmitterPropagationToken(Transaction.Current);
           }
           catch (TransactionException e)
           {
              throw new CommunicationException("TransactionInterop.GetTransmitterPropagationToken failed.", e);
           }
       }

      // set the propToken on the message in a TransactionFlowProperty
       TransactionFlowProperty.Set(propToken, request);

       return null;
    }
  }

  static bool IsTxFlowRequiredForThisOperation(String action)
 {
       // In general, this should contain logic to identify which operations (actions)      require transaction flow.
      [...]
 }
}

KendisiTransactionFlowInspector, özel bir davranış kullanılarak çerçeveye geçirilir: .TransactionFlowBehavior

public class TransactionFlowBehavior : IEndpointBehavior
{
       public void AddBindingParameters(ServiceEndpoint endpoint,            System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
      {
      }

       public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
      {
            TransactionFlowInspector inspector = new TransactionFlowInspector();
            clientRuntime.MessageInspectors.Add(inspector);
      }

      public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
     {
     }

      public void Validate(ServiceEndpoint endpoint)
      {
      }
}

Yukarıdaki mekanizma uygulandığında, kullanıcı kodu hizmet işlemini çağırmadan önce bir TransactionScope oluşturur. İleti denetçisi, hizmet işlemine akışının gerekli olması durumunda işlemin taşımaya geçirilmesini sağlar.

CalculatorContractClient calculatorClient = new CalculatorContractClient("SampleProfileUdpBinding_ICalculatorContract");
calculatorClient.Endpoint.Behaviors.Add(new TransactionFlowBehavior());

try
{
       for (int i = 0; i < 5; ++i)
      {
              // call the 'Add' service operation under a transaction scope
             using (TransactionScope ts = new TransactionScope())
             {
        [...]
        Console.WriteLine(calculatorClient.Add(i, i * 2));
         }
      }
       calculatorClient.Close();
}
catch (TimeoutException)
{
    calculatorClient.Abort();
}
catch (CommunicationException)
{
    calculatorClient.Abort();
}
catch (Exception)
{
    calculatorClient.Abort();
    throw;
}

İstemciden bir UDP paketi aldıktan sonra, hizmet iletiyi ve büyük olasılıkla bir işlemi ayıklamak için bu paketi seri durumdan çıkarır.

count = listenSocket.EndReceiveFrom(result, ref dummy);

// read the transaction and message                       TransactionMessageBuffer.ReadTransactionMessageBuffer(buffer, count, out transaction, out msg);

TransactionMessageBuffer.ReadTransactionMessageBuffer() , tarafından TransactionMessageBuffer.WriteTransactionMessageBuffer()gerçekleştirilen serileştirme işlemini tersine çeviren yardımcı yöntemdir.

bir işlem akışı yapıldıysa, içindeki iletiye TransactionMessagePropertyeklenir.

message = MessageEncoderFactory.Encoder.ReadMessage(msg, bufferManager);

if (transaction != null)
{
       TransactionMessageProperty.Set(transaction, message);
}

Bu, dağıtıcının gönderme zamanında işlemi almasını ve ileti tarafından ele alınan hizmet işlemini çağırırken bunu kullanmasını sağlar.

Örneği ayarlamak, derlemek ve çalıştırmak için

  1. Çözümü oluşturmak için Windows Communication Foundation Örnekleri Oluşturma başlığındaki yönergeleri izleyin.

  2. Geçerli örnek, Aktarım: UDP örneğine benzer şekilde çalıştırılmalıdır. Çalıştırmak için hizmeti UdpTestService.exe ile başlatın. Windows Vista çalıştırıyorsanız, hizmeti yükseltilmiş ayrıcalıklarla başlatmanız gerekir. Bunu yapmak için, Dosya Gezgini'da UdpTestService.exe sağ tıklayın ve Yönetici olarak çalıştır'a tıklayın.

  3. Bu, aşağıdaki çıkışı oluşturur.

    Testing Udp From Code.
    Service is started from code...
    Press <ENTER> to terminate the service and start service from config...
    
  4. Şu anda, UdpTestClient.exe çalıştırarak istemciyi başlatabilirsiniz. İstemci tarafından üretilen çıkış aşağıdaki gibidir.

    0
    3
    6
    9
    12
    Press <ENTER> to complete test.
    
  5. Hizmet çıkışı aşağıdaki gibidir.

    Hello, world!
    Hello, world!
    Hello, world!
    Hello, world!
    Hello, world!
    The client transaction has flowed to the service
       adding 0 + 0
    The client transaction has flowed to the service
       adding 1 + 2
    The client transaction has flowed to the service
       adding 2 + 4
    The client transaction has flowed to the service
       adding 3 + 6
    The client transaction has flowed to the service
       adding 4 + 8
    
  6. Hizmet uygulaması, istemci tarafından gönderilen işlem tanımlayıcısını işlemin parametresinde clientTransactionId hizmet işleminin CalculatorService.Add() tanımlayıcısı ile eşleştirebiliyorsa iletiyi The client transaction has flowed to the service görüntüler. Eşleşme yalnızca istemci işlemi hizmete akıyorsa elde edilir.

  7. İstemci uygulamasını yapılandırma kullanılarak yayımlanan uç noktalarda çalıştırmak için hizmet uygulaması penceresinde ENTER tuşuna basın ve ardından test istemcisini yeniden çalıştırın. Hizmette aşağıdaki çıkışı görmeniz gerekir.

    Testing Udp From Config.
    Service is started from config...
    Press <ENTER> to terminate the service and exit...
    
  8. İstemciyi hizmete karşı çalıştırmak artık daha önce olduğu gibi benzer bir çıkış üretir.

  9. Svcutil.exe kullanarak istemci kodunu ve yapılandırmasını yeniden oluşturmak için hizmet uygulamasını başlatın ve ardından örneğin kök dizininden aşağıdaki Svcutil.exe komutunu çalıştırın.

    svcutil http://localhost:8000/udpsample/ /reference:UdpTransport\bin\UdpTransport.dll /svcutilConfig:svcutil.exe.config
    
  10. Svcutil.exe için sampleProfileUdpBindingbağlama uzantısı yapılandırmasını oluşturmadığını unutmayın; bunu el ile eklemeniz gerekir.

    <configuration>
        <system.serviceModel>
            …
            <extensions>
                <!-- This was added manually because svcutil.exe does not add this extension to the file -->
                <bindingExtensions>
                    <add name="sampleProfileUdpBinding" type="Microsoft.ServiceModel.Samples.SampleProfileUdpBindingCollectionElement, UdpTransport" />
                </bindingExtensions>
            </extensions>
        </system.serviceModel>
    </configuration>
    

Ayrıca bkz.