使用 .NET 远程处理时,为什么我只能从 ASP.NET Web 应用程序读取属性而不能设置属性?

发布于 2024-08-09 12:15:21 字数 2439 浏览 4 评论 0原文

我在尝试设置 Windows 服务中托管的远程对象的属性时遇到问题。我正在尝试更改对象的属性,但由于某种原因它没有保存。

这是服务的相关代码:

    private static List<Alert> _alerts = new List<Alert>(); // List of the Alerts
    private TcpChannel _tcpChannel;

    protected override void OnStart(string[] args)
    {
        loadAlerts(); // This sets up the List (code not req'd)
        // Set up the remotelister so that other processes can access _alerts
        // Create the TcpChannel
        _tcpChannel = new TcpChannel(65000);
        ChannelServices.RegisterChannel(_tcpChannel, false);

        // Register the Proxy class for remoting.
        RemotingConfiguration.RegisterWellKnownServiceType(
          typeof(RemoteLister),
          "AlertList.soap",
          WellKnownObjectMode.Singleton);
    }

    [Serializable]
    public class RemoteLister : MarshalByRefObject
    {
        public List<Alert> TheList
        {
            get { return _alerts; }
            set { _alerts = value; }
        }

        public bool save()
        {
            EventLog.WriteEntry("AlertService", "Calling saveAlerts...");
            return saveAlerts();
        }
    }

这是 Alert 类的代码(还有很多其他内容):

    private string _alertName; // Name of alert

    public string AlertName
    {
        get { return _alertName; }
        set { _alertName = value; }
    }

现在在我的 ASP.NET Web 应用程序中,这是我初始化所有内容的方法:

AlertService.RemoteLister remoteAlertList;

    protected void Page_Load(object sender, EventArgs e)
    {
        // This is where we create a local object that accesses the remote object in the service
        Type requiredType = typeof(AlertService.RemoteLister);
        // remoteAlertList is our reference to the List<Alert> in the always running service
        remoteAlertList = (AlertService.RemoteLister)Activator.GetObject(requiredType,
                "tcp://localhost:65000/AlertList.soap");
    }

所以现在以下代码可以工作:

private void fillFields()
    {
        AlertNameTextBox.Text = remoteAlertList.TheList[AlertDropDownList.SelectedIndex].AlertName;
    }

但是当我去更改该属性,如下所示,它不起作用。

 protected void AlertSaveButton_Click(object sender, EventArgs e)
    {
        remoteAlertList.TheList[AlertDropDownList.SelectedIndex].AlertName = AlertNameTextBox.Text;
    }

有谁知道为什么它不保存该财产?

提前致谢!

I'm having an issue with attempting to set a property on a remote object hosted in a Windows Service. I'm trying to change a property of an object and it is not saving for some reason.

Here is the pertinent code of the service:

    private static List<Alert> _alerts = new List<Alert>(); // List of the Alerts
    private TcpChannel _tcpChannel;

    protected override void OnStart(string[] args)
    {
        loadAlerts(); // This sets up the List (code not req'd)
        // Set up the remotelister so that other processes can access _alerts
        // Create the TcpChannel
        _tcpChannel = new TcpChannel(65000);
        ChannelServices.RegisterChannel(_tcpChannel, false);

        // Register the Proxy class for remoting.
        RemotingConfiguration.RegisterWellKnownServiceType(
          typeof(RemoteLister),
          "AlertList.soap",
          WellKnownObjectMode.Singleton);
    }

    [Serializable]
    public class RemoteLister : MarshalByRefObject
    {
        public List<Alert> TheList
        {
            get { return _alerts; }
            set { _alerts = value; }
        }

        public bool save()
        {
            EventLog.WriteEntry("AlertService", "Calling saveAlerts...");
            return saveAlerts();
        }
    }

Here is the code for the Alert class (a lot of other stuff too):

    private string _alertName; // Name of alert

    public string AlertName
    {
        get { return _alertName; }
        set { _alertName = value; }
    }

Now in my ASP.NET web app, here's how I initialize everything:

AlertService.RemoteLister remoteAlertList;

    protected void Page_Load(object sender, EventArgs e)
    {
        // This is where we create a local object that accesses the remote object in the service
        Type requiredType = typeof(AlertService.RemoteLister);
        // remoteAlertList is our reference to the List<Alert> in the always running service
        remoteAlertList = (AlertService.RemoteLister)Activator.GetObject(requiredType,
                "tcp://localhost:65000/AlertList.soap");
    }

So now the following code works:

private void fillFields()
    {
        AlertNameTextBox.Text = remoteAlertList.TheList[AlertDropDownList.SelectedIndex].AlertName;
    }

But when I go to change that property as in the following, it doesn't work.

 protected void AlertSaveButton_Click(object sender, EventArgs e)
    {
        remoteAlertList.TheList[AlertDropDownList.SelectedIndex].AlertName = AlertNameTextBox.Text;
    }

Does anyone have an idea of why it wouldn't save that property?

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

谁人与我共长歌 2024-08-16 12:15:21

我猜想,由于 List 不是从 MarshalByRefObject 继承的,当您调用属性 remoteAlertList.TheList code> 你得到一个断开连接的对象。也许可以向对象添加一个索引器:

public class RemoteLister : MarshalByRefObject
{
    public Alert this[int index] {get {...} set {...}}
}

实际上,我主要会说放弃远程处理并使用 WCF/SOA。而且 RemoteLister 成为 [Serialized] 没有什么意义。您可能还想考虑一下线程安全。


澄清; Alert 实例是独立的,因此本地更新不会影响服务器;基本上,有两种情况:

  • 如果类型是 MarshalByRefObject,那么它只存在于服务器中;所有客户端操作都远程到实际对象 - 但对于MarshalByRefObjecf类型,
  • 否则,该对象将被序列化并且实际 em> 对象被重建。

如果您的索引器具有(例如),

obj[index].Name = "abc";

那么这是:(

var tmp = obj[index]; // tmp points to the deserialized disconnected Alert
tmp.Name = "abc"; // we update the local disconnected Alert

如果AlertMarshalByRefObject,这更新服务器,但是不要这样做)。但是,如果我们将值推回

obj[index] = tmp;

那么我们已经更新了服务器。

正如您所发现的,以操作为中心的设计可能要简单得多(即 setAlertName)。但我真的认为远程处理在这里是一个坏主意。

I would guess that since List<T> doesn't inherit from MarshalByRefObject, when you call the property remoteAlertList.TheList you get a disconnected object. Perhaps add an indexer to the object instead:

public class RemoteLister : MarshalByRefObject
{
    public Alert this[int index] {get {...} set {...}}
}

Actually, I would mainly say ditch remoting and use WCF/SOA. And there is little purpose in RemoteLister being [Serializable]. You might also want to put some thought into thread-safety.


To clarify; the Alert instances will also be standalone, so local updates won't affect the server; basically, you have two scenarios:

  • if the type is MarshalByRefObject, then it only lives at the server; all client operations are remoted to the actual object - but only for MarshalByRefObjecf types
  • otherwise, the object is serialized and an actual object is reconstructed.

If you an indexer with (for example)

obj[index].Name = "abc";

then this is:

var tmp = obj[index]; // tmp points to the deserialized disconnected Alert
tmp.Name = "abc"; // we update the local disconnected Alert

(if Alert was MarshalByRefObject, this would update the server, but don't do that). But if we push the value back:

obj[index] = tmp;

then we have updated the server.

As you've discovered, an operation-centric design may be far simpler (i.e. setAlertName). But I really think remoting is a bad idea here.

昨迟人 2024-08-16 12:15:21

尝试了索引器,但没有运气。我尝试了下面显示的另一种方法,它有效,但这似乎是一种解决方法,而不是正确的方法。我所做的就是在 RemoteLister 类中添加此内容:

public void setAlertName(int index, string name)
            {
                _alerts[index].AlertName = name;
            }

然后按如下方式更改保存按钮:

protected void AlertSaveButton_Click(object sender, EventArgs e)     
{     
    remoteAlertList.setAlertName(AlertDropDownList.SelectedIndex, AlertNameTextBox.Text);    
} 

我想这暂时可以解决我的问题,但如果有人知道为什么不这样做,我宁愿以“正确”的方式进行操作按照我的第一种方式工作。

Tried the indexer, no luck with that. I tried another way shown below and it worked, but it seems like a workaround and not the proper way of doing it. All I did was add this in the RemoteLister class:

public void setAlertName(int index, string name)
            {
                _alerts[index].AlertName = name;
            }

And then changed the save button as follows:

protected void AlertSaveButton_Click(object sender, EventArgs e)     
{     
    remoteAlertList.setAlertName(AlertDropDownList.SelectedIndex, AlertNameTextBox.Text);    
} 

I suppose this will get me by for now, but i'd rather do it the "right" way if anyone knows why it wasn't working the first way I did it.

掌心的温暖 2024-08-16 12:15:21

我查看了您的代码,它似乎是正确的。
但可能导致错误的代码行位于remoteAlertList初始化中:

    remoteAlertList = (AlertService.RemoteLister)Activator.GetObject(requiredType, "tcp://localhost:65000/AlertList.soap");

您已使用初始.net转换方法“(newType)obj”和Activator.GetObject(..)初始化了remoteAlertList类,其中之一没有返回原始 obj 的引用[我认为是 Activator.GetObject(..)]。它返回“AlertService.RemoteLister”类的精确副本,因此当您调用“TheList”时,您调用了它的精确副本,当您调用 Save() 时,它保存在复制的对象中而不是真实的对象中。

在这里我看不到您的完整代码,但从我所看到的我可以告诉您解决方案是找到一种方法来从主机访问 AlertService.RemoteLister 对象的引用。

I have take a look at your code and it seems to be correct.
but the line of code which may caused the error is here in remoteAlertList initializing:

    remoteAlertList = (AlertService.RemoteLister)Activator.GetObject(requiredType, "tcp://localhost:65000/AlertList.soap");

You have initialized a remoteAlertList class with a initial .net convertion method "(newType)obj" and Activator.GetObject(..) which one of them does't return the reference of original obj [I think it's the Activator.GetObject(..)]. It returns an exact copy of "AlertService.RemoteLister" class so when you call "TheList" you called an exact copy of it and when you call Save() it saves in the copied object not in the real object.

Here I can't see your full code but from what I see I can tell you the solution is finding a way to for accessing the referece of AlertService.RemoteLister object from the host.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文