Quantcast
Channel: C# Help » Remoting
Viewing all articles
Browse latest Browse all 10

.Net Remoting – Long-duration Invocations using C#

$
0
0

Sometimes server needs to perform lengthycalculations in reply to the client's request. If such calls are rareor do not take too much time, it's not a problem. If your solutionshows a tendency to have about 20-30 such invocations being performedconcurrently at the same time, you should consider the followingthings. Any process that makes any invocation remotely should becounted as well, because execution time usually is noticable and theyshould not hold on a Thread taken from the ThreadPool.

  1. Your server can meet ThreadPool limitations. In this case all .NET Remoting stuff and all things dependant on this will just stop working.
  2. You should apply a reasonable time-out on the client side.
  3. Do not forget about sponsorship. Client shouldhold on the server business object as well as server may want to attacha sponsor to client's object. Actually such things depend on design, sowe will not consider them in this article.
  4. A progress bar usually is not a problem at all. See this article for the sample.

Generally our plans can look so: weinitiate an action sending to the server our request. Server receivesit and runs a lengthy process in the dedicated background thread toavoid and ThreadPool-related problems. We will need to receive a resultfrom that thread, so we provide our callback to receive a result.

Using the code (the first solution)

Let's study the first sample. The known layer contains only interfaces:

A brief desciption of how to use the article or code. The class names, themethods and properties, any tricks or tips.

public interface IReceiveLengthyOperationResult
{
void ReceiveResult(string operationResult);
}

public interface IInitiateLengthyOperation
{
void StartOperation(string parameter,
IReceiveLengthyOperationResult resultReceiver);
}

Client initiates the operation execution and uses an instance of the ManualResetEvent class to check for the timeout.

static void Main(string[] args)
{
// Initiates the operation
iInitiateLengthyOperation.StartOperation("Operation N" +
random.Next(100).ToString(), new Client());

// and wait until it finishes or time is up
if (! InvocationCompletedEvent.WaitOne(5000, false))
Console.WriteLine("Time is up.");
}

// Is set when the invocation is completed.
public static ManualResetEvent InvocationCompletedEvent =
new ManualResetEvent(false);

// Is called by an operation executer to transfer the operation
// result to the client.
public void ReceiveResult(string operationResult)
{
Console.WriteLine("A result has been received from the server:
{0}.", operationResult);
InvocationCompletedEvent.Set();
}

Server implements lengthy operation provider that creates business objects run in the separate thread.

public class LengthyOperationImplementation
{
// Starts a lengthy process in the separate background thread.
public LengthyOperationImplementation(string parameter,
IReceiveLengthyOperationResult resultReceiver)
{
this._parameter = parameter;
this._iReceiveLengthyOperationResult = resultReceiver;

Thread thread = new Thread(new ThreadStart(this.Process));
thread.IsBackground = true;
thread.Start();
}

private string _parameter;
private IReceiveLengthyOperationResult
_iReceiveLengthyOperationResult;

// Simulates a long-duration calculations.
public void Process()
{
Console.WriteLine("We started long-duration calculations that
are expected to be finished in {0} milliseconds.",
CALL_DURATION_MS);
Thread.Sleep(CALL_DURATION_MS);
Console.WriteLine("Calculations are finished. Calling client
callback…");

// Warning: this call should be asyncrhonous. I can be
// lazy here only because I use Genuine Channels!
this._iReceiveLengthyOperationResult.ReceiveResult
(this._parameter.ToUpper());
}
}

What we've got finally with this approach?

  • We've run a request in the separate threadand avoided any Thread Pool-related problems. That's good and we can doany lengthy processing there or invoke remote peers' objects.
  • We have to write two interfaces for each type of long-duration invocations.
  • In general we need to write a separate class and create its instance for each request.
  • Client is able to keep track of timeout. We can use ThreadPool.RegisterWaitForSingleObject method to avoid holding on a thread on the client side.

Do you think it's a good idea to spend yourtime writing and supporting two interfaces and a class for each suchinvocation? No? Neither do I. We can get the same result by writing afew lines of code without any redundant interfaces or callbacks.

Using the code (the second solution)

Let's do the same with Genuine Channels now. And consider the difference!

Known layer contains the only one interfacecontaining a declaration of the operation. It receives necessaryparameters and return a result.

// Summary description for IPerformLengthyOperation.
public interface IPerformLengthyOperation
{
// Performs a lengthy operation.
string PerformOperation(string parameter);
}

Server just implements the operation andreturns a result. Please notice you have the simplest code you can havehere. You just perform an operation and return a result.

/// Starts a lengthy operation.
public string PerformOperation(string parameter)
{
Console.WriteLine("We started long-duration calculations that are
expected to be finished in {0} milliseconds.", CALL_DURATION_MS);
Thread.Sleep(CALL_DURATION_MS);
Console.WriteLine("Calculations are finished. Returning a
result…");

return parameter.ToUpper();
}

Client's side as simple as it is possible.The secret is in Security Session parameters that force thread contextand custom timeout for this call.

using(new SecurityContextKeeper(GlobalKeyStore.
DefaultCompressionLessContext + "?Thread&Timeout=5000"))
iPerformLengthyOperation.PerformOperation("Operation N" +
random.Next(100).ToString());

If you do not want to hold on client'sthread, make an asynchronous call within the same Security Sessionparameters. Thread and timeout parameters will work for it as well.

Downloads

<!– demo and source files –>

Download source (the first solution) – 133 Kb
Download source (the second solution) – 132 Kb


Viewing all articles
Browse latest Browse all 10

Trending Articles