C# 为什么在使用.NET远程处理时只能从ASP.NET web app读取属性而不能设置属性?
我在尝试设置Windows服务中托管的远程对象的属性时遇到问题。我试图更改对象的属性,但由于某种原因,它没有保存 以下是服务的相关代码:C# 为什么在使用.NET远程处理时只能从ASP.NET web app读取属性而不能设置属性?,c#,asp.net,remoting,.net-remoting,C#,Asp.net,Remoting,.net Remoting,我在尝试设置Windows服务中托管的远程对象的属性时遇到问题。我试图更改对象的属性,但由于某种原因,它没有保存 以下是服务的相关代码: private static List<Alert> _alerts = new List<Alert>(); // List of the Alerts private TcpChannel _tcpChannel; protected override void OnStart(string[] args)
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();
}
}
现在,在我的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");
}
但是,当我像下面那样更改该属性时,它不起作用
protected void AlertSaveButton_Click(object sender, EventArgs e)
{
remoteAlertList.TheList[AlertDropDownList.SelectedIndex].AlertName = AlertNameTextBox.Text;
}
有人知道为什么它不能挽救那笔财产吗
提前谢谢 我猜,由于列表
不是从MarshalByRefObject
继承的,当您调用属性remoteAlertList时,列表
会得到一个断开连接的对象。或许可以将索引器添加到对象:
public class RemoteLister : MarshalByRefObject
{
public Alert this[int index] {get {...} set {...}}
}
实际上,我主要想说的是沟渠远程处理和使用WCF/SOA。而RemoteLister
成为[可序列化]
的目的也不大。您可能还需要考虑线程安全性
澄清;
警报
实例也将是独立的,因此本地更新不会影响服务器;基本上,您有两种情况:
- 如果类型为
,则它仅存在于服务器上;所有客户端操作都远程到实际对象,但对于MarshalByRefObject
类型,仅远程MarshalByRefObjecf
- 否则,将序列化对象并重构实际对象
var tmp = obj[index]; // tmp points to the deserialized disconnected Alert
tmp.Name = "abc"; // we update the local disconnected Alert
(如果Alert
是MarshallByRefObject
,这将更新服务器,但不执行此操作)。但如果我们将价值推后:
然后我们更新了服务器
正如您所发现的,以操作为中心的设计可能要简单得多(即
setAlertName
)。但是我确实认为远程处理在这里是个坏主意。尝试了索引器,但没有成功。我尝试了下面所示的另一种方法,效果很好,但这似乎是一种解决方法,而不是正确的方法。我所做的只是在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);
}
我想这将暂时解决我的问题,但如果有人知道为什么我第一次使用时它不起作用,我宁愿使用“正确”的方法。我已经查看了您的代码,它似乎是正确的。 但可能导致错误的代码行位于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对象引用的方法。尝试作为索引器执行此操作。。。不走运。关于可序列化的建议,马克-你是对的,它没有任何用途。我是C#的新手,刚开始访问它时遇到了错误,说它需要可序列化,所以我在这里和实际的Alert类中添加了[serializable],它成功了。我想我只需要在警觉课上用它。至于线程安全,好主意。虽然它可能不会一次被多个线程访问,但这是可能的,我将对此进行研究。为什么你认为远程处理是个坏主意?这似乎是实现这一点的最简单方法。。。我简单地研究了一下WCF,它似乎有很多额外的工作和开销。windows服务和web应用在同一台服务器上,如果这有区别的话。我正在学习,我想用“最好”的方式来做这件事,所以我真的很有兴趣听听你关于如何做这件事的建议。WCF其实并不比远程处理更难设置(也没有更多的开销)。在很多方面都比较简单。如果远程处理对您有效,那么很好。事实上,不必导航防火墙使事情变得更简单。总的来说,我相信WCF有更多的灵活性,但如果你不需要它。。。(毕竟,我没有拒绝回答远程问题)。也许把它当作“也考虑WCF”,这听起来像你已经做了……我补充了一些进一步的解释,你的评论只是一个FIY…一个免费的工具来帮助你做的事情“正确”的方式是FxCop。它会分析您的代码,并推荐VisualStudio不会推荐的内容。例如,它会告诉您不要通过属性公开泛型列表。相反,使用索引器来设置项,并为get公开一个只读列表。这允许您控制添加到列表中的内容和时间。如果您公开它,任何使用您的类的东西都可以随时改变它的状态。只是一些想法。谢谢亚伦,我会查出来的!我真的很感谢董事会的帮助!
obj[index] = tmp;
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);
}
remoteAlertList = (AlertService.RemoteLister)Activator.GetObject(requiredType, "tcp://localhost:65000/AlertList.soap");