Laden...

Remoting: manche Objekte lassen sich nicht übertragen

Erstellt von naumann vor 17 Jahren Letzter Beitrag vor 17 Jahren 14.008 Views
N
naumann Themenstarter:in
61 Beiträge seit 2005
vor 17 Jahren
Remoting: manche Objekte lassen sich nicht übertragen

Hallo,

ich habe ein Problem mit dem Remoting. Manche Objekte lassen sich einfach nicht übertragen. Folgende Exception kommt wenn ich versuche eine Variable vom Typ Bitmap als Parameter zu übertragen.

Eine nicht behandelte Ausnahme des Typs 'System.Runtime.Serialization.SerializationException' ist in mscorlib.dll aufgetreten.

Zusätzliche Informationen: Auf den Typ 'System.Runtime.Remoting.ObjRef' kann aufgrund von Sicherheitseinschränkungen nicht zugegriffen werden.

Das kuriose ist, wenn ich den Typ des Parameters als String angebe funktioniert es.
Laut MSDN sollte es funktionieren, da Bitmap serialisierbar ist.

Hier der Code des Projekts (ist zwar VB, aber ich denke es ist erkennar😉) :

Server


Private Sub btnConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnect.Click
Dim _channel As New TcpChannel(Int32.Parse(txtPort.Text)) 'channel instanzieren
ChannelServices.RegisterChannel(_channel) 'channel registrieren

RemotingConfiguration.RegisterWellKnownServiceType(GetType(ServerFunctions), _
"test.rem", _
WellKnownObjectMode.SingleCall)
End Sub

Client


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim _channel As New TcpChannel(0)
ChannelServices.RegisterChannel(_channel)

RemotingConfiguration.RegisterWellKnownClientType(GetType(MainFunctions.ITest), _
"tcp://" & txtServer.Text & ":" & txtPort.Text & "/test.rem";)

Dim test As MainFunctions.ITest

test = Activator.GetObject(GetType(MainFunctions.ITest), _
"tcp://" & txtServer.Text & ":" & txtPort.Text & "/test.rem";)

Dim get_local_scrn As New ClassScreenshot.CaptureScreen
test.send_screenshot(get_local_scrn.GetDesktopImage) ' <-- ! FEHLER !

End Sub

Interface


Public Interface ITest
Sub send_screenshot(ByVal bm As Drawing.Bitmap)
End Interface

In dem Serverprojekt liegt auch noch eine Programlogik-Klasse, welche jedoch leer ist.

Der fehler tritt auf, wenn ich auf der Clientseite versuche die Methode send_screenshot aufzurufen.

Woran könnte das liegen? Wie schon oben gesagt, funktioniert es, wenn ich anstatt Bitmap String als Parametertyp nehme.

Ich hoffe mir kann einer bei dem Problem helfen.

N
naumann Themenstarter:in
61 Beiträge seit 2005
vor 17 Jahren

Mmmhh.. Ich hab mal das Internet ein bisschen tiefer durchforstet. Normaler weise tritt dieser Fehler auf, wenn ich die Klasse die ich per Remoting übertragen will nicht serialisiert habe. Sie ist es aber.

Ich hab von tutorials.de noch das Chat-Beispiel kompiliert. Auch dort schmeißt er den gleichen Fehler. Ich denke mal, dass in dem Code auch ein Fehler steckt. Kann es aber auch einfach sein, dass ich für Remoting noch irgend eine Einstellung setzen muss?

D
8 Beiträge seit 2006
vor 17 Jahren
Ich auch...

Das gleiche Problem habe ich auch... bin schon den ganzen Nachmittag auf der Suche nach einer Lösung. Mein zu übergebendes Objekt ist als [Serializable] gekennzeichnet bzw. von MarshalByRefObject abgeleitet.

