Почему я могу только читать свойства и не устанавливать свойства из веб-приложения ASP.NET при использовании удаленного взаимодействия .NET? - PullRequest
2 голосов
/ 02 ноября 2009

У меня проблема с попыткой установить свойство для удаленного объекта, размещенного в службе 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;
    }

Кто-нибудь имеет представление о том, почему бы не сохранить это свойство?

Заранее спасибо!

Ответы [ 3 ]

2 голосов
/ 02 ноября 2009

Я бы предположил , что, поскольку 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). Но я действительно думаю, что удаленное взаимодействие здесь плохая идея.

0 голосов
/ 13 февраля 2012

Я взглянул на ваш код, и он кажется правильным. но строка кода, которая могла вызвать ошибку, находится здесь в инициализации 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 с хоста.

0 голосов
/ 02 ноября 2009

Попробовал индексатор, не повезло с этим. Я попробовал другой способ, показанный ниже, и это сработало, но кажется, что это обходной путь, а не правильный способ сделать это. Все, что я сделал, это добавил это в класс 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);    
} 

Полагаю, это пока что поможет мне, но я бы предпочел сделать это "правильно", если кто-нибудь знает, почему это не сработало, когда я это сделал в первый раз.

...