 |
|
 |
I must be missing something. This project is rated 3.6 and there are compliments. But when I downloaded the code, there were no project files, and even when I created project files and added the code files to them, the projects would not compile without changes. And when I run the projects, the client app hangs up in adding the event handler, then continues only after the server exits, at which point it crashes. Frustrating!
|
|
|
|
 |
|
 |
OK so the hang up and crash were due to security issues that are different in newer .Net (3.5). You have to specify a 'false' parameter to RegisterChannel. I have other examples using TcpChannel and none of them work reliably with the default or 'true', even when you configure the authentication.
But the code as presented should at least compile, which it did not.
|
|
|
|
 |
|
 |
How do we notify the client if the server ip address changes. Client will be communicating with old ip address and will not know the new Ip address to send a message.
|
|
|
|
 |
|
 |
I think that would be an example of "out-of-band" messsaging. You will have to communicate that some other way than just via a tcp message. There would have to be some way of discovering the new ip address, such as writing it in a commonly accessible disk location or web page.
|
|
|
|
 |
|
 |
I compiled mycomponent and server. When I run server everything is ok.
But when I run Client i get:
Subscribing
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Client' or one of its dependencies. The system cannot find the file specified.
File name: 'Client'
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke (System.Runtime.Remoting.Proxies.RealProxy rp, IMessage msg, System.Exception& exc, System.Object[]& out_args) [0x00185] in /build/buildd/mono-1.9.1+dfsg/mcs/class/corlib/System.Runtime.Remoting.Proxies/RealProxy.cs:227
Ayn idea?
|
|
|
|
 |
|
 |
Hi , I have a problem
I want to configure time to live of the server to be the maximum .
Can any one tell me how I can do that ?
Thanks a lot.
|
|
|
|
 |
|
 |
See in MSDN/.Net Development/.Net Framework/Programming with the .Net Framework/Accessing Objects in Other Application Domains Using .NET Remoting/.Net Remoting Overview/Objects Activation and Lifitimes/Server Activation, which says:
In COM, "singleton" meant that as long as clients had references to your object, the object would not be deleted from memory. In .NET remoting, however, a Singleton object is subject to the lifetime lease that was specified for it, so it can be recycled even if clients currently hold references to it. You can create the former type of Singleton object by overriding the InitializeLifetimeService method of MarshalByRefObject to return a null reference (Nothing in Visual Basic). This effectively keeps the object in memory as long as the host application domain is running. For details, see Lifetime Leases. You can create the latter type of Singleton object by configuring the initial lease time in the remoting configuration file.
Igal Pugach
|
|
|
|
 |
|
 |
Why are all the examples I can find console applications? I need to see an example where the event returned from the server then goes on to update the GUI, not Console.WriteLine. How about textBox1.AppendText(msg); There is something very different about the scenario, but I can't seem to figure out what, except that it locks up the client.
Sean
|
|
|
|
 |
|
|
 |
|
 |
I have setup per this example, even updating per one of the posts to use the BinarySink. Here is my problem.
I have implemented this in a Windows form, which has 2 widgets, a Button and a TextBox. When I click the button it runs a "go()" method which creates the Channel and creates the EventSink, etc.
I then created the EventSink class. In the example he wrote the returned value from the EventSink's callback method to the console. How can I access that same value from within my form? Since it is in a seperate class I can't call my form's methods or access my forms objects to update the TextBox. I have tried making EventSink a nested class inside of my main Form1 class. Then I passed EventSink a reference to my textBox. This will let me update the textBox when I first create the instance of the EventSink however it hangs when I try to update my textBox (or access any data) from my main form. Code below
internal class EventSink : AbstractBroadcastedMessageEventSink
{
public TextBox myForm;
public string MyString
{
get
{
return myForm.Text;
}
set
{
myForm.Text = value;
}
}
public EventSink(ref TextBox form)
{
// These Work
myForm = form;
form.Text = "Grrrr1";
form.Update();
myForm.Text = myForm.Text + Environment.NewLine + "Grrr2";
}
public void updateText(string str)
{
myForm.Text = str;
myForm.Update();
}
protected override void internalCallback(string str)
{
// This works
Console.WriteLine("Grrrrrrr: {0}", str);
// These all hang
updateText(str);
myForm.Text = "Testing";
Console.WriteLine("Blah: {0}", this.MyString);
this.MyString = "Grrrrrr";
}
}
public void go()
{
TcpChannel m_TcpChan = new TcpChannel(0);
ChannelServices.RegisterChannel(m_TcpChan);
AbstractedServer m_RemoteObject = (AbstractedServer)Activator.GetObject(typeof(AbstractedServer), "tcp://localhost:9999/MyServer");
RemotingConfiguration.RegisterWellKnownServiceType(typeof(EventSink), "ServerEvents", WellKnownObjectMode.Singleton);
EventSink sink = new EventSink(ref this.textBox1);
textBox1.Text = textBox1.Text + Environment.NewLine + "Subscribing to events";
textBox1.Update();
m_RemoteObject.myEvent += new myEventHandler(sink.myCallback);
textBox1.Text = textBox1.Text + Environment.NewLine + "Calling myFunc";
textBox1.Update();
// The following never gets called, the application hangs at this point string ret = m_RemoteObject.myFunc("Hello");
textBox1.Text = textBox1.Text + Environment.NewLine + "Called myFunc";
textBox1.Update();
textBox1.Text = textBox1.Text + Environment.NewLine + "Returned from myFunc: " + ret;
textBox1.Update();
}
I hope I provided enough information. And thank you to anybody who wishes to take this on.
|
|
|
|
 |
