Remoting Tutorial?

R

Rich

Can anyone suggest a good (current) tutorial on how to do basic
remoting with C# (2005 express edition)?
 
D

DeveloperX

There are some on CodeProject. Here's a mini program that won't run as
I've cut out all the gui stuff and replaced with ..., but it should
give you the idea. There are four projects in the solution, Client,
Server, Interface and Shared, the salient code for each is below.
Client, Server and Shared reference Interface, Server also references
Shared.
Server creates a real object, Client uses an interface so it is never
exposed to the remote object directly, Interface contains that
interface and shared the real implemenation of it that allows the
server to do things.
There are a lot of comments though, I'd trim it down properly but I
must go now, sorry!

Server-------------------------------------------------------------------------------------

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels.Tcp;

namespace Ian.Remoting
{
public class ServerGUI : System.Windows.Forms.Form
{
private delegate void UpdateTextDelegate(string pText);

//ObjRef transfers an object reference across appdomain boundaries
private ObjRef _refCalcRequest;
//Our Remoted object Remoted is the class name, it's not some cunning
keyword.
private Remoted _calcRequest;

...
private void ServerGUI_Load(object sender, System.EventArgs e)
{
//Set up the channel.
ChannelServices.RegisterChannel(new TcpChannel(50050));
//Using singleton model to get our Remoted instance.
_calcRequest = Remoted.Instance;
//Get the ObjRef
_refCalcRequest = RemotingServices.Marshal(_calcRequest, "Remoted");
//Hook up to the event so we know when a client is trying to do a
calculation
_calcRequest.CalcRequestEvent+=new
Ian.Remoting.Remoted.CalcRequestEventHandler(_calcRequest_CalcRequestEvent);
}

private void _calcRequest_CalcRequestEvent(object sender,
CalcRequestEventArgs e)
{
Random r = new Random();
//Invoke should always be required in this scenario, but this is
good practice.
if(this.InvokeRequired)
{
//Thread safely update the GUI
this.BeginInvoke(new UpdateTextDelegate(UpdateText), new object[]
{e.Name + " Submitted: " + e.Calculation});
}
//Populate the EventArgs results field so when we exit the Remoted
can return the results.
e.Results = new double[] {r.NextDouble() * 10 , r.NextDouble() *
10};
}
private void UpdateText(string pText)
{
textBox1.Text+="\r\n" + pText;
}
}
}


Shared------------------------------------------------------------------------------------------


namespace Ian.Remoting
{
public class Remoted : MarshalByRefObject , IRemoted
{
//The event and delegate used when the user calls calculate. This
notifies the server.
public delegate void CalcRequestEventHandler(object sender,
CalcRequestEventArgs e);
public event CalcRequestEventHandler CalcRequestEvent;

//Singleton
private static Remoted _instance;

private Remoted()
{
}
public static Remoted Instance
{
get
{
if(null==_instance)
{
_instance=new Remoted();
}
return _instance;
}
}
public override Object InitializeLifetimeService()
{
// Allow this object to live "forever". Even singletons are
collected after a default of 5 minutes normally.
return null;
}
double[] IRemoted.Calculate(string pCalculation, string pName)
{
//The user has access to IRemoted and has called Calculate on it. We
manage concurrency by creating a new EventArgs to hold
//our info then raise the event which the server consumes.
CalcRequestEventArgs calcRequest = new
CalcRequestEventArgs(pCalculation, pName);

if(null != CalcRequestEvent)
{
CalcRequestEvent(this,calcRequest);
//This would of been populated by the server.
return calcRequest.Results;
}
else
{
return new double[] {-1.0};
}
}
}

public class CalcRequestEventArgs : EventArgs
{
private string _calculation;
private double[] _results;
private string _name;

public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public string Calculation
{
get
{
return _calculation;
}
}
public double[] Results
{
get
{
return _results;
}
set
{
_results = value;
}
}
public CalcRequestEventArgs(string pCalculation, string pName)
{
_calculation = pCalculation;
_name = pName;
}
}

}

Interface
---------------------------------------------------------------------------------------------

using System;

namespace Ian.Remoting
{

public interface IRemoted
{
double[] Calculate(string pCalculation, string pName);
}
}



Client
-----------------------------------------------------------------------------------------------------------------

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels.Tcp;

namespace Ian.Remoting
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class ClientGUI : System.Windows.Forms.Form
{

private IRemoted _remoted; //Remoted implements IRemoted. We hold a
reference the the interface not the concrete object

private delegate void SetTextDelegate(string pText); //Used to
thread safe update the GUI as we're using Async callbacks
private delegate double[] DoCalculationDelegate(string pName, string
pCalculation); //Used to call the Calculate method on IRemoted

...

private void button1_Click(object sender, System.EventArgs e)
{
txtResults.Text = string.Empty;

//Our Async callback will call CalculationCallback on completion
AsyncCallback acb = new AsyncCallback(this.CalculationCallback);
//DoCalculationDelegate has the same signature as IRemoted.Calculate
DoCalculationDelegate d = new
DoCalculationDelegate(_remoted.Calculate);
//Invoke the Delegate with the parameters. the AsyncCallback and
null (not sure what object represents)
IAsyncResult ar = d.BeginInvoke(txtName.Text,txtCalculation.Text,
acb, null);

}
public void CalculationCallback(IAsyncResult ar)
{
//The call to the remote object has ended and called here to let us
know.
//Get our delegate out so we can end it.
DoCalculationDelegate del =
(DoCalculationDelegate)((AsyncResult)ar).AsyncDelegate;
try
{
//del's signature is the same as calculate, so we expect an array
of doubles out.
double[] results = (double[])del.EndInvoke(ar);
string output="";
foreach(double r in results)
{
output+=r.ToString() + " ";
}
//Thread safely call Updateoutput with our new output.
this.BeginInvoke finds this control's thread and fires the delegate on
it.
this.BeginInvoke(new SetTextDelegate(UpdateOutput),new
object[]{output});
}
catch(Exception e)
{
this.BeginInvoke(new SetTextDelegate(UpdateOutput),new
object[]{e.Message});
}
}
private void UpdateOutput(string pText)
{
txtResults.Text = pText;
}
private void ClientGUI_Load(object sender, System.EventArgs e)
{
//Register a channel
ChannelServices.RegisterChannel(new TcpChannel());
//retrieve the remote object. On the server side it will be a
concrete object of type Remoted
_remoted = (IRemoted)Activator.GetObject(typeof(IRemoted),
"tcp://localhost:50050/Remoted");
}
}
}
 
R

Rich

Perhaps I have a more basic problem. I have tried the TCP approach (as
you show here) and I have tried an IPC approach. The first problem I
have is that VS2005 Express chokes on either of the following:

using System.Runtime.Remoting.Channels.Ipc;
or
using System.Runtime.Remoting.Channels.Tcp;

I get a compile error:
The type or namespace name 'Ipc' (or 'Tcp') does not exist in the
namespace 'System.Runtime.Remoting.Channels' (are you missing an
assembly reference?)

Is this a limitation of the Express version?

Thanks,
 
J

JS

I'm not sure what the express edition supports, but check that you have
added a reference to the System.Runtime.Remoting dll.
 
D

DeveloperX

Yep, I got exactly the same error the first time I palyed with
remoting, and it's because you need to add the reference. I checked in
Express and the assembly is available and can be added to the project.

Something I wanted to say the other day was the above hacked up example
is a Server activated object, there are also client activated objects.
The difference is basically SAO's can't hold state, but CAO's can. That
might help when you're googling.
As mentioned previously, there are lots of tutorials on CodeProject.
It's a while ago, but I think the code above was based on a couple of
their tutorials. It's part of a series of tech primers I wrote for
work.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top