【问题标题】:Caller ID within a MarshalByReferenceObject called by remoting远程调用的 MarshalByReferenceObject 中的呼叫者 ID
【发布时间】:2015-03-05 10:24:37
【问题描述】:

我有一个MarshalByReferenceObject,它的方法通过 .net 远程调用。

public class MyServer : MarshalByReferenceObject
{
    public void DoSomething();
}

System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownServiceType(
            typeof(MyServer), "serverUrl", System.Runtime.Remoting.WellKnownObjectMode.SingleCall);

客户端像这样调用服务器:

var server = Activator.GetObject(typeof(MyServer), "serverUrl");
server.DoSomething();

现在出于调试目的,当客户端调用 DoSomething() 方法时,我想记录实际调用者是谁。

如何从我的 server.DoSomething() 函数中识别调用方法?或者从我的服务器构造函数中,它由 Activator.GetObject 调用?

理想情况下,我想要整个堆栈跟踪:哪个客户端方法调用服务器,哪个父方法调用该客户端方法,等等。但我会满足于一些类型的来电显示。我控制着客户,所以也许我可以以某种方式给他们起名字?接口规范已经非常固定,因此我希望避免为每个方法添加一个多余的 string callerId 参数。

本地堆栈跟踪当然只识别System.Runtime.Remoting 方法,而不是实际的远程调用者。


服务器端的示例堆栈跟踪:

    at MyServer.MyServer(), line 123
    at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
    at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache)
    at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache)
    at System.Activator.CreateInstance(Type type, Boolean nonPublic)
    [...] 
    at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

这显然不能帮助我从客户端识别调用方法。

【问题讨论】:

  • 如果你控制双方,为什么不将这些信息作为参数添加?
  • 我控制双方,但调用的方法签名是由接口规范预先确定的,我宁愿不改变。它有很多方法,从很多地方调用。
  • 这会排除像重载 ctor 这样的东西吗?
  • @Plutonix 不,构造函数可以重载,因为它实际上并未包含在规范中。但是Activator.GetInstance 方法不允许我将任何参数传递给构造函数。我唯一能传递的是某种“通道状态”对象,它只在内部使用。似乎无法使用自定义构造函数创建服务器对象。
  • @HugoRune - 我在远程处理方面做得不多,但我做了一些快速的研究......你能实现 IServerChannelSinkProvider 并以某种方式利用那里的信息来获得你需要的关于客户...msdn.microsoft.com/en-us/library/…

标签: c# stack-trace remoting marshalbyrefobject


【解决方案1】:

如果您可以选择稍微调整客户端和服务器的工作方式,则可以将参数传递给您的协议类 (MyServer) 构造函数。

在服务器端,您可以使用RemotingConfiguration.RegisterActivatedServiceType 注册您的协议类。

在客户端,您可以调用RemotingConfiguration.RegisterActivatedClientType 来注册您希望在服务器上创建协议类的实例。然后您可以创建一个新实例并将您喜欢的任何客户端识别参数传递给构造函数(以正常方式,不带Activator.GetObject),该对象将自动在服务器上创建并在本地代理。

协议类

using System;

public class MyServer : MarshalByRefObject
{
    Guid clientID;

    public MyServer(Guid clientID)
    {
        this.clientID = clientID;
    }

    public void DoSomething()
    {
        Console.WriteLine("Logged operation from client {0}.", this.clientID);
    }
}

服务器

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

class Server
{
    static void Main(string[] args)
    {
        ChannelServices.RegisterChannel(new TcpServerChannel(1234), false);
        RemotingConfiguration.ApplicationName = "Test";
        RemotingConfiguration.RegisterActivatedServiceType(typeof(MyServer));
        Console.WriteLine("Server listening ...");
        Console.ReadLine();
    }
}

客户

using System;
using System.Runtime.Remoting;

class Client
{
    static void Main(string[] args)
    {
        RemotingConfiguration.RegisterActivatedClientType(typeof(MyServer),
                                      "tcp://localhost:1234/Test");
        var id = Guid.NewGuid();
        Console.WriteLine("Creating object with id {0}.", id);
        var obj = new MyServer(id);
        obj.DoSomething();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-27
    相关资源
    最近更新 更多