У меня возникла проблема с попыткой установить свойство на удаленном объекте, размещенном в службе 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;
}
У кого-нибудь есть идея, почему он не сохранит это свойство?
Спасибо заранее!
Я бы предположил, что, поскольку 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
). Но я на самом деле думаю, что удаленная работа - плохая идея здесь.
Я взглянул на ваш код, и это кажется правильным. но строка кода, которая может вызвать ошибку, находится здесь в инициализации 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 с хоста.
Пробовал индексатор, не повезло с этим. Я попробовал другой способ, показанный ниже, и это сработало, но это похоже на обходной путь, а не на правильный способ сделать это. Все, что я сделал, это добавить в класс 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);
}
Я предполагаю, что это заберет меня пока, но я предпочел бы это "правильно", если кто-нибудь знает, почему он не работал первым, как я это сделал.