Fehlermeldungen
"by value": Auf den Typ Name.meines.Typs kann aufgrund von Sicherheitseinschränkungen nicht zugegriffen werden.
"by reference": Auf den Typ System.Runtime.Remoting.ObjRef kann aufgrund von Sicherheitseinschränkungen nicht zugegriffen werden.

HILFE! 🙂

Grüße
Deadalus

D
8 Beiträge seit 2006
vor 17 Jahren
Lösung

Habe die Lösung!

Siehe hier.

So sieht's jetzt bei mir aus:


BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
IDictionary props = new Hashtable();
props["port"] = 1234;
this.chan = new TcpChannel(props, null, provider);

Ich musste also "nur" beim Erstellen des TCPChannels diesen Provider dort mitgeben, der die Eigenschaft TypeFilterLevel auf Full gesetzt hat.

N
naumann Themenstarter:in
61 Beiträge seit 2005
vor 17 Jahren

Vielen Dank! Der Fehler ist weg.

Leider kommt darauf hin ein neuer: 😁

Eine nicht behandelte Ausnahme des Typs 'System.Net.Sockets.SocketException' ist in mscorlib.dll aufgetreten.

Zusätzliche Informationen: Es konnte keine Verbindung hergestellt werden, da der Zielcomputer die Verbindung verweigerte

Ich weiß, dass ich noch einen Rückkanal anlegen muss. Kann mir mal einer ein Codebespiel daür senden? In fast allen Beispielen wird das in der .config Datei definiert. Ich muss es jedoch zur Laufzeit machen.

_
227 Beiträge seit 2006
vor 17 Jahren

Hallo, ich möchte keinen Extre Thread eröffnen und denke hier passt es am besten zum Topic.

Und zwar, ich haben Objekte in denen die Daten gehalten werden also ne Klasse mit feldern und Properties. Sollte man da trotzdem Interfaces bei Remoting verwenden oder kann man da die Objekte beiseitig haben?

D
23 Beiträge seit 2006
vor 17 Jahren

Ich wollte auch eine Bitmap übertragen und hatte das gleiche Problem wie naumann.

Daher war ich froh, daß Daedalus eine Lösung gefunden hat. Dieses Problem ist bei mir jetzt weg, dafür gibt es ein neues: ich bekomme jetzt beim Übertragen eine Exception mit der Meldung:

"Der Remoteproxy hat keinen Channelempfänger, d.h. der Server besitzt keine registrierten Serverchannel oder die Anwendung hat keinen passenden Clientchannel, um mit dem Server zu kommunizieren."

Ich bin leider noch Anfänger auf dem Gebiet Remoting, daher kann es auch sein, daß ich etwas sehr Triviales vergessen habe einzustellen.

Wenn ich in meinem zu übertragenen Objekt die Bitmap auskommentiere und sonst alles so lasse, dann funktioniert die Übertragung einwandfrei. Nur mit Bitmap bekomme ich die Probleme.

Wäre schön, wenn jemand einen Rat hierzu hätte.

D
23 Beiträge seit 2006
vor 17 Jahren

Es hat warhrscheinlich etwas damit zu tun, daß ich jetzt auf Serverseite einen BinaryServerFormatterSinkProvider verwende. Ich habe gesehen, daß es ein dazu passenden BinaryClientFormatterSinkProvider gibt.

Doch wie verwende ich diesen?

Ich habe folgenden Code:

[Serializable]
    public class Screenshot
    {
        private Bitmap _screenshot;
        public Bitmap Screenshot
        {
            get { return _screenshot; }
            set { _screenshot = value; }
        }

        private int _shotType;
        public int ShotType
        {
            get { return _shotType; }
            set { _shotType = value; }
        }

    }

    [Serializable]
    public class Response
    {
        private String _result;
        public String Result
        {
            get { return _result; }
            set { _result = value; }
        }
    }

    public class cTransfer : MarshalByRefObject
    {
        public delegate Response del_SlaveCall(Screenshot screenshot);
        public event del_SlaveCall ev_SlaveCall;

        // Default public no argument constructor
        public cTransfer()
        {
        }

        public NiftyResponse CallSlave(NiftyScreenshot screenshot)
        {
            return ev_SlaveCall(screenshot);
        }

        public override Object InitializeLifetimeService()
        {
            return null;
        }
    }

