question

JoaquimCampos-1536 avatar image
0 Votes"
JoaquimCampos-1536 asked Bruce-SqlWork answered

WFC Service, testing if a contract operation is executing

Hi there.
I have a standalone Client Application that is installed in 3 different phisical locations.
That application is used to upload files from each location, to a server, over the internet, using a WFC service.
The WFC service is IIS hosted, installed on a WebSite the Internet.
The clients can request connections to the server, from the diferent locations.
The Service is runnig ok, but because of the lower bandwith, only one file must be uploaded at a time.
So, there is no point, for a client to connect to the service and try to execute the download, if the service is already busy with another request.


My question is: It´s possible, on client side, to test if the service is currently uploading a file from a diferent client, before actually request a new upload?
What I mean is someting like the following:

The service having two Operation Contracts. One to check if the server is currently uploading a file (using a field for instance) and another operation to execute the upload.

<ServiceContract>
Public Interface IWebUpload
<OperationContract>
Function IsSomeUploadFileInProgress() As Boolean

 <OperationContract>
 Function UploadFile(ObjUploadFile As UploadFile) As UploadFileResponse

End Interface

<MessageContract>
Public Class UploadFile
<MessageHeader(MustUnderstand:=False)>
Public Property Filename As String=""
<MessageBodyMember(Order:=1)>
Public Property Stream() As Stream=""
End Class

<MessageContract>
Public Class UploadFileResponse
<MessageBodyMember(Order:=1)>
Public Property Result() As String = ""
End Class

So, after connecting to the service (via channelfactory), the client first calls IsSomeUploadFileInProgress() Operation, and (only) if it returns false, then try to upload the file calling the UploadFile() Operation.

Hi hope my question was clear to you, and I ask you what is the best approach or solution for this?
By the way, the WFC service is implemented using InstanceContextMode.PerCall behavior.

King Regards.
Joaquim Campos

dotnet-standardwindows-wcf
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

LanHuang-MSFT avatar image
0 Votes"
LanHuang-MSFT answered

Hi @JoaquimCampos-1536,
Maybe you could try using the WCF test client, which can be used to test many types of WCF services, but not all - like duplex contracts are an unsupported class. You need to create some kind of client application to test it. In your client application, you need to write a class that implements the callback interface so that it can receive messages initiated by the service.
https://docs.microsoft.com/en-us/dotnet/framework/wcf/wcf-test-client-wcftestclient-exe
example:

 public class DuplexTemplate
 {
     [ServiceContract(CallbackContract = typeof(ICallback))]
     public interface ITest
     {
         [OperationContract]
         string Hello(string text);
     }
     [ServiceContract(Name = "IReallyWantCallback")]
     public interface ICallback
     {
         [OperationContract(IsOneWay = true)]
         void OnHello(string text);
     }
     public class Service : ITest
     {
         public string Hello(string text)
         {
             ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
             ThreadPool.QueueUserWorkItem(delegate
             {
                 callback.OnHello(text);
             });
    
             return text;
         }
     }
     class MyCallback : ICallback
     {
         AutoResetEvent evt;
         public MyCallback(AutoResetEvent evt)
         {
             this.evt = evt;
         }
    
         public void OnHello(string text)
         {
             Console.WriteLine("[callback] OnHello({0})", text);
             evt.Set();
         }
     }
     public static void Test()
     {
         string baseAddress = "net.tcp://" + Environment.MachineName + ":8000/Service";
         ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
         host.AddServiceEndpoint(typeof(ITest), new NetTcpBinding(SecurityMode.None), "");
         host.Open();
         Console.WriteLine("Host opened");
    
         AutoResetEvent evt = new AutoResetEvent(false);
         MyCallback callback = new MyCallback(evt);
         DuplexChannelFactory<ITest> factory = new DuplexChannelFactory<ITest>(
             new InstanceContext(callback),
             new NetTcpBinding(SecurityMode.None),
             new EndpointAddress(baseAddress));
         ITest proxy = factory.CreateChannel();
    
         Console.WriteLine(proxy.Hello("foo bar"));
         evt.WaitOne();
    
         ((IClientChannel)proxy).Close();
         factory.Close();
    
         Console.Write("Press ENTER to close the host");
         Console.ReadLine();
         host.Close();
     }
 }

Best regards,
Lan Huang


If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Bruce-SqlWork avatar image
0 Votes"
Bruce-SqlWork answered

the easiest is a static counter. be sure to use locking for multi-thread access

in file upload action inc at the start, dec at the end (be sure to use a finally for the decrement.

in is file uploading, just return if counter > 0

due to race conditions (delay between check and upload), more than one upload can happen at a time. if this is an issue, then you need a more complex solution

1) the client needs to get a ticket to upload (the ticket will have a timeout). the call to the server use a static to hold the current ticket. if the ticket is expired, null or not inuse, the server can return the new ticket else it returns rejected.

2) the load checks that the ticket matches current ticket and its not expired, then marks as inuse. when upload completed, delete the ticket.



5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.