[.NET] Remoting en events

Pagina: 1
Acties:
  • 434 views sinds 30-01-2008
  • Reageer

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
Ik heb een remoted object gemaakt, en dat object moet feedback kunnen geven over wat hij aan het doen is naar de client die dat object gestart heeft.
Ik heb dit gedaan door een event te definieren in m'n 'remote class', echter, als ik dat event wil gebruiken (als in 'een eventhandler eraan hangen'), dan krijg ik een SystemArgumentException met de volgende message:
Error binding to target method
De stacktrace zegt dit:
at System.Delegate.InternalCreate(object target, string method, bool ignoreCase)
Mijn code ziet er zo uit:

Relevante gedeeltes van de class waar m'n remote object een instance van is:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MyMigrator : MarshalByRefObject, IMigrator
{

     private RemoteBatchReportProgressEventHandler _remoteProgressReport;

     public RemoteBatchReportProgressEventHandler RemoteProgressReport
     {
         get
         {
                 return _remoteProgressReport;
         }
         set
         {
                  _remoteProgressReport = value;
         }
     }

     // .... 

}


De code van m'n client, waarin ik dus zo'n remote object gebruik ziet er als volgt uit:

code:
1
2
3
4
5
6
7
8
9
10
// IMigrationBatchConfigReader is ook een remote object; dit is eigenlijk een factory
// die een remoted IMigrator instance returned.
IMigrationBatchConfigReader reader = (IMigrationBatchConfigReader)Activator.GetObject ( .... );

// Hier returned the reader een 'IMigrator' object.
IMigrator migr = reader.CreateBatch(txtConfigFile.Text);

// Hier treedt de exceptie op; als ik een event-handler aan m'n event wil hangen, dan krijg ik 
// bovenvermelde exceptie
migr.RemoteProgressReport += new RemoteBatchReportProgressEventHandler( ... );

[/]

Iemand enig idee wat ik hier trouwens fout doe ?
Ik gebruik .NET 1.1, en ik weet dat je -als je in .NET 1.1 werkt, je rekening moet houden met bepaalde properties van je Channel ([rml][ .NET] Remoting : SecurityExceptions bij delegates[/rml]).

Mijn config-file die m'n channel etc... initializeert ziet er trouwens zo uit:

Config file van de client:
code:
1
2
3
4
5
6
7
8
9
10
11
<system.runtime.remoting>
        <application name="Client">
            <channels>
                <channel port="0" ref="http" useDefaultCredentials="true" >
                    <clientProviders>
                        <formatter ref="binary"/>
                    </clientProviders>
                </channel>              
            </channels>
        </application>
</system.runtime.remoting>


Config file op de server:
code:
1
2
3
4
5
6
7
8
9
10
11
12
<system.runtime.remoting>
        <customErrors mode="on"/>
        <application>
            <channels>
                <channel ref="http" useDefaultCredentials="true">
                    <serverProviders>
                        <formatter ref="binary"  typeFilterLevel="Full" />
                    </serverProviders>
                </channel>
            </channels>
        <service>
....


Wellicht dat ik in de config-file van de client ook wel een 'serverProvider' (zie bovenvermelde link naar een vorig topic van mij, daar creeër ik het channel via code, en specifieer ik ook op de client een serverprovider) moet specifieren, maar als ik dat doe, dan krijg ik een andere exceptie.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
Ok.

Ik ben ondertussen iets verder geraakt.
Ipv m'n event-handler zo aan m'n remote-object te koppelen, heb ik het nu als volgt gedaan:

Op m'n server heb ik een extra class gemaakt die er als volgt uit ziet:
code:
1
2
3
4
5
6
7
8
9
10
11
public abstract class RemoteBatchDelegateObject : MarshalByRefObject
{
        
    public  void    ReportBatchProgressCallback (object sender, RemoteBatchReportProgressEventArgs e)
    {
        InternalReportBatchProgressCallback (sender, e);
    }
        
    protected abstract void InternalReportBatchProgressCallback (object sender, RemoteBatchReportProgressEventArgs e);      
        
}


Aan de client kant inherit ik dan van die class een specifieke - class, en die ga ik dan gaan 'binden' aan m'n event-handler.

Bv:
code:
1
2
3
4
// ListViewRemoteReporter inherits van RemoteBatchDelegateObject
ListViewRemoteReporter r = new ListViewRemoteReporter(lvProgress);

migr.RemoteProgressReport += new RemoteBatchReportProgressEventHandler( r.ReportBatchProgressCallback );

Door deze 'omweg' te maken, krijg ik de eerder vermelde fout niet meer.

Echter, nu krijg ik een SecurityException:
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in Unknown Module.

Additional information: Because of security restrictions, the type System.Runtime.Remoting.ObjRef cannot be accessed.
Dit komt voort uit het feit dat ik geen 'serverProvider' heb gedefinieert in voor m'n Channel waarvoor de TypeFilterLevel op Full staat. (Zie m'n topicstart).
Als ik echter in m'n config - file zo'n serverprovider ga gaan definieren, dan krijg ik weer een andere exception:
An unhandled exception of type 'System.Runtime.Remoting.RemotingException' occurred in Unknown Module.

Additional information: System.ArgumentNullException: No message was deserialized prior to calling the DispatchChannelSink.
Parameter name: requestMsg
at System.Runtime.Remoting.Channels.DispatchChannelSink.
:/

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
:o
fix0rd

Ik heb het dus moeten oplossen door zo'n 'tussen-delegate' object te creeëren, maar dan kreeg ik, zoals je kunt zien die RemotingException (no message was deserialized .... ).

Nu heb ik dat kunnen oplossen door gewoon in m'n config file geen binary formatter maar een soap-formatter te specifieren. IMO is dat dus een bug in het .NET framework. (Aan mijn code heb ik verder niets meer veranderd).

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • P_de_B
  • Registratie: Juli 2003
  • Niet online
offtopic:
Je praat wel vaker in jezelf of niet :+

edit
Nou mooi dat GoT een oplossing voor je probleem heeft kunnen vinden

[ Voor 81% gewijzigd door P_de_B op 11-02-2005 11:54 ]

Oops! Google Chrome could not find www.rijks%20museum.nl


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
P_de_B schreef op vrijdag 11 februari 2005 @ 11:53:
offtopic:
Je praat wel vaker in jezelf of niet :+
Dan post je eens de oplossing, is het weer niet goed. :/

:+

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
Kan aan mij liggen, maar is dit niet mega inefficient?

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
EfBe schreef op vrijdag 11 februari 2005 @ 12:16:
Kan aan mij liggen, maar is dit niet mega inefficient?
Als je een manier weet die efficienter is, en die werkt, feel free to post. ;)

Waar kan het volgens jou beter ?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
Hmmm, toch niet zo leuk...
Mijn batch stopt plots na een aantal minuten, zonder dat er een reden wordt opgegeven.

Het remoted object is een 'SingleCall' object. Ik dacht dat een singlecall pas beëindigd werd, als de volledige method beëindigd werd ?
Het is nu wel zo dat m'n batch eigenlijk nog op een andere trhead draait.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op vrijdag 11 februari 2005 @ 12:18:
[...]


Als je een manier weet die efficienter is, en die werkt, feel free to post. ;)
Waar kan het volgens jou beter ?
Nou je krijgt op deze manier een 'chatty' applicatie: het lijkt 1 applicatie maar het genereert veel verkeer (denk ik) ,door dat je een marshallbyref gebruikt. Ik weet niet hoevaak het event afgaat, maar m.i. is het gebruik van een remote service er een die zoveel mogelijk stateless gehouden moet worden, dus je roept de service aan om iets te doen en als dat results oplevert dan krijg je ze terug middels de call. In jouw geval blijft alles connected en bij veel clients heb je dus veel connecties met de server die bij elke property access een call naar de server plegen.

[ Voor 5% gewijzigd door EfBe op 11-02-2005 13:14 ]

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
Het event wordt niet zo heel veel getriggerd.
Het remoted object is een soort 'batch' die een aantal stappen uitvoert. Voordat er aan een stap begonnen wordt, wordt het event getriggered zodanig dat je kan weten welke stap er zal uitgevoerd worden.

Het is ook niet iets dat door veel mensen (tegelijk) zal gebruikt worden.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
Wat ik trouwens vreemd vind is, dat m'n remote-object blijkbaar niet lang blijft leven.

Of ik het nu als singlecall of singleton definieer, op een gegeven tijdstip lijkt het wel of IIS (m'n remote object wordt in IIS gehost) het object gewoon weggooid. Er gebeurt niets meer, aspnet_wp doet niets meer, ..... vreemd.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
Ik kick deze nog even;

Mijn remote object (de factory) is een single-call object, wat dus wil zeggen dat het object blijft 'leven' tot dat de method die het object geactiveerd heeft, beëindigd is.
In mijn geval creeërt mijn singlecall IMigrationBatchConfigReader class dus een object die een IMigrator interface implementeert.

Aangezien dat object gecreeërd wordt door een 'remoted object' (IMigrationBatchConfigReader), is het IMigratorBatch object automatisch ook 'remoted'.

Nu vraag ik mij af: van welk type is dat IMigratorBatch object dan ? Volgens mij is het geen singlecall object, want, ik roep bv 2 methods op van dat object, en ik merk dat de state van het object tussen die method-calls behouden blijft. Daarom is het volgens mij dus geen singlecall object.

Wat ik ook gemerkt heb is, dat mijn IMigratorBatch object aan het werken is op de server, maar na een tijd (zeg een aantal minuten), is het plots verdwenen. Er is dan ook geen cpu activeit meer. Blijkbaar is het dan op dat moment 'gedestroyed'.
Dit vind ik vreemd, aangezien ik ook de 'InitializeLifeTimeService' method in m'n IMigratorBatch implementatie overriden heb, en deze null laat returnen.
(Als mijn IMigratorBatch object zijn taken aan het uitvoeren is, doet deze dat op een andere thread).
Heeft iemand hier een idee over hoe dat zou kunnen komen ?

[ Voor 4% gewijzigd door whoami op 11-02-2005 20:15 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
whoami schreef op vrijdag 11 februari 2005 @ 11:52:
:o
fix0rd

Ik heb het dus moeten oplossen door zo'n 'tussen-delegate' object te creeëren, maar dan kreeg ik, zoals je kunt zien die RemotingException (no message was deserialized .... ).

Nu heb ik dat kunnen oplossen door gewoon in m'n config file geen binary formatter maar een soap-formatter te specifieren. IMO is dat dus een bug in het .NET framework. (Aan mijn code heb ik verder niets meer veranderd).
Subtiel schopje.
Ik zit hier nl. nogal mee in m'n maag.... Ik wil een BinaryFormatter gebruiken, maar dan werkt m'n delegate op m'n remote object niet meer. Als ik die een SoapFormatter gebruik (gewoon een configuratie-kwestie), dan werkt alles naar behoren.
Iemand die hier een work-around oid voor heeft ?

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
Dit is dus de exceptie die ik krijg:
Additional information: System.ArgumentNullException: No message was deserialized prior to calling the DispatchChannelSink.
Parameter name: requestMsg
at System.Runtime.Remoting.Channels.DispatchChannelSink.
En, het enige dat ik veranderd heb, is dit (in m'n config file)
van
code:
1
2
3
4
5
6
7
8
9
10
<channels>
     <channel port="0" ref="http" useDefaultCredentials="true" >
        <clientProviders>
            <formatter ref="soap"/>
        </clientProviders>
        <serverProviders>
            <formatter ref="soap" typeFilterLevel="Full"/>
           </serverProviders>                   
    </channel>              
</channels>

(zo werkt het dus)

naar
code:
1
2
3
4
5
6
7
8
9
10
<channels>
     <channel port="0" ref="http" useDefaultCredentials="true" >
        <clientProviders>
            <formatter ref="binary"/>
        </clientProviders>
        <serverProviders>           
            <formatter ref="binary" typeFilterLevel="Full"/>
           </serverProviders>                   
    </channel>              
</channels>

En zo niet.
Het leuke is nu dat ik die BinarryFormatter wil / moet gebruiken in de meeste gevallen...
Ik zou nu wel in bepaalde gevallen een SoapFormatter kunnen gebruiken, maar ik weet niet hoe ik kan aangeven wanneer ik welke forrmatter wil gebruiken...

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
Het ziet er naar uit dat ik een oplossing heb:

De config file op m'n server ziet er als volgt uit: (enkel relevant gedeelte)
code:
1
2
3
4
5
6
7
8
9
10
<application>
    <channels>
        <channel ref="http" useDefaultCredentials="true">
        <serverProviders>
            <formatter ref="binary" typeFilterLevel="Full"/>
        </serverProviders>
    </channel>
</channels>
<service>
...


Zoals ik het hier nu gezet heb, maakt ie gebruik van een binary formatter. In combinatie met een client - config file die gebruik maakt van een binary formatter, werkt dit niet.

Als ik in de server-config file echter die formatter verander van binary naar soap, en op de client hetzelfde doe, dan werkt het wel.

Wat heb ik nu gedaan:
Ik heb in m'n client config file de formatter op binary gezet
Ik heb in m'n web.config file de formatter op binary gezet EN ik heb in m'n web.config file ook aangegeven welke client formatter er moet gebruikt worden:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
<application>
    <channels>
        <channel ref="http" useDefaultCredentials="true">
            <serverProviders>
                <formatter ref="binary" typeFilterLevel="Full"/>
            </serverProviders>
        <clientProviders>
              <formatter ref="binary"/>
        </clientProviders>
    </channel>
</channels>
<service>
....


En, hurray, het werkt wel.

_o_ whoami _o_

:+

[sub]* whoami denkt dat hij nu maar eens naar huis gaat...[/ME]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
Nu alleen nog zien na te gaan waarom dit nodig is...

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
De oorzaak (althans, dat denk ik...., feel free to correct):
Een HttpChannel gebruikt als 'default' een SoapFormatter, een TcpChannel gebruikt als default een BinaryFormatter.
Nu, ik heb wel aangegeven welke formatter er op de client moet gebruikt worden en op de server had ik enkel de 'server-side' formatter aangegeven. Aangezien de keuze van de formatter toch op de client moet bepaald worden dacht ik dat dit voldoende was.
Echter, met die delegates moet de server iets terugsturen, en dat moet dus over hetzelfde channel gaan, en met dezelfde formatter.
Aangezien de server niet weet welke formatter mijn client gebruikt, en dat ook nergens gespecifieerd was, zal hij dus automatisch z'n default formatter gemaakt hebben, en het 'bericht' met de SoapFormatter geserialized hebben.
M'n client verwacht echter dat hij dat bericht via de BinaryFormatter kan deserializen, en daar loopt het dus fout.

/gis & speculatie-modus, maar ik denk dat ik er niet te ver van zit.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:05
EfBe schreef op vrijdag 11 februari 2005 @ 13:14:
[...]

Nou je krijgt op deze manier een 'chatty' applicatie: het lijkt 1 applicatie maar het genereert veel verkeer (denk ik) ,door dat je een marshallbyref gebruikt. Ik weet niet hoevaak het event afgaat, maar m.i. is het gebruik van een remote service er een die zoveel mogelijk stateless gehouden moet worden, dus je roept de service aan om iets te doen en als dat results oplevert dan krijg je ze terug middels de call. In jouw geval blijft alles connected en bij veel clients heb je dus veel connecties met de server die bij elke property access een call naar de server plegen.
Om hier even op terug te komen; zo 'chatty' is ze niet.
Ik heb gewoon een aantal 'listeners' gehangen aan m'n remoted object, en iedere keer als m'n remote object een taak gedaan heeft, dan triggert hij die listener.
Die listener is dus een 'event', dat event wordt getriggered, en er wordt een item getoond in m'n listview die aangeeft wat m'n objectje aan het doen is.
Aangezien dit hooguit zo'n 10x gebeurt tijdens de 'looptijd' van m'n process, valt dit nogal goed mee vind ik. (Zeker als je weet dat dit process behoorlijk lang kan duren... 2 gb aan informatie importeren met allerhande validaties duurt wel een tijdje).

https://fgheysels.github.io/

Pagina: 1