Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More Classic .NET Remoting support #52

Open
igitur opened this issue Nov 20, 2023 · 2 comments
Open

More Classic .NET Remoting support #52

igitur opened this issue Nov 20, 2023 · 2 comments
Assignees
Labels
question Further information is requested

Comments

@igitur
Copy link
Contributor

igitur commented Nov 20, 2023

Hi,

I have a large legacy codebase with remoting calls via .NET Remoting so, of course, we're stuck on .NET Framework. This library looks like the perfect way to migrate to .NET Core. I had a look at the Classic Remoting API and it seems not all the classes and methods are implemented.

Examples of missing elements:

  • WellKnownClientTypeEntry
  • RemotingConfiguration.GetRegisteredWellKnownClientTypes()
  • RemotingConfiguration.GetRegisteredWellKnownServiceTypes()
  • and more

I'm willing to help out and submit PRs to fill the gap, but would like to check in with your first. I assume most of the lacking Classic Remoting API was just not implemented because nobody had a need for it so far, but I also assume that some of the APIs were deliberately omitted ( #47 is maybe such an example ).

Can we maybe brainstorm together in what way the Classic Remoting API can be enhanced further to reduce the effort involved in migrating from .NET Framework System.Runtime.Remoting?

Thanks for this project so far.

@theRainbird
Copy link
Owner

theRainbird commented Nov 21, 2023

Hi igitur,

Can we maybe brainstorm together in what way the Classic Remoting API can be enhanced further to reduce
the effort involved in migrating from .NET Framework System.Runtime.Remoting?

Yes, of course.

had a look at the Classic Remoting API and it seems not all the classes and methods are implemented.

Client Activated Objects (CAOs) are not easily realizable. This is because Castle.DynamicProxy, which is used under the hood to create proxies for remote objects in CoreRemoting, can only create proxies based on interfaces or abstract classes, but not regular classes. .NET Core has no integrated facility to create proxy objects. Castle.DynamicProxy is - as far as I know - currently the best possible solution.

This is why GetRegisteredWellKnownClientTypes and WellKnownClientTypeEntry are not implemented in CoreRemoting.

If your codebase uses CAOs, you will have to switch to Server Activated Objects (SAOs) and create interfaces for all remote classes, in order to get your code running with CoreRemoting. The proxy creation itself is easy to change. Instead of
var proxy = new RemoteClass();
write
var proxy = client.CreateProxy<IRemoteClass>();.

The object lifetime could make more trouble. In .NET Remoting the lifetime of a CAO is controlled through the client. When switching to SAO, the lifetime is controlled by the server and can be Singleton (lives forever) or SingleCall (lives only for one method call). This may impact the runtime behavior of your software.

Since the early days of .NET Remoting, CAOs have never been recommended due to their poor scalability.

There is one other limitation in CoreRemoting that may affect you (depending on the architecture of your codebase). In CoreRemoting Server and Clients are fixed roles. The server process provides services to clients. The clients consume services from the server. Remote events, delegates and callbacks can be used to notify clients actively from server side or vice versa. But a client can not provide services for the server. In .NET Remoting this possible, because .NET Remoting just remotes objects between different AppDomains (the client can also be a server).

In CoreRemoting Callbacks are special, when it comes to lifetime. Their lifetime is bound to the session. When the session is closed, references to callbacks are freed.

RemotingConfiguration.GetRegisteredWellKnownServiceTypes

A 1:1 implementation is not possible, because CoreRemoting doesn't work with object URIs and the services (remotable objects that are provided by the server process) are registered in a DI container. So you could easily get your registered services from the DI container. Please have a look at the following snippet:

var diContainer = RemotingServer.DefaultRemotingServer.ServiceRegistry;
IEnumerable<Type> serviceTypes = diContainer.GetAllRegisteredTypes();

This snippet uses the default remoting server. If you have only one server, this is fine. If you host multiple servers inside one process, every server must have a name (unique instance name) and the server instance must be addressed by its name. When using the app.config to configure CoreRemoting these unique instances must also be used. See example here: https://github.com/theRainbird/CoreRemoting/blob/master/CoreRemoting.Tests/TestConfig.xml

One last thing, that may cause trouble is the ability in .NET Remoting to pass a proxy that point to a object living on server process A to server process B and then to a client which can use it to directly commuicate to server A (.NET Remoting is creating implicit network connections based on channel and proxy metadata). This is not possible with CoreRemoting. In CoreRemoting a client connects to a server. This connection can only be used for communication between this client and this server. To communication with a second server, a new client instance needed (the RemotingClient object behaves similar to the SqlConnection object in ADO.NET).

@theRainbird theRainbird self-assigned this Nov 21, 2023
@theRainbird theRainbird added the question Further information is requested label Nov 21, 2023
@igitur
Copy link
Contributor Author

igitur commented Nov 22, 2023

Thanks, Hagen for a very thorough reply. Let's take this step by step. I'm on board that CAOs are not scalable. But I believe our current .NET Remoting implementation uses only SAOs. I believe that SAOs are defined by <wellKnown /> elements in the server and client configuration (if you're using XML configuration, as we are) and that CAOs are defined by <activated /> elements.

Minified example of our current server and client configurations:

<!-- server -->
<configuration>
  <system.runtime.remoting>
    <application>
      <channels>
        <channel ref="tcp" port="9009" />
      </channels>
      <service>
        <wellknown mode="Singleton" type="MyProject.RemotingClass, MyProject" objectUri="RemotingClass.rem" />
      </service>
    </application>
  </system.runtime.remoting>
</configuration>
<!-- client -->
<configuration>
  <system.runtime.remoting>
    <application>
      <client>
        <wellknown type="MyProject.IRemotingClass, MyProject" url="tcp://localhost:9009/RemotingClass.rem" />
      </client>
    </application>
  </system.runtime.remoting>
</configuration>

Unless I'm wrong, the registered entries above should be retrievable via RemotingConfiguration.GetRegisteredWellKnownClientTypes() on the client and RemotingConfiguration.GetRegisteredWellKnownServiceTypes() on the server. CAOs would use the analogous .GetRegisteredActivatedClientTypes() and .GetRegisteredActivatedServiceTypes().

Let me know if you agree with the above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants