all groups > dotnet remoting > april 2008 >
You're in the

dotnet remoting

group:

MarshalByRef class and non-serializable members


MarshalByRef class and non-serializable members alex
4/2/2008 7:24:37 AM
dotnet remoting:
Hello
I need to send an object of HttpListenerContext class to another AppDomain.
HttpListenerContext class is neither inheritor of MarshalByRefObject nor
marked as Serializable (more over it is sealed). I wrote a wrapper for this
class and tried to send an object of this class which inherits MarshlByRefObject
to another AppDomain:

public class web_request_parameters : MarshalByRefObject
{
private readonly HttpListenerContext context_;

public HttpListenerContext context
{
get { return this.context_; }
}

public web_request_parameters( HttpListenerContext context )
{
this.context_ = context;
}
}

Object is successfully passed through AppDomain boundaries but when I try
to access the "context" property of this class I get an Exception "Type 'System.Net.HttpListenerContext'
in Assembly 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
is not marked as serializable."

So my question is: should all members of the class which inherits MarshalByRefObject
be either Serializable or inherit MarshalByRefObject?
May be there are some workarounds this work?

Thank you

Re: MarshalByRef class and non-serializable members Jeroen Mostert
4/2/2008 8:18:21 PM
[quoted text, click to view]

Why? That would be my first question. There's something very unintuitive
about one AppDomain creating this object and another one using it.

[quoted text, click to view]
The reason this doesn't work is simple: while web_request_parameters is a
MarshalByRefObject (and thus lives only in its originating AppDomain) the
system still has to marshal the HttpListenerContext object itself when it's
accessed, and this of course fails for the same reason that passing it
directly fails. In other words, the wrapper isn't wrapping at all.

[quoted text, click to view]

Not exactly.

A class which is serializable can control its own serialization by
implementing ISerializable, so it can decide to serialize its parts however
it chooses -- they needn't be serializable themselves. However, if it
doesn't do this and it relies on default serialization, then all fields not
marked [NonSerialized] must be serializable themselves. (All
MarshalByRefObjects are serializable; they serialize by passing proxies.)

For MarshalByRefObject, there's the exception that, obviously, a member need
not be marshallable if it's never accessed from another AppDomain.
Otherwise, it needs to be serializable just as if it had been used directly.
Method calls are remotable as long as their parameters and results are (and
the getters and setters of properties are just special methods).

[quoted text, click to view]
Well, the "workaround" (I'd call it the proper approach, rather) is to keep
the HttpListenerContext in its own AppDomain, so that only that AppDomain is
responsible for it. This is why AppDomains exist in the first place: to
provide a clean separation.

That's not to say it's hopeless. You can use an MBRO as a proxy to marshal
request and results back and forth -- that is, don't try to use an
HttpListenerContext directly in a cross-domain context, instead call methods
and pass simpler types on your proxy (which in turn delegates to the
HttpListenerContext) to achieve what you want.

Working with AppDomains can be tricky. It's a good idea to exactly define
the minimal interfaces you want to communicate with. Don't simply do
cross-AppDomain calls willy-nilly, because the overhead is considerable
(it's essentially just a local form of remoting) and as you've experienced
it's easy to run into problems with nonserializable types. You also lose the
benefits of AppDomains somewhat (clean separation and unloading
capabilities) if you start migrating a lot of data across them.

--
Re: MarshalByRef class and non-serializable members alex
4/3/2008 6:59:23 AM
Hello Jeroen,

Thank you for your reply

[quoted text, click to view]

There was an idea to create asp.net host (by calling ApplicationHost.CreateApplicationHost())
on the first user request to decrease startup time of the server. Thats why
HttpListener had to be created before creating of asp.net host AppDomain
and in another than this AppDomain. Then we use our custom worker_request
which inherits standard SimpleWorkerRequest (SimpleWorkerRequest doesn't
use HttpListenerContext so we need extend it with worker_request which uses
HttpListenerContext while) which is used to call HttpRuntime.ProcessRequest(worker_request).

[quoted text, click to view]

Thank you for clearing this moment

[quoted text, click to view]

Yes idea with proxy was considered. And yes - you absolutely right that performance
considerations are very significant with proxy approach. I will check how
intensively these methods are called when request is processed.
Another idea - is to pass only neccessary data to asp.net host AppDomain
(e.g. headers, response stream, etc.) which are serializable and can be passed
and accessed in another AppDomain - but currently there is no clear point
that this will work

AddThis Social Bookmark Button