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

2

У меня возникла проблема с попыткой установить свойство на удаленном объекте, размещенном в службе 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
    Я добавил некоторые дополнительные пояснения к вашим комментариям
Теги:
remoting
.net-remoting

3 ответа

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

  • 0
    Пробовал делать это как индексатор ... не повезло. Что касается сериализуемого предложения, Марк - Вы правы, оно не служит какой-либо цели. Я очень новичок в C # и у меня возникли ошибки при доступе к нему, который сказал, что он должен быть сериализуемым, поэтому я просто добавил [Serializable] здесь и к реальному классу Alert, и это сработало. Я думаю, что мне нужно было только в классе Alert. А что касается безопасности потоков, хорошая идея. Хотя, скорее всего, к нему не будет одновременно обращаться более чем к одному потоку, это возможно, и я рассмотрю это.
  • 0
    Почему вы думаете, что удаленное взаимодействие это плохая идея? Кажется, это самый простой способ реализовать это ... Я кратко рассмотрел WCF, и это просто кажется дополнительной работой и накладными расходами. Служба Windows и веб-приложение находятся на одном сервере, если это имеет значение. Я учусь, и я хотел бы сделать это «лучшим» способом, поэтому мне было бы очень интересно услышать ваше предложение о том, как сделать это вместо этого.
Показать ещё 1 комментарий
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 с хоста.

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);    
} 

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

  • 0
    Просто FYI ... Одним из бесплатных инструментов, который поможет вам делать правильные вещи, является FxCop. Он анализирует ваш код и будет рекомендовать то, что Visual Studio не будет. Например, он сказал бы вам не выставлять свой общий список через свойство. Вместо этого используйте индексатор для установки элементов и выставьте список только для чтения для получения. Это позволяет вам контролировать, что и когда будет добавлено в список. Если вы выставите это, все, что потребляет ваш класс, может изменить его состояние в любое время. Просто некоторые мысли.
  • 0
    Спасибо Аарон, я проверю это! Я действительно ценю помощь от этой доски!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню