我在尝试在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网络应用程序中,这是我如何初始化所有内容:
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;
}
有没有人知道为什么不能保存这个属性?
提前致谢!
答案 0 :(得分:2)
我会猜测,因为List<T>
不会从MarshalByRefObject
继承,所以当你调用属性remoteAlertList.TheList
时,你会得到一个断开连接的对象。也许可以在对象中添加索引器:
public class RemoteLister : MarshalByRefObject
{
public Alert this[int index] {get {...} set {...}}
}
实际上,我会主要说沟通远程并使用WCF / SOA。在RemoteLister
[Serializable]
Alert
中没有什么用处。您可能还想考虑线程安全性。
澄清; MarshalByRefObject
个实例也是独立的,因此本地更新不会影响服务器;基本上,你有两种情况:
MarshalByRefObjecf
,那么它只存在于服务器上;所有客户端操作都远程到实际对象 - 但仅用于obj[index].Name = "abc";
类型如果你是一个索引器(例如)
var tmp = obj[index]; // tmp points to the deserialized disconnected Alert
tmp.Name = "abc"; // we update the local disconnected Alert
然后是:
Alert
(如果MarshalByRefObject
为obj[index] = tmp;
,此将更新服务器,但不执行此操作。但是,如果我们将值推回:
setAlertName
然后我们已经更新了服务器。
正如您所发现的,以操作为中心的设计可能要简单得多(即{{1}})。但我真的认为远程处理在这里是一个坏主意。
答案 1 :(得分:0)
尝试了索引器,没有运气。我尝试了下面显示的另一种方式并且它有效,但它似乎是一种解决方法而不是正确的方法。我所做的就是在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);
}
我想这会让我暂时离开,但如果有人知道为什么它不按照我做的第一种方式工作,我宁愿以“正确”的方式去做。
答案 2 :(得分:0)
我看了你的代码,似乎是正确的。 但是可能导致错误的代码行在remoteAlertList初始化中:
remoteAlertList = (AlertService.RemoteLister)Activator.GetObject(requiredType, "tcp://localhost:65000/AlertList.soap");
你初始化了一个remoteAlertList类,它带有一个初始.net转换方法“(newType)obj”和Activator.GetObject(..),其中一个没有返回原始obj的引用[我认为它是Activator。 GetObject的(..)]。它返回“AlertService.RemoteLister”类的精确副本,因此当您调用“TheList”时,您调用了它的精确副本,当您调用Save()时,它会保存在复制的对象中而不是真实对象中。
在这里,我看不到您的完整代码,但从我看到的情况我可以告诉您解决方案是找到一种方法来访问来自主机的AlertService.RemoteLister对象的参考。