Mein Client-seitiger Aufruf sieht so aus:


private void Notify(Bitmap bm, int shotType)
        {
            Remote.Screenshot screenshot = new Remote.Screenshot();
            screenshot.Screenshot = bm;
            screenshot.ShotType = shotType;          

            String url = String.Format("tcp://{0}:{1}/TestService", serverTB.Text, portTB.Text);
            try
            {
                transfer = (Remote.cTransfer)Activator.GetObject(typeof(Remote.cTransfer), url);

                // Löst den Event transfer.ev_SlaveCall im Server aus
                Remote.Response response = transfer.CallSlave(screenshot);               
            }
            catch (Exception Ex)
            {
                MessageBox.Show(this, "Fehler:\n" + Ex.Message, "Master Error");
            }
            

        }

Beim Aufruf von transfer.CallSlave(...) kommt die Exception.

An welcher Stelle müßte ich den BinaryClientFormatterSinkProvider einbauen? Oder ist es doch ein anderes Problem?

3.728 Beiträge seit 2005
vor 17 Jahren
App.Config

Am besten definierst Du das alles in der App.config von Host und Client, statt das als C# Code fest reinzuschreiben.

.Net Remoting -Fehler?

D
23 Beiträge seit 2006
vor 17 Jahren

@Rainbird

Vielen Dank für Deine Antwort. Das hört sich sehr vernünftig an. Nur wenn ich gewisse Parameter in einer config Datei speichere, wie sieht dann der übriggebliebene Code aus?

Ganz konkret: ich will letztendlich CallSlave aufrufen. Dies ist im cTransfer Objekt. Also muß ich mir zunächst das cTransferObjekt beschaffen. Ich habe das bislang so gemacht:


String url = String.Format("tcp://{0}:{1}/TestService", serverTB.Text, portTB.Text);
transfer = (Remote.cTransfer)Activator.GetObject(typeof(Remote.cTransfer), url);

Anschließend die Methode aufgerufen:


Remote.NiftyResponse response = transfer.CallSlave(screenshot);

Wie läuft das jetzt mit einem Config File?

1.378 Beiträge seit 2006
vor 17 Jahren

public static MyRemoteObject MRB=null;
RemotingConfiguration.Configure("SimpleServer.exe.config"); 
MRB=new MyRemoteObject(); 
RemotingServices.Marshal((MRB),"MyRemoteObject");

hab ich hier gefunden.

D
23 Beiträge seit 2006
vor 17 Jahren

Ich habe es jetzt mit Konfigurationsfiles versucht. Das ist super, da der Code sehr viel kürzer wird. Aber die Fehlermeldung ist nachwievor die gleiche:

Der Remoteproxy hat keinen Channelempfänger, d.h. der Server besitzt keine registrierten Serverchannel oder die Anwendung hat keinen passenden Clientchannel, um mit dem Server zu kommunizieren.

Ich kann also Standard Datentypen übertragen, aber keine Bitmap.

Im übrigen brauche ich in meinem Fall die Zeile

RemotingServices.Marshal((MRB),"MyRemoteObject");

nicht, da dies nur für Published Objects gilt, also solche, die vom Server vorab erzeugt werden.

Wer hat noch eine Idee, was ich mal versuchen könnte?

D
23 Beiträge seit 2006
vor 17 Jahren

Habe das Problem lösen können.

Man muß den Client Channel mit port="0" registrieren, um Callbacks zu erhalten. Auf diese Weise sucht das .NET Framework einen beliebigen freien Port für die Clientseite und überträgt diesen auch zum Server, damit dieser auch antworten kann.