Issue with remoting when different domains are used - c#

I have the following project:
server, client, remote object. client does something, then pass the proxy of remote object to the server. All the things work property until server and client are in different domains. Now, when I try to pass result to server I have an exception
"An unhandled exception of type 'System.Runtime.Remoting.RemotingException' occurred in mscorlib.dll
Additional information: This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server. "
some sources on Internet says that I need to create some additional channel but I don't know where and how should I do that because I have the channel registration on server and client yet.
Info:
server - domain 2
client - domain 1
remote object - domain 1
Thank you

Sounds like a permissions issue to me. How are you hosting your remoting objects? How are you authenticating across domains? Here's a decent article on some of the issues you might face with auth.
From this article ...
By default, a TCP client channel authenticates itself with the user identity under which the client process is running. You can specify an alternative identity by setting the domain, username, and password properties to specify an alternative identity
Have you specified correct credentials (including domain) on your channel properties?

then pass the proxy of remote object
to the server
Can you explain this? This doesn't sound like a good idea. Typically a proxy is used to invoke remote methods (RPC). Passing the proxy back to the server, doesn't make sense. Sure it may work in some scenarios, but it just adds unnecessary complication.
If you want to pass an object, create a separate data class and pass that as a parameter to the remote method.
Common.dll
[Serializable]
public class Data
{
int a;
int b;
}
[Serializable]
public class ResultData
{
int c;
}
public interface IServerInterface
{
ResultData DoSomething(Data data);
}
Server.dll
public class ServerObject : MarshalByRefObject, IServerInterface
{
public ResultData DoSomething(Data data)
{
// do some work on the server
return new ResultData();
}
}
Client.exe
class Program
{
static void Main(string[] args)
{
IServerInterface proxy = CreateProxy();
ResultData result = proxy.DoSomething(new Data());
}
}

Related

A connection attempt failed because the connected party did not properly respond... .NET Remoting

I have two apps on two computers. These apps are communicating by .NET Remoting.
First app acts as server for access to database, second app acts as client and writes that data to another database.
When my client calls some method on my remote object on server, I get following error:
A connection attempt failed because the connected party did not
properly respond after a period of time, or established connection
failed because connected host has failed to respond
192.168.200.60:31621
Well, that's nice, but I don't know anything about IP address 192.168.200.60, I was connecting to 172.XXX.XXX.216. It seems that there are two network connections and it's somehow not good for remoting.
ipcongif on my server look like that:
Exactly the same solution works on another 3 computers with Windows 2000, Windows XP and Windows 7. Server is developed in .NET Framework 2.0.
Client and server have common DLL library with two interfaces ICAOFactory and ICAO. First I create factory CAOFactory, which has method CreateCAO, which returns CAO object. When I call some method oh that ICAO object, it fails.
This is how my server app registers remoting object:
TcpChannel channel = new TcpChannel(31621);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(My_Server.CAOFactory), "My_Server", WellKnownObjectMode.Singleton);
This is how my client creates remote object:
My_Share.ICAOFactory srvFactory;
My_Share.ICAO srvCAO;
srvFactory = (My_Share.ICAOFactory)Activator.GetObject(typeof(Foerster_Share.ICAOFactory), "tcp://" + ip + ":" + port + "/My_Server");
srvCAO = srvFactory.CreateCAO(); // no problem
srvCAO.Init(dateTime); // problem
This is my CAOFactory object:
public class CAOFactory : MarshalByRefObject, ICAOFactory
{
public ICAO CreateCAO()
{
ICAO CAOObj = new CAO();
return CAOObj;
}
public void GetClientCount(out long clientCountSum, out long clientCountMax, out long clientCountActive)
{
clientCountSum = 0;
clientCountMax = 0;
clientCountActive = 0;
return;
}
public override object InitializeLifetimeService()
{
return null;
}
}
This is my CAO object:
public class CAO : MarshalByRefObject, ICAO
{
public void Ping()
{
return;
}
DateTime dtInit;
public void Init(DateTime dt)
{
dtInit = dt;
}
// + some other methods
}
Any help greatly appreciated!
What version of .NET are you targeting?
I think you need to use the bindTo property of the TcpChannel class https://msdn.microsoft.com/en-us/library/bb187434(v=vs.85).aspx to tell your server to bind to the correct NIC. This is probably most easily done in the configuration. Does your server project have an app.config? If not add one then add a section like this to it (this is copy/pasted from this question .Net Remoting: Indicate which local interface to use to connect to one server)
<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="tcp" port="0" bindTo="172.xxx.xxx.xxx" />
</channels>
</application>
</system.runtime.remoting>
</configuration>
This will tell the server to bind to the specific IP address.
Reordering network connection priority helped in my case.
http://ecross.mvps.org/howto/change-network-connection-priority-in-windows-10.htm
Press the Windows Key + X and select Network Connections from the menu.
Press the ALT key, click Advanced and then Advanced Settings.
Select the network connection and click the arrows to give priority to the network connection.
Click Ok when you are done organizing the priority of the network connection. The computer will now follow an order when connections are available.

Is there a way to make in WCF a datamember of datacontract as a reference to an instance of class in server?

I am moving .NET Remoting solution to WCF.
There are windows form client and WCF application server in session mode running as windows service and a layer of interaction application server and WCF core singleton server running as windows service too.
The structure of data consist of about 20 middle weight classes for core and application server with mostly composition relationship and with corresponding interfaces.
An interaction of a client and application server in .NET Remoting is provided by references to interfaces (proxies) on client to objects in server. That is working very well using full features of OOP. For example a Remoting request:
IDTGroupUser aDTGroupUser = addGroupUser( group, user, requestor);
Server side:
public IDTGroupUser addGroupUser(IDTGroup group, IDTUser user,
IDTGroupUser Requestor)
{
if (Requestor.User.IsSuperUser || Requestor.Group.IsAdmin)
{
DTGroupUser gu = new DTGroupUser(group, user, Requestor);
ISingletonSpace.groupUsers.Add(gu);
return gu;
}
else return null;
}
Now in WCF there is no object oriented approach.
So far I am trying to use server object's ID on client side to link to server objects. If client need something from server then
client sending with each request one additional parameter - ID and on the server side first is searched by ID that object and then
performed needed operation.
But this looks like a big bottleneck. WCF request:
int aDTGroupUser addGroupUser( gID, uID, requestorID);
Server side (where IDTUser, IDTGroup, IDTGroupUser and ISingletonSpace are endpoints):
public int addGroupUser( uint gID, uint uID, uint requestorID)
{
if (IDTUser.UserIsSuperUser(uID) || IDTGroup.GroupIsAdmin(gID)) // 2 searching
{
uint guID = IDTGroupUser.createGroupUser(gID, uID, requestorID); // 3 searching
ISingletonSpace.groupUsersAdd(guID); // 1 searching
return guID;
}
else return -1;
}
How to organize interaction between client and application server without searching the objects?
Is there a way to make a datamember of datacontract as reference to object in server?
Basically that is what you have got to do. You cannot directly transfer object references. A couple of things you could do-
1. Make object lookup dictionary based so that they are faster.
2. Pass the object id in the header of the request so that API is not cluttered with all of them taking object id. In your service contract you can first search the object with Id from header and then invoke method on that object.
Hope it helps.

Bouncy Castle TLS API usage

I want to communicate between Server and Client using sockets using bouncy castle TLS library.
I went through many documentation(which was insufficient for me) but I did not get any idea how to do this,
I am using BouncyCastle v1.7.48(runtime version=v2.0.50727) binary,
and I have found these info,
I have to use, Org.BouncyCastle.Crypto.Tls namespace and TlsProtocolHandler class.
To achieve TLS communication,
what API I should use in server side?
what API I should use in client side?
System.IO.Stream inputStream, outputStream;
TlsProtocolHandler tls = new TlsProtocolHandler(inputStream, outputStream);
What are the parameters inputStream and outputStream?
public virtual void Connect(TlsClient tlsClient);
where, TlsClient is an interface, and that contains many interfaces inside.
4. How to use the above API? I have to declare new classes and implement methods inside that to all?
Please help me with this Bouncy Castle.
EDIT 1:
I created one class which inherits from an abstract class called DefaultTlsClient.
Then I could create an instance of my class and pass it for interface reference.
So I could send the parameter like this. tls.Connect(tlsClient);
I am not initializing any parameters except I mentioned above.
(Sockets are connected before these operation on 2055)
But I am not sure handshake is complete or not. My program will go to reading state.
There is no server-side TLS API in bouncy castle. You can read on main page that they support only client-side.
For client-side you have found right classes already. TlsProtocolHandler does the job, but it won't work without custom classes. Here is example code:
// Need class with TlsClient in inheritance chain
class MyTlsClient : DefaultTlsClient
{
public override TlsAuthentication GetAuthentication()
{
return new MyTlsAuthentication();
}
}
// Need class to handle certificate auth
class MyTlsAuthentication : TlsAuthentication
{
public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
{
// return client certificate
return null;
}
public void NotifyServerCertificate(Certificate serverCertificate)
{
// validate server certificate
}
}
class Program
{
static void Main(string[] args)
{
TcpClient client = new TcpClient();
client.Connect(IPAddress.Loopback, 6000);
// input/output streams are deprecated, just pass client stream
TlsProtocolHandler handler = new TlsProtocolHandler(client.GetStream());
handler.Connect(new MyTlsClient());
// handshake completed
// use handler.Stream.Write/Read for sending app data
Console.ReadLine();
}
}
I have tested this with my tcp server and received client hello.
Keep in mind it is TLS in version 1.0 so if u need other version or server api then I recommend using other library (.NET framework supports TLS).

SignalR 1.0 - send data to a specific client

I want to be able to send messages to a specific client, I have working code but I cannot find a way to identify users, as on each page load/refresh the client id will change, so I cannot rely on that.
I have tried to append a querystring to the connection, but I have only been able to find the querystring of the same context.
This is my hub, and within the send method i want to be able to match the id that is sent in to a particular connection id at the point of sending the message:
public class Chat : Hub
{
public string addMsg()
{
return "";
}
public void Send(string message, string id)
{
Clients.Client(Context.ConnectionId).receiveMessage(message);
}
}
Here is my client code, i want to pass the id of the person to send a message to to the server send method, and use the querystring value of the other connected user to match it to the id i am sending.
var chat = $.connection.chat;
chat.client.receiveMessage = function (message) {
alert("Received from server: " + message);
};
chat.addMsg = function (message) {
};
$("#sendMessage").click(function () {
chat.server.send($('#newMessage').val(), 6);
});
$.connection.hub.qs = "id=1";
$.connection.hub.start().done(function () {
var myClientId = $.connection.hub.id;
var qs = $.connection.hub.qs;
});
I hope my question makes sense, I have been trying to crack this for a while now, below are some links to some of the articles i have used to get to where i am now, I am just missing the last piece of the puzzle, please go easy on me :)
http://weblogs.asp.net/davidfowler/archive/2012/11/11/microsoft-asp-net-signalr.aspx
SignalR- send data to a specific client
https://github.com/SignalR/SignalR/wiki/QuickStart-Hubs
I don't think this is going to work the way you want it to. The connection ID is just that -- an identifier for a particular connection. SignalR itself doesn't know anything about authenticating users. It is, however, built on top of ASP.NET and all of your familiar authentication methods (Windows, Forms, etc.) work as you would expect.
Once ASP.NET has authenticated the user, you have access to this in your hubs as Context.User. It's now up to you to maintain a mapping between this user and one or more connection IDs. Besides browser refreshes, you might need to deal with a user accessing your service from multiple browsers or machines. Sending a message to this user means sending it to all of those browsers and machines.
Jabbr does all this and more. You really should take a look at that code for a good way to implement this.
How about using the Clients.Caller object int he hub, and overriding the OnConnected method:
public override Task OnConnected()
{
Clients.Caller.sendInitMessage(...);
return base.OnConnected();
}

SignalR Client connection issues? Can't connect to path with HubConnection()

I've been trying to look in the wiki about doing this, I'm following it, but I seem to be missing something?
So here is where I am at:
I have a client side JS that works fine locally.
I now want to send something via an API to update the client side version.I should use SignalR Client right?
This is what i have:
var connection = new HubConnection("http://localhost/test/echo", useDefaultUrl: false);
Global.asax
RouteTable.Routes.MapConnection<MyConnection>("echo", "echo/{*operation}");
I'm getting an error along the lines of no cancellation token is declared....
Is it that I'm not hitting my HubConnection page?
If you need me to clarify let me know.
Thanks,
UPDATE:
Thanks for replying! I'm still uncertain on how a Hub can talk to a persistent connection?
This is what I have so far...
namespace ConnectionHubDemo{
public class ChatHub : Hub
{
public void SendMessage(string message)
{
Clients.NewMessage(message);
}
}
public class ConnectionHub
{
public string test(string data)
{
//Will this talk to my PersistentConnection?
var connection = new HubConnection("http://localhost/test", false);
var myHub = connection.CreateProxy("ConnectionHubDemo.ServiceHub");
//How would I send a message to my persisten connection?
//myHub...
//If succcessful bla bla bla
return data;
}
}
}
That's because you're not using Hubs. You're mixing Hubs and PersistentConnections. On the server Hubs are automatically routed so there's no need to map anything (see https://github.com/SignalR/SignalR/wiki/Hubs). From the wiki:
Unlike low level PersistentConnections, there's no need to specify a route for the hub as they are automatically accessible over a special url (/signalr). This url is configurable:
To make the client side work you just declare a HubConnection with the root url (see https://github.com/SignalR/SignalR/wiki/SignalR-Client-Hubs). Again from the documentation:
To connect to a hub using SignalR, create a HubConnection with the appropriate url.
NOTE: This url will not point to a specific connection. But will instead point to the root of your site.
Example
var connection = new HubConnection("http://mysite/");
So in your case, this would be:
var connection = new HubConnection("http://localhost/test");
Hope this helps.
UPDATE
Hubs DO NOT talk to persistent connections. All you have to do is follow the documentation. My answer above shows how to use Hubs on the server and on the client.
If you want to use Persistent connections then look at the documentation https://github.com/SignalR/SignalR/wiki/PersistentConnection (Server) and https://github.com/SignalR/SignalR/wiki/SignalR-Client (Client).

Categories

Resources