|
Well, yes, FileStream is a MarshalByRefObject . But, internally, it has a cursor that is inside the client's file. That cursor is completely invalid on any other machine except the client. Trying to read data from a client machine through the server will just not work. There are only two ways to accomplish this: send the entire file to the server or open up a network channel on the client and allow the server to read the data through that channel.
Logifusion[^]
If not entertaining, write your Congressman.
|
|
|
|
|
See, I'm trying to understand .NET Remoting, and if object were people here is how I think they would talk (based on the code sample in my previous response).
Client To Server: "Server, Im sending u a FileStream object. If you want to know anything about it, let me know. From your point of you, this is just a description of the object. You can't do anything with it. Im just letting you know that I have this object and what features this object has. Ask me and I will tell you anything about it.
Server To Client: "Ok, I want you to read 4 bytes from the object starting at the begining and then send the bytes back to me."
Client To Server: [CLIENT Reads the 4 bytes locally] "Ok, there you go, I read the 4 bytes from the beginning and sent it to you."
So I thought thats the idea with MarshalByRefObjects as opposed to [Serializable] objects. If the cursor is invalid on any other machine then that shouldnt matter. Because the server machine is marshaling all calls to the client, the server is not actually doing anything with the object. When a certain function is executed on the object on the server, the server asks two questions "What do I need to pass to the client and what will the client return to me?" Then it marhals a call to the client.
I the case of "fileStream.Read(someData, 0, someData.Length);" the server doesnt do jack with filesSream, it just lets the client know that the it should read 4 bytes from the file and send it back to the server. Then the sever would store the data in "someData" array. If this is not the case then I am totaly lost.
-- modified at 14:51 Monday 31st July, 2006
|
|
|
|
|
Well, let's clear up the terminology a little bit. MarshalByRefObject indicates to remoting that a proxy has to be created. So, when you send a FileStream to the server, you're actually creating a proxy on the server side that it can pass it's calls through to the client. Calling it a pointer is what was confusing me because it sounded like you wanted to transfer the serialized FileStream object over to the server.
Anyways, you can use the FileStream on the server side, because .Net remoting will create the proxy for you. But this is very inefficient. The call to the proxy will be interpreted and sent to the client, which will do the work then interpret and send it back to the server, which has to be interpreted again and send back to the caller. It's much faster to open a channel and just send the file.
Also, I understand you have a client application and a server application and the file needs to go from client to server. But, in remoting, the side that has the proxy is the client. Your client application will actually have to become a server. This is my understanding of how it works anyway. The server appliation needs a proxy and the only way it can get that is by being a client.
Logifusion[^]
If not entertaining, write your Congressman.
|
|
|
|
|
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
|
|
|
|
|