|
 |
Hello,
You need to do your GUI work in the GUI application thread. If you try to use the callback domain thread, then your GUI will lock-up because you are using the UI resources in an unsafe manner.
How do you do this? Take your callback data, put it into an event data structure, and then invoke your update method using a method invoker:
private void UpdateUI(object[] args)
{
MyUpdateState newState = (MyUpdateState)args[0];
// .. use your newState data to update the UI ..
}
internal void UpdateUI(MyUpdateState newState)
{
if(InvokeRequired) {
// This will invoke the UpdateUI using the current form's
// thread pool. You could also do BeginInvoke(..) to
// make this an asynchronous update.
//
//
this.Invoke(new MethodInvoker(UpdateUI), new object[] { newState }));
}
else {
UpateUI(new object[] { newState });
}
}
=============================
Jacob W Anderson
Software Consultant
http://www.javatopia.com
jwa@javatopia.com
-----------------------------
.NET and Java Development
=============================
|
|
|
|
 |
|
 |
Why does the client component need the two methods? Doesn't the server call the method and then it comes back to the client to actually run it? I tried to do it that way, but when the client attempt's to subscribe to the servers event it get a SerializationExcecption and complains that it doesn't know about the client's assembly. Why must it jump through the extra hoop?
-Kent
|
|
|
|
 |
|
 |
That is the exact problem. The server needs to know about the client, at least its interface.
|
|
|
|
 |
|
 |
You can always:
ObjRef internalRef = RemotingServices.Marshal(this, myUrl);
AbstractServer rem = RemotingServices.Unmarshal(internalRef) as AbstractServer;
in the server (once you have started the server) and then you can call methods on the rem object.
I am unclear why we need 2 tcp ports for this method.
|
|
|
|
 |
|
 |
got this to work with these changes....
///
/// Server Code Fixed with Full Permission (refer to Ingo Rammer
/// or www.glacialcomponents.com/Articles.aspx - serial exception V1.1 .Net
///
Server Code - Replace the following code...
TcpChannel m_TcpChan = new TcpChannel(props, clientProv, tpfProvider);
TcpChannel m_TcpChan = new TcpChannel(9999);
ChannelServices.RegisterChannel(m_TcpChan);
With this code.....
BinaryServerFormatterSinkProvider tpfProvider = new BinaryServerFormatterSinkProvider();
tpfProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = 9999;
TcpChannel m_TcpChan = new TcpChannel(props, clientProv, tpfProvider);
ChannelServices.RegisterChannel(m_TcpChan);
///
/// Client Code revised - I did a new console app and added some console
/// write statements so one can see what is going on.
///
using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using MyComponent;
namespace Client1
{
///
/// Summary description for Class1.
///
class Class1
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("Start Client");
TcpChannel m_TcpChan = new TcpChannel(1011);
ChannelServices.RegisterChannel(m_TcpChan);
AbstractServer m_RemoteObject = Activator.GetObject(typeof(AbstractServer),"tcp://localhost:9999/FirstRemote");
Activator.GetObject(typeof /localhost:9999/FirstRemote");
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(EventSink),
"ServerEvents",
WellKnownObjectMode.Singleton);
EventSink sink = new EventSink();
Console.WriteLine("Subscribing");
m_RemoteObject.myevent += new myeventhandler(sink.myCallback);
m_RemoteObject.myfunc("Hello");
Console.WriteLine("Message: Hello Sent");
Console.ReadLine();
}
}
class EventSink : AbstractBroadcastedMessageEventSink
{
protected override void internalcallback (string str)
{
Console.WriteLine("Your message in callback 2");
}
}
}
A. Burch
|
|
|
|
 |
|
 |
This 1st line in the Server Code - Replace the following code... was an edit mistake, it's not in the original source code, so disregard it. But the 2 lines following it do need to be replaced.
TcpChannel m_TcpChan = new TcpChannel(props, clientProv, tpfProvider);
|
|
|
|
 |
|
 |
That really helped I was getting no were! How does this progromatic configuration look in a config file? I just can't seem to get the sink set up right.
Matthew
|
|
|
|
 |
|
 |
OMG. Thank you so much, I was sooo stuck for ages thinking it was the Firewall settings... Great work! + thanks to the author for the solution.
|
|
|
|
 |
|
 |
Great article!!
I was searching for this for months. There are tons of other articles about remoting for accessing server resources, but almost nothing about using it for IPC.
There is no security exception here (I updated the framework to v1.1).
I tried the same with using a windows forms type server application,
but it does not work . When the application creates the form
object ( Application.Run(new Form1()); ), it throws an exception:
'System.TypeLoadException' in Server.exe
(Method myfunc in type Server.ServerClass from assembly myfunc does not have an implementation.)
Any idea how to do it correctly with forms?
|
|
|
|
 |
|
 |
I got this to work with these changes....
///
/// Server Code Fixed with Full Permission (refer to Ingo Rammer
/// or www.glacialcomponents.com/Articles.aspx - serial exception V1.1 .Net
///
Server Code - Replace the following code...
TcpChannel m_TcpChan = new TcpChannel(props, clientProv, tpfProvider);
TcpChannel m_TcpChan = new TcpChannel(9999);
ChannelServices.RegisterChannel(m_TcpChan);
With this code.....
BinaryServerFormatterSinkProvider tpfProvider = new BinaryServerFormatterSinkProvider();
tpfProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = 9999;
TcpChannel m_TcpChan = new TcpChannel(props, clientProv, tpfProvider);
ChannelServices.RegisterChannel(m_TcpChan);
///
/// Client Code revised - I did a new console app and added some console
/// write statements so one can see what is going on.
///
using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using MyComponent;
namespace Client1
{
///
/// Summary description for Class1.
///
class Class1
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("Start Client");
TcpChannel m_TcpChan = new TcpChannel(1011);
ChannelServices.RegisterChannel(m_TcpChan);
AbstractServer m_RemoteObject = Activator.GetObject(typeof(AbstractServer),"tcp://localhost:9999/FirstRemote");
Activator.GetObject(typeof /localhost:9999/FirstRemote");
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(EventSink),
"ServerEvents",
WellKnownObjectMode.Singleton);
EventSink sink = new EventSink();
Console.WriteLine("Subscribing");
m_RemoteObject.myevent += new myeventhandler(sink.myCallback);
m_RemoteObject.myfunc("Hello");
Console.WriteLine("Message: Hello Sent");
Console.ReadLine();
}
}
class EventSink : AbstractBroadcastedMessageEventSink
{
protected override void internalcallback (string str)
{
Console.WriteLine("Your message in callback 2");
}
}
}
A. Burch
|
|
|
|
 |
|
 |
I tried making all the the function signatures as "public" but it still throws an erro saying
An unhandled exception of type 'System.Security.SecurityException' occurred in mscorlib.dll
Additional information: Type System.DelegateSerializationHolder and the types derived from it (such as System.DelegateSerializationHolder) are not permitted to be deserialized at this security level.
Also is there no .config file settings required
|
|
|
|
 |
|
 |
You should register the channel in both the client and the server as following
BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
System.Collections.IDictionary props = new System.Collections.Hashtable();
props["port"] = 9999;
channel = new TcpChannel( props, clientProv, serverProv);
ChannelServices.RegisterChannel(channel);
instead
channel = new TcpChannel(9999);
ChannelServices.RegisterChannel(channel);
And remember to change 9999 to any other port number when registering the client channel
|
|
|
|
 |
|
|
 |
|
 |
How can I call the callback function to all of the connected clients ?
|
|
|
|
 |
|
 |
Change the server to this:
public override event myeventhandler myevent
{
add
{
Console.WriteLine("in event myevent + add");
myHandler += value;
}
remove
{
Console.WriteLine("in event myevent + remove");
myHandler -= value;
}
}
Also, to prevent potential crashing when clients disconnect, be sure to call m_RemoteObject.myevent -= {saved reference to client handler};
Chris
|
|
|
|
 |