[C#] Events over Remoting

Pagina: 1
Acties:

  • Flard
  • Registratie: Februari 2001
  • Laatst online: 21-04 20:50
Ik heb een eigen class genaamd CateringQueue, die er als volgt uitziet:

Het gaat hier trouwens op DotNet Framework 2.0, maar volgens mij is dat irrelevant voor mijn probleem.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public delegate void QueueEventHandler(QueueItem queueItem);

[Serializable()]
class CateringQueue : MarshalByRefObject, ICateringQueue
{
    public event QueueEventHandler OnNewQueueItem;

    Dictionary<int, QueueItem> list = new Dictionary<int, QueueItem>();

    public void Add(QueueItem item)
    {
        list.Add(item.Id, item);

        if (OnNewQueueItem != null)
            OnNewQueueItem(item);
    }

    ...
}


Zoals je ziet implementeerd deze class ook ICateringQueue, die ook OnNewQueueItem en Add bevat.

QueueItem is trouwens een simpele struct.

Nu heb ik ergens anders een class CateringQueueControl die zowel als client als server gestart kan worden.
Wat relevante code:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public partial class CateringQueueControl : UserControl
{
    private IChannel serverChannel;
    private IChannel clientChannel;

    ICateringQueue queue = new CateringQueue();
    
    //...

    public void AddItem(int productid, string username)
    {
        QueueItem item = new QueueItem(lastId, productid, username);
        AddItem(item);
    }


    #region Remoting
    public void StartServer()
    {

        // HTTP-Server Channel
        BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
        serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

        serverChannel = new HttpServerChannel("LavaAdminCateringQueue", remotingPort, serverProv);
        ChannelServices.RegisterChannel(serverChannel);

        // HTTP-Client Channel

        BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();

        clientChannel = new HttpClientChannel("LavaAdminCateringQueueServer", clientProv);
        ChannelServices.RegisterChannel(clientChannel);

        // Service maken
        RemotingConfiguration.RegisterWellKnownServiceType(typeof(CateringQueue), "LavaAdminCateringQueue.rem", WellKnownObjectMode.Singleton);

        // Service ophalen
        string objectUrl = String.Format("http://{0}:{1}/{2}", "localhost", remotingPort, "LavaAdminCateringQueue.rem");
        queue = (CateringQueue)Activator.GetObject(typeof(CateringQueue), objectUrl);

        // Events afvangen
        queue.OnNewQueueItem += new QueueEventHandler(queue_OnNewQueueItem);
        queue.OnItemSetBusy += new QueueEventHandler(queue_OnItemSetBusy);
        queue.OnItemSetDone += new QueueEventHandler(queue_OnItemSetDone);

        Console.WriteLine("CateringQueue Server Started");
    }

    public void StartClient()
    {
        BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
        BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
        serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

        IDictionary props = new Hashtable();

        clientChannel = new HttpChannel(props, clientProv, serverProv);
        ChannelServices.RegisterChannel(clientChannel);

        string objectUrl = String.Format("http://{0}:{1}/{2}", remotingIp, remotingPort, "LavaAdminCateringQueue.rem");
        queue = (CateringQueue)Activator.GetObject(typeof(CateringQueue), objectUrl);

        // Events afvangen
        queue.OnNewQueueItem += new QueueEventHandler(queue_OnNewQueueItem);

        Console.WriteLine("CateringQueue Client Started");
    }

    void queue_OnNewQueueItem(QueueItem queueItem)
    {
        Console.WriteLine("OnNewQueueItem({0}) <{1}>", queueItem.Id, this.InvokeRequired.ToString());
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new QueueEventHandler(queue_OnNewQueueItem), queueItem);
        }
        else
        {
            // Toevoegen en weergeven
        }
    }
}


Ik heb twee programma's, een serverprogramma wat deze control in de GUI heeft zitten, en StartServer() aanroept en een clientprogramma (domme terminal) dat StartClient() aanroept.

De bedoeling is dat als de server AddItem(..) aanroept er een event wordt geraised, die op zowel de server als client getoond wordt.
Máár, dit event wordt op het moment alleen maar bij de server aangeroepen, en zodra hij de event naar de client wil sturen krijg ik de volgende foutmelding:

code:
1
2
3
4
5
6
System.Runtime.Remoting.RemotingException: This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server.
   at System.Runtime.Remoting.Proxies.RemotingProxy.InternalInvoke(IMethodCallMessage reqMcmMsg, Boolean useDispatchMessage, Int32 callType)
   at System.Runtime.Remoting.Proxies.RemotingProxy.Invoke(IMessage reqMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at LavaAdmin.Catering.QueueEventHandler.BeginInvoke(QueueItem queueItem, AsyncCallback callback, Object object)
   at LavaAdmin.Catering.CateringQueue.Add(QueueItem item) in d:\my documents\visual studio 2005\Projects\CateringQueue\CateringQueue.cs:line 46


Er wordt dus gezegd dat er geen channel sink is, maar volgens mij heb ik die op zowel de server als de client gemaakt.

In eerste instantie heb ik de client iets specifieker gemaakt met behulp van:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void StartClient2()
{
    // HTTP Server Channel
    BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
    serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

    serverChannel = new HttpServerChannel(new System.Collections.Hashtable(), serverProv);
    ChannelServices.RegisterChannel(serverChannel);

    // HTTP Client Channel
    BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();

    clientChannel = new HttpClientChannel("LavaAdminCateringQueueClient", clientProv);
    ChannelServices.RegisterChannel(clientChannel);

    string objectUrl = String.Format("http://{0}:{1}/{2}", remotingIp, remotingPort, "LavaAdminCateringQueue.rem");
    queue = (CateringQueue)Activator.GetObject(typeof(CateringQueue), objectUrl);

    // Events afvangen
    queue.OnNewQueueItem += new QueueEventHandler(queue_OnNewQueueItem);

    Console.WriteLine("CateringQueue Client Started");
}


Het enige relevante topic wat ik hier kon vinden was [rml][ .NET] Remoting mbv interfaces[/rml], en ik heb het ook geprobeerd om het op de manier die daar uiteindelijk wordt gegeven, maar ook dat levert dezelfde foutmelding op.

Op google heb ik ook al veel gezocht (met combinaties van de keywords 'C#' 'RemotingException' 'suitable' 'sink' 'events' 'delegate' in alle mogelijke combinaties), en dat levert ook veel resultaten op. Alleen in alle bruikbare resultaten die ik tegenkom zie ik dezelfde code die ik gebruik.

Is er iemand die me kan vertellen wat ik fout doe of mij misschien kan ergens nog wat tips kan geven? Ik heb hier inmiddels al een uur of 20 in gestoken (vrijetijdsproject), maar nog steeds zonder resultaat.

  • whoami
  • Registratie: December 2000
  • Laatst online: 14:33
Waarom maak je 2 channels in startserver ?
Wat je nodig hebt op je server is 1 channel, die 2 providers heeft: een serverprovider en een clientprovider.

Op je client heb je ook 1 channel nodig, met 2 providers: clientprovider en serverprovider.

Ik heb wel enkel ervaring met remoting in .NET 1.0 en .NET 1.1. In 2.0 heb ik nog niets gedaan, maar, ik geloof dat dit ongeveer hetzelfde moet werken.

Misschien helpt dit je verder:
[rml][ .NET] Remoting en events[/rml]

https://fgheysels.github.io/


  • Flard
  • Registratie: Februari 2001
  • Laatst online: 21-04 20:50
Hmm... ik heb nu eerste geprobeerd mijn StartServer te herschrijven:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
        public void StartServer()
        {
            queueMode = QueueMode.Server;

            
            BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider();
            BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();

            serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
            
            IDictionary props = new Hashtable();
            props.Add("port", remotingPort);

            serverChannel = new HttpChannel(props, clientProv, serverProv);
            ChannelServices.RegisterChannel(serverChannel);

            // Service maken
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(CateringQueue), "LavaAdminCateringQueue.rem", WellKnownObjectMode.Singleton);

            // Service ophalen
            string objectUrl = String.Format("http://{0}:{1}/{2}", "localhost", remotingPort, "LavaAdminCateringQueue.rem");
            queue = (CateringQueue)Activator.GetObject(typeof(CateringQueue), objectUrl);

            // Events afvangen
            queue.OnNewQueueItem += new QueueEventHandler(queue_OnNewQueueItem);
            queue.OnItemSetBusy += new QueueEventHandler(queue_OnItemSetBusy);
            queue.OnItemSetDone += new QueueEventHandler(queue_OnItemSetDone);

            Console.WriteLine("CateringQueue Server Started");
        }


Toen heb ik het topic dat je hierboven aandroeg eens doorgelezen, nog wel wat interessante gezien, en ik heb o.a. de volgende dingen geprobeerd:

Van het TcpChannel een HttpChannel maken, in dat geval krijg ik meteen WebException.... :?
Van de BinarySinkProviders een SoapSinkProvider gemaakt: gaat ook fout.


Verder heb jij het in dat topic over een apart object
C#:
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);        
        
}


Mij lijkt eigenlijk niet dat het van toepassing is op mijn probleem en ik begrijp ook niet echt wat je hier nu doet. Maar als het wel van toepassing is, dan zou ik dus mijn CateringQueue (het remote object) hiervan moeten laten inheriten? (uiteraard rename ik hem wel...)
Zou het zin hebben om dat te implementeren?

  • whoami
  • Registratie: December 2000
  • Laatst online: 14:33
Als je met events werkt, zal je zo'n object nodig hebben, aangezien je zowel op je server als op je client weet moet hebben van die delegate.

Op je server heb je dan uitsluitend die abstracte class nodig, op je client maak je een concrete class die van deze class inherit en doet wat er moet gebeuren.

https://fgheysels.github.io/