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ı TransactionFlowInspector
istemci 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) kullanarakTransactionFlowProperty
geç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 TransactionMessageProperty
eklenir.
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
Çözümü oluşturmak için Windows Communication Foundation Örnekleri Oluşturma başlığındaki yönergeleri izleyin.
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.
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...
Ş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.
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
Hizmet uygulaması, istemci tarafından gönderilen işlem tanımlayıcısını işlemin parametresinde
clientTransactionId
hizmet işlemininCalculatorService.Add()
tanımlayıcısı ile eşleştirebiliyorsa iletiyiThe client transaction has flowed to the service
görüntüler. Eşleşme yalnızca istemci işlemi hizmete akıyorsa elde edilir.İ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...
İstemciyi hizmete karşı çalıştırmak artık daha önce olduğu gibi benzer bir çıkış üretir.
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
Svcutil.exe için
sampleProfileUdpBinding
bağ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>