|
I don't know why it is failing for you. I've done the same thing with a memory stream between appDomains, which should perform the same way, but it might not. It probably makes more sense to create your own marshalByRef proxy object wrapping the filestream to pass in as a parameter. That will give you more freedom to change the internal implementation in the future and you should be able to debug the methods of your custom object.
Also, if you are running these from seperate systems disable any firewalls that might be causing problems allowing the return connection from the server back to the client.
-- modified at 16:22 Monday 31st July, 2006
I can imagine the sinking feeling one would have after ordering my book,
only to find a laughably ridiculous theory with demented logic once the book arrives - Mark McCutcheon
|
|
|
|
|
I somehow think it has something to do with secuirty. I am going to dig into it a bit, it's just frustrates me how little there is on .net remoting there is. Even books like "Advanced .NET Remoting" would start off with chat client sample and then divulge into writing your own sinks and lease times and all that, not single one tutorial used something like passing a Form or a Button from client to server, its all strings and ints and bytes.
|
|
|
|
|
A typical, safe deployment of remoting is to keep valuable resources local and make value data passable. Now in your example you wanted to have something remote and get bits of data from the file. To actually do this there are one of two ways that you can safely do it:
1) make successive remote calls to a server side component. The server side component manages what file it is working with, where in the file the last process occured, and what needs to be returned next. The data itself would marshal across but the rare resource (file handle) remains on the server.
However...the above scenario will only work if you have very long lags between each request and you can maintain. If, on the other hand, you need to frequently interogate the data then you do a client/server deployment as follows:
2) Server side gets the entire file and marshals it across to a client interface. The client interface is the go-between between your code and the server. It's job is to maintain the data it gets from the server (determines if it needs to get new data or not), as well as all of the tasks listed in 1).
Now in the second scenario you are thread-safe, have a handle on the data, and make your remoting call 'chunky'. Keep in mind that chunky calls is the difference between having a performing application and having half-hour response time for a user process.
|
|
|
|
|
Thanks for all your help so far. Conside the following C# 2.0 simple client-server code:
Client:
--------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.IO;
namespace RemotingTest
{
class Program
{
static void Main(string[] args)
{
IDictionary properties = new Hashtable();
SoapClientFormatterSinkProvider clientSinkProvider = new SoapClientFormatterSinkProvider();
SoapServerFormatterSinkProvider serverSinkProvider = new SoapServerFormatterSinkProvider();
serverSinkProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
properties["name"] = "";
properties["port"] = 0;
properties["typeFilterLevel"] = "Full";
HttpChannel httpChannel = new HttpChannel(properties, clientSinkProvider, serverSinkProvider);
ChannelServices.RegisterChannel(httpChannel, false);
RemotingConfiguration.RegisterWellKnownClientType(
typeof(ServerInterface),
"http://igor.no-ip.ca:1024/Server"); // change to appropriate address here
ServerInterface server = new ServerInterface();
string text = "";
while((text = Console.ReadLine()) != "Quit")
{
Console.WriteLine(server.ShowText("testing string"));
Console.WriteLine(server.ShowFileInfo(text).Name);
}
Console.Read();
}
}
}
Server Interface:
------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace RemotingTest
{
public class ServerInterface: MarshalByRefObject
{
public FileInfo ShowFileInfo(string filename)
{
Console.WriteLine("Filename " + filename + " requested");
return new FileInfo(filename);
}
public string ShowText(string text)
{
Console.WriteLine(text);
return "\"" + text + "\" show on the server.";
}
}
}
Server:
-------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
namespace RemotingTest
{
class Program
{
static void Main(string[] args)
{
IDictionary properties = new Hashtable();
SoapServerFormatterSinkProvider serverSinkProvider = new SoapServerFormatterSinkProvider();
serverSinkProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
properties["name"] = "";
properties["port"] = 1024;
properties["typeFilterLevel"] = "Full";
HttpChannel httpChannel = new HttpChannel(properties, null, serverSinkProvider);
ChannelServices.RegisterChannel(httpChannel, false);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(ServerInterface),
"Server", WellKnownObjectMode.SingleCall);
Console.Read();
}
}
}
-------------------------------------------------------------------------
The above sample would work no problem if you launch the server and client on the same machine. However, move them across machine boundries and you will find that passing a string and getting a response from server.ShowText() works, but the client will give you an exception after 30 sec. or so trying to execute server.ShowFileInfo();
To test the programs, enter properly formatted filenames, like "C:\test.txt" or something in the client and if you want to quit, type in "Quit". The filename does not have to exist, it just has to have proper format.
For you convinience, i zipped up VS2005 solution here: http://igor.no-ip.ca/remoting%20test.zip
Thanks!
|
|
|
|
|
Am I missing something here? Why is your client not calling Activator.CreateInstance or Activator.GetObject?
Logifusion[^]
If not entertaining, write your Congressman.
|
|
|
|
|
Beacause I called RegisterWellKnownClientType() on the client. That allows me to instantiate objects using "new". MSDN: http://msdn2.microsoft.com/en-us/library/hcd5d6y7.aspx
|
|
|
|
|
Ah ok. So what happens if you have your file on both machines in the same place?
Logifusion[^]
If not entertaining, write your Congressman.
|
|
|
|
|
You mean the file that I pass to server.ShowFileInfo() method? If I have a file named text.txt on drive C:\ on both server and client the proram would still fail.
|
|
|
|
|
Just eliminating possibilities. Your code works fine on two different machines. Normally I'd say it's a security problem, but if you're logged into both machines running a console app, then that's not really a concern.
Logifusion[^]
If not entertaining, write your Congressman.
|
|
|
|
|
Hmm, I did test this code across my home and work computers. Maybe I should try other combinations. What I do is I have the client running on the machine that I am using, and the server on the machine that I use remote desktop to connect to. It could also be a prob. with firewall. On the server machine that I use Remote Desktop to connect to I have port 1024 open. Maybe when the whole marshalling process takes place other ports need to be open that I dont know about?
|
|
|
|
|
Ya, it does sound odd. You're able to get past the first statement, so there's definitely a connection. Since you're remote desktop'd into the work server, your server app is running under whatever windows user you have, so that's not a problem as long as you can access that file. Can you try a TcpChannel instead to see if that has any different results? There might be firewall issues there somewhere. Maybe you can grant that server application access through the firewall?
Logifusion[^]
If not entertaining, write your Congressman.
|
|
|
|
|
I changed the channels to Tcp and both server and client are setup with Windows Firewall. That didnt help. I am going to try this code on a local network where a router will not be invlolved and I will turn off firewalls.
|
|
|
|
|
I found the problem !!! The programs do work on separate computers over a local network. Firewalls were turned off, so they are not the problem. Port forwarding on the routers must be the problem. Why the ShowText() method works and ShowFileInfo() fails is a mystery. Maybe there are more ports open then one would think. ShowFileInfo() does return a reference to an object, so maybe there is some sort of 2-way communictaion happening that requires additional ports.
-- modified at 15:44 Thursday 3rd August, 2006
|
|
|
|
|
Mk, after further examintation and tracing using Wireshack (formerly Ethereal) here is what I found.
Firs the setup.
Home computer which has the server:
address: igor.no-ip.ca
local address of nic: 10.0.0.1
Work computer which has the client:
address: pennylane.no-ip.ca
local nic address: 192.168.0.101
Both computers are behind routers with port 1024 open and forwarded.
Basicaly, looking at the soap messages, it looks like when ShowText() method is called, the soap message is relatively small. When ShowFileInfo() method is called, the soap message is big, and one of the entries in that message is address 10.0.0.1, which is the local address of the server, and to the client has no meaning. But, after receiving that message, the client tries to connect to 10.0.0.1 on port 1024!
Here is the trace:
---------------------------------------------------------------------------------------
http://img394.imageshack.us/img394/3109/remotingtestyk0.png
-------------------------------------------------------------------------------
If you look at server's soap response message (the last one) you will see that item id="ref-17" is set to http://10.0.0.1:1024. The client must be reading this value because the next thing it does is it tries to connect to 10.0.0.1:1024, which, ofcourse, fails.
Here are complete trace files in case you are interested: http://igor.no-ip.ca/remoting%20trace%20test.zip (tcpdump / ethereal format)
VS2005 Solution: http://igor.no-ip.ca/remoting%20test.zip
Any ideas?
-- modified at 14:23 Friday 4th August, 2006
|
|
|
|
|
|
Thanks for the quick reply. I actually figured out the problem. May not be a problem after all, just the way .NET developers designed the library. There is a peculiar channel property called "machineName" which by default you shouln't have to worry about: http://msdn2.microsoft.com/en-us/library/kw7c6kwc(d=ide).aspx#machineName
Setting the property on the server to the current "outside" address solves the problem !!! Here is what I think happens:
When ShowText() is called, nothing special takes place b/c the client knows what to pass and what to get back. Done deal. With ShowFileInfo(), the FileInfo object can incurr additional calls from the client side. That is why in that case the server will return a message with a bunch of stuff and one of them being the server's ip address. Dont know whats the need for that, since the client already knows the server's ip address. But the server is "dumb" enough to put its local address in message, not the wan address. So setting "machineName" to the wan address of the server does the trick. Here is the soap message returned by the server to the client upon ShowFileInfo():
http://img185.imageshack.us/img185/1772/remotingtestworksfu1.png
Note how item id="ref-17 is now set to "igor.no-ip.ca:1024" as opposed to "10.0.0.1:1024". It makes sence now.
So here, in all glory is a working code:
----------------------------------------
Client:
<br />
using System;<br />
using System.Collections;<br />
using System.Collections.Generic;<br />
using System.Text;<br />
using System.Runtime.Remoting;<br />
using System.Runtime.Remoting.Channels;<br />
using System.Runtime.Remoting.Channels.Http;<br />
using System.IO;<br />
<br />
namespace RemotingTest<br />
{<br />
class Program<br />
{<br />
static void Main(string[] args)<br />
{<br />
IDictionary properties = new Hashtable();<br />
<br />
SoapClientFormatterSinkProvider clientSinkProvider = new SoapClientFormatterSinkProvider();<br />
SoapServerFormatterSinkProvider serverSinkProvider = new SoapServerFormatterSinkProvider();<br />
<br />
serverSinkProvider.TypeFilterLevel =<br />
System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;<br />
<br />
properties["name"] = "";<br />
properties["port"] = 0;<br />
properties["typeFilterLevel"] = "Full";<br />
<br />
HttpChannel commChannel = new HttpChannel(properties, clientSinkProvider, serverSinkProvider);<br />
<br />
ChannelServices.RegisterChannel(commChannel, false);<br />
<br />
RemotingConfiguration.RegisterWellKnownClientType(<br />
typeof(ServerInterface),<br />
"http://igor.no-ip.ca:1024/Server");
<br />
ServerInterface server = new ServerInterface();<br />
<br />
string text = "";<br />
<br />
while((text = Console.ReadLine()) != "Quit")<br />
{<br />
Console.WriteLine(server.ShowText("testing string"));<br />
Console.WriteLine(server.ShowFileInfo(text).Name);<br />
}<br />
<br />
Console.Read();<br />
}<br />
}<br />
}<br />
Server Interface:
-----------------------
<br />
using System;<br />
using System.Collections.Generic;<br />
using System.Text;<br />
using System.IO;<br />
<br />
namespace RemotingTest<br />
{<br />
public class ServerInterface: MarshalByRefObject <br />
{<br />
public FileInfo ShowFileInfo(string filename)<br />
{<br />
Console.WriteLine("Filename " + filename + " requested");<br />
<br />
return new FileInfo(filename);<br />
}<br />
<br />
public string ShowText(string text)<br />
{<br />
Console.WriteLine(text);<br />
<br />
return "\"" + text + "\" show on the server.";<br />
}<br />
}<br />
}<br />
Server:
-------------------
<br />
using System;<br />
using System.Collections;<br />
using System.Collections.Generic;<br />
using System.Text;<br />
using System.Runtime.Remoting;<br />
using System.Runtime.Remoting.Channels;<br />
using System.Runtime.Remoting.Channels.Http;<br />
<br />
namespace RemotingTest<br />
{<br />
class Program<br />
{<br />
static void Main(string[] args)<br />
{<br />
IDictionary properties = new Hashtable();<br />
<br />
SoapServerFormatterSinkProvider serverSinkProvider = new SoapServerFormatterSinkProvider();<br />
<br />
serverSinkProvider.TypeFilterLevel =<br />
System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;<br />
<br />
properties["name"] = "";<br />
properties["port"] = 1024;<br />
properties["typeFilterLevel"] = "Full";<br />
properties["machineName"] = "igor.no-ip.ca";
<br />
HttpChannel commChannel = new HttpChannel(properties, null, serverSinkProvider);<br />
<br />
ChannelServices.RegisterChannel(commChannel, false);<br />
<br />
RemotingConfiguration.RegisterWellKnownServiceType(<br />
typeof(ServerInterface),<br />
"Server", WellKnownObjectMode.SingleCall);<br />
<br />
Console.Read();<br />
}<br />
}<br />
}<br />
----------------------
Now its time for me to write an article on this. Having a router is quite common, and Im sure other programmers will stumble on the same problem.
Thanks for all you help guys!!
-- modified at 15:31 Friday 4th August, 2006
|
|
|
|
|
Okay, that's great! You still have a broken network and I would highly suggest you fix it before you go much further and I mean that seriously. Please don't be advising others on how something may work until you've tested it thoroughly on a functioning network.
- Rex
|
|
|
|
|
I did follow your guide and changed everything to the suggested settings. It was very detailed, thank you. It did not solve my problem though, but I am sure it will prevent me from having other network-related problems.
-- modified at 9:18 Saturday 5th August, 2006
|
|
|
|
|
Does anyone have an idea of how to get a DataGridView column to display as a button with an icon?
My current application displays just the icon, as an image, but it would be more obvious that the icons can be clicked and aren't just status icons if the cell containing them looked like a button. When I set the column type to Button, there does not appear to be any way to assign an image, only text, to a cell. So, is it possible to have a cell that is obviously a button which has an icon upon it?
I thought this would be a more common issue than it seems to be!
Thanks for your help!
|
|
|
|
|
Hi everybody, i used a thread to process a button function inside my code and because of that i used the showDialog function to open another forms from the thread, but i am trying to close the form i opend by using the ShowDialog function and it didnt work. How can i make an instance from the Active form i showed by the ShowDialog in order to close it later .
Any help please
Thanx
I hope that i am helping programmers
|
|
|
|
|
Ramez Quneibi wrote: used a thread to process a button function inside my code
Could you elaborate on that a little bit? My guess is your problem has something to do with threading. You cannot access a control on a thread other than the one it was created on.
Tech, life, family, faith: Give me a visit.
I'm currently blogging about: Messianic Instrumentals (with audio)
The apostle Paul, modernly speaking: Epistles of Paul
Judah Himango
|
|
|
|
|
Here i am showing you snippets from my code to elaborate on the problem to you
These snippets form Form1 class :
static void Main()
{
Application.Run(new Form1());
}
private void button1_Click(object sender, System.EventArgs e)
{
System.Threading.Thread NewFormMaker = new System.Threading.Thread(new System.Threading.ThreadStart(Dummy));
NewFormMaker.Start();
}
public static void Dummy()
{
Form2 fmNew = new Form2();
fmNew.ShowDialog();
}
This is a snippet from Form2 class :
// When this button pressed from Form2 this function should create new
// form with new controls and close the previous one
private void Next_Click(object sender, System.EventArgs e)
{
// Create an instance from the active form to close it
Form2 tempForm=(Form2)Form2.ActiveForm;
// Call Dummy() function from Form1 to show the new results
Form1.Dummy();
// Close the previous form with the old results
tempForm.Close();
}
The problem is that i cant make an instance from the active form to close it when i press button next from Form2.
Thanx
I hope that i am helping programmers
-- modified at 3:42 Tuesday 1st August, 2006
|
|
|
|
|
Ramez Quneibi wrote: he problem is that i cant make an instance from the active form to close it when i press button next from Form2.
OK, a couple things worth mentioning here. If you need to pass an instance of form1 over to form2, add an argument to the Form2 constructor that stores the form1 instance:
class Form2
{
readonly Form1 firstFormInstance;
public Form2(Form1 instance)
{
this.firstFormInstance = instance;
}
}
A second thing to note is that you cannot access a control or a form on a thread other than the one it was created on. Say you have Form1 instance created by "thread1". You start a new thread, "thread2" to launch a new Form2 instance. This is all valid, however, inside form2, you cannot access form1 because it was created by a different thread. If you need to do that, you'll need to use form1.Invoke or form1.BeginInvoke, which will invoke some method on the correct thread for form1.
Tech, life, family, faith: Give me a visit.
I'm currently blogging about: Messianic Instrumentals (with audio)
The apostle Paul, modernly speaking: Epistles of Paul
Judah Himango
|
|
|
|
|
I used these techniques you told me about ,it may work in other applications but it my code it didnt. I used another thread to show form2 from form1 but i didnt work because i am filling form2 from form1 class and if i make another thread i cant fill form2 from form1 class.
Anyways...I am using this technique to avoid the from freezing when i start the application because i have a very long process consumes 2 mins, the form in this duration freezes and stop me to do anything, if you can help me to give another technique i will appreciate .
Thanx alot .
|
|
|
|
|
Ramez Quneibi wrote: I am using this technique to avoid the from freezing when i start the application because i have a very long process consumes 2 mins
Don't use a 2nd thread to start the form. If the form itself is doing lots of work, have the form use a background thread to perform the work, thus keeping the UI thread free. You should never do any large amount of work on the UI thread. If you are, most likely you have designed your application incorrectly.
I recommend launching form2 from form1 using the same thread that's running form1. If form2 is doing lots of work, make form2 start a background thread to do the work.
|
|
|
|
|