Based on my previous post, I managed to get distributed transaction scenario working using WCF, MTOM and WS-AtomicTransactions.
This means that you have the option to transport arbitrary files, using transactional ACID semantics, from the client, over HTTP and MTOM.
The idea is to integrate a distributed transaction with TxF, or NTFS file system transaction. This only works on Windows Server 2008 (Longhorn Server) and Windows Vista.
Download: Sample code
If the client starts a transaction then all files within it should be stored on the server. If something fails or client does not commit, no harm is done. The beauty of this is that it's all seamlessly integrated into the current communication/OS stack.
This is shipping technology; you just have to dive a little deeper to use it.
Here's the scenario:
There are a couple of issues that need to be addressed before we move to the implementation:
OK, here we go.
Here's the service contract:
[ServiceContract(SessionMode = SessionMode.Allowed)]interface ITransportFiles{ [OperationContract] [TransactionFlow(TransactionFlowOption.Allowed)] byte[] GetFile(string name);
[OperationContract] [TransactionFlow(TransactionFlowOption.Allowed)] void PutFile(byte[] data, string name);}
We allow the sessionful binding (it's not required, though) and allow transactions to flow from the client side. Again, transactions are not mandatory, since client may opt-out of using them and just transport files without a transaction.
The provided transport mechanism uses MTOM, since the contract's parameter model is appropriate for it and because it's much more effective transferring binary data.
So here's the service config:
<system.serviceModel> <bindings> <wsHttpBinding> <binding name="MTOMBinding" transactionFlow="true" messageEncoding="Mtom" maxReceivedMessageSize="10485760"> <readerQuotas maxArrayLength="10485760"/> </binding> </wsHttpBinding> </bindings> <services> <service name="WCFService.TransportService"> <host> <baseAddresses> <add baseAddress="http://localhost:555/transportservice"> </baseAddresses> </host> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="MTOMBinding" contract="WCFService.ITransportFiles"/> </service> </services></system.serviceModel>
Here, MTOMBinding is being used to specify MTOM wire encoding. Also, quotas and maxReceivedMessageSize attribute is being adjusted to 10 MB, since we are probably transferring larger binary files.
Service implementation is straight forward:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]class TransportService : ITransportFiles{ [OperationBehavior(TransactionScopeRequired = true)] public byte[] GetFile(string name) { Console.WriteLine("GetFile: {0}", name); Console.WriteLine("Distributed Tx ID: {0}", Transaction.Current.TransactionInformation.DistributedIdentifier); return ReadFully(TransactedFile.Open(@"C:\TxF\Service\" + name, FileMode.Open, FileAccess.Read, FileShare.Read), 0); }
[OperationBehavior(TransactionScopeRequired = true)] public void PutFile(byte[] data, string filename) { Console.WriteLine("PutFile: {0}", filename); Console.WriteLine("Distributed Tx ID: {0}", Transaction.Current.TransactionInformation.DistributedIdentifier);
using (BinaryWriter bw = new BinaryWriter( TransactedFile.Open(@"C:\TxF\Service\" + filename, FileMode.Create, FileAccess.Write, FileShare.Write))) { bw.Write(data, 0, data.Length); // clean up bw.Flush(); } }}
Client does four things:
Before you run:
This sample is provided without any warranty. It's a sample, so don't use it in production environments.
Remember Me
The opinions expressed herein are my own personal opinions and do not represent my company's view in any way.
My views often change.
This blog is just a collection of bytes.
Copyright © 2003-2024Matevž Gačnik
E-mail