1

I've read a fair bit on remoting but nearly all of it seems to be from the context of the child calling the server so I'm pretty confused on what I should do here.

I have a .NET 3.5 server application that compiles a set of C# scripts into a separate application domain. All calls into this application domain are synchronous and they get a newly created 'provider' object inheriting MarshalByRefObject which they can use to access functionality from the server application domain.

So I have the following heavily simplified example, running in the server appdomain:

object RunScript()
{
    var myProvider = new MyProvider(this); // Inherits MarshalByRefObject 

    // Passes myProvider to the script appdomain
    var results = CallAMethodInScriptAppDomain(myProvider); 

    // I want myProvider to be garbage collectable from here.

    return results;
}

I did try getting it to work with sponsors and leases in the past but whatever I did it was still getting collected. I think that was because they were designed to be used from the client and I'm trying to manage the lifetime of this object from the server.

The fact is I know exactly at which line of code in the server appdomain I want it to be collected (or rather be collectable), and it must not be collected before that no matter how long the script call takes (most script calls will be in the order of a few ms, but theoretically some could take hours).

Currently my InitializeLifetimeService returns null because that was the only way I could get it to not collect while my scripts were running.

Any idea?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Nick Thompson
  • 73
  • 1
  • 5
  • Welcome to Stack Overflow! Remoting is a legacy technology that is retained for backward compatibility with existing applications and is not recommended for new development. Distributed applications should now be developed using WCF or ASP.NET Web API. See the note at the top of http://msdn.microsoft.com/en-us/library/vstudio/xws7132e.aspx for proof. – John Saunders Dec 23 '14 at 15:24
  • This isn't really new development, it's 5 years old we've just now got a new client that has a much heavier workload on the scripting system which means the memory leak I've got at the moment has suddenly become an issue. Note that this isn't a 'distributed' application as such, it all runs in a single process. It's just the scripts that are in their own AppDomain for the purposes of sandboxing and recompiling and the communication between them uses remoting. Does WCF still apply to that scenario? – Nick Thompson Dec 23 '14 at 15:30
  • Yes, WCF would apply if this were new development. I believe there are channel types optimized for in-memory scenarios. – John Saunders Dec 23 '14 at 15:33
  • @JohnSaunders Well, there are scenarios where .NET Remoting is still useful. For example to exchange the data across AppDomains. It is faster in comparison to WCF. – Sergey Oct 26 '18 at 20:27

1 Answers1

2

InitializeLifetimeService should return an ILease implementation which your can register an ISponsor implementation with. The sponsor could have a property Finished that is set to true when you are done with the server class, and when the framework calls Renewal on the lease your sponsor can check the property and renew the lease if Finished is false.

This article explains is qutie nicely: http://msdn.microsoft.com/en-us/magazine/cc300474.aspx

and has code you can copy.

Kell
  • 3,252
  • 20
  • 19
  • I wonder if where I was going wrong is the location at which I was creating the sponsor, should I actually be creating this in the script application domain? I was originally trying to create it in the server app domain because it's the server that knows when it's finished with the class. I think I read though the article you linked several times but just ended up more confused because it didn't really explain very well where I should be doing things when it's the server that is knows what the lifetime of the object should be rather than the client. – Nick Thompson Dec 23 '14 at 15:25
  • I would be tempted to pass back the provider (as an interface) to the server and let the server call the CallAMethodInScriptAppDomain in this case and you won't need to worry about lifetimes as the server will have a handle on the object and can dispose it when it's done, though I realise having read your later comments that this is a legacy app so it may not be feasable. – Kell Dec 23 '14 at 15:33
  • I'm not sure whether you've misunderstood what's going on or if I've misunderstood your response. The server creates the provider (which calls out to stuff across the server), and passes it (or rather its proxy) to the scripts so they can access those services indirectly. So the server has a handle to the object, and can dispose of all its children, the problem is the provider object itself (and a load of remoting objects) is kept alive, I think because I'm not returning a lease as you said. – Nick Thompson Dec 23 '14 at 15:40
  • I think what I need to do is within the script app domain (within the CallAMethodInScriptAppDomain) call, register the sponsor so that it can keep it's connection to the provider alive, and change the provider to return a lease object. That's probably the best way to do it, however I think I've just worked out a way I can use a single provider object for all script call, will see if that works because that may be a lot easier and have less chance to go wrong on me. – Nick Thompson Dec 23 '14 at 15:42
  • Yeah, not returning a lease will result in imortal (or immoral :) ) client classes. Sorry, I did get mixed up because you have a server app creating objects which are then clients to the server but which are the servers to the server if you know what I mean (since they provide methods for the server to call). – Kell Dec 23 '14 at 15:49
  • It's irritating to have the overhead of creating sponsors (which presumably create a separate thread to do their thing) when having a line of code at the end to say I'm done with it would be sufficient in this use case. Right now I've managed to get it down to a single system wide provider which then holds the call specific information internally in a dictionary and it seems to be working, about 10 new uncollected objects (looks like remoting cache) rather than 20k which is good progress. I'll mark your answer as accepted for what I probably should be doing, even if it would be a pita. :) – Nick Thompson Dec 23 '14 at 16:07
  • Thanks again for your help, I would upvote you but it seems I need 15 reputation to do so for someone answering my own question (how silly!). – Nick Thompson Dec 23 '14 at 16:09
  • I don't think the sponsors each live on a separate thread, I think the framework has a thread for monitoring stuff and checking whether the lease needs to be renewed, but I've not worked in remote scenarios for a couple of years and the internals escape me :) Glad it was useful to you – Kell Dec 23 '14 at 16:13
  • The magazine link no longer works - according to https://stackoverflow.com/a/25315226/155892 it was in the *December 2003* issue though which can be downloaded in CHM format from the same page. – Mark Sowul Sep 09 '18 at 20:27