На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
> Сериализация класса по завершению работы WCF-службы
    Сабж.
    Пробовал так:
    ExpandedWrap disabled
      public class Service : IService, IDisposable
      {
          private XmlSerializer serializer;
       
          //...
       
          public void Dispose()
          {
              Dispose(true);
              GC.SuppressFinalize(this);
          }
       
          private void Dispose(bool disposing)
          {
              if (disposing)
                  serializer.Serialize([блаблабла]);
          }
      }

    Но к тому времени, когда вызывается Dispose, XmlSerializer serializer уже "дохлый" (null). Т.е. в методе Dispose делать сериализацию поздно. А где тогда не поздно?
      GoldenJoe, не понятна суть вопроса, зачем и что ты пытаешься серилизовать
        Pit-Bul, это не имеет никакого отношения к дело, но если надо, поясню: есть класс User, описывающий пользователя сервиса. Сериализовать надо List<User> - список пользователей. Причем сделать это надо по завершению работы службы (это происходит при закрытии консольного приложения, в котором хостится сервис).

        Добавлено
        Пытаюсь выполнить сериализацию List<User> в методе Dispose, но экземпляр XmlSerializer к тому времени уже равен null (спасибо GC)
          а что мешает сделать эту самую сериализацию до вызова Dispose, то есть включить это в метод завершения работы сервиса ???
            Цитата Pit-Bul @
            метод завершения работы сервиса

            Это как? Мой сервис состоит целиком и полностью из [OperationContract]'ов. И Dispose.

            P.S. начал учить C# неделю назад.
              не уверен, не понятен контекст, но может сработать это

              ExpandedWrap disabled
                if (disposing)
                {
                  serializer = new XmlSerializer();            
                  serializer.Serialize([блаблабла]);
                }
                private XmlSerializer serializer; - этот использую еще и для ДЕсериализации. Второй создавать что-ли? (в методе Dispose)
                  ты пока просто попробуй
                    Pit-Bul, работает. Но Dispose вызывается каждый раз, когда отключается один из клиентов. Мне это не нужно, по этому ставлю InstanceContextMode=InstanceContextMode.Single (чтобы для каждого клиента не создавался отдельный экземпляр службы). Теперь Dispose вообще не вызывается, даже при закрытии окна консоли.
                      Никто не знает, почему Dispose сервиса не вызывается при завершении работы хоста? (если поставить InstanceContextMode=InstanceContextMode.Single)
                        Dispose подняться при InstanceContextMode.Single должен только при завершении сервиса...
                        По сути, как написано в MSDN, он может и поднимается, но мы этого уже не видим :)
                        Сообщение отредактировано: Spawn.NET -
                          Цитата Spawn.NET @
                          Dispose подняться при InstanceContextMode.Single должен только при завершении сервиса...

                          Что мне и нужно. Ставлю бряк на dispose - не срабатывает вообще, и при завершении сервиса не срабатывает. А при Single вроде и не должен. Значит, dispose - не вариант. Как же тогда отловить завершение работы сервиса?
                            GoldenJoe, разве что при отключении последнего пользователя, ну или пользователя в принципе, коль уж одно соединение на всех.
                              Spawn.NET, после отключения каждого пользователя выполнять сериализацию списка пользователей... Ужас. Сервис будет грузить проц и жрать оперативу.

                              Добавлено
                              Цитата Spawn.NET @
                              при отключении последнего пользователя

                              Когда отключается пользователь, никак нельзя заранее знать, что он последний.
                                GoldenJoe, и почему меня не оставляет ощущение что ты все таки что то не так делаешь, у тебя явно серьезное упущение в логике приложения раз ты пришел к таким проблемам.
                                  ИМХО, замени консоль хост на виндовский сервис. У сервиса есть очень хороший метод OnStop. Вот в нем сериализовать будет удобно.
                                    MIF с учетом выше озвученных вопросов ему очень сложно будет такое дело отладит, и если честно то я болше склоняюсь к версии что сохранение пользователей надо выносить в логическую процедуру и делать это отдельно, и никак не при dispose обьекта
                                      ТС нам не всё сказал, посему приходится гадать. Я лично понял что лист пользователей хранится в статической (static) переменной.
                                        Таки не буду менять консоль на виндовсовский сервис, ибо
                                        Цитата Pit-Bul @
                                        очень сложно будет такое дело отладит


                                        Цитата Pit-Bul @
                                        сохранение пользователей надо выносить в логическую процедуру

                                        Имхо, сохранять надо именно по завершению работы консольной программы-хоста (а соответственно и сервиса). Чтобы при следующем запуске сервис загрузил список пользователей из xml файла и спокойно продолжил работать (иначе после перезапуска сервиса всем пользователям придеться заново регистрироваться)

                                        Цитата MIF @
                                        Я лично понял что лист пользователей хранится в статической (static) переменной.

                                        Как-то незачем делать статик, если у меня InstanceContextMode=InstanceContextMode.Single (т.е. один экземпляр сервиса на всех).
                                          GoldenJoe, что в сериализованном xml планируется хранить?
                                            Spawn.NET
                                            Я же говорил уже. Класс User описывает пользователя сервиса (как минимум логин и пароль). В xml буду хранить List<User>.
                                              Почему не сохранять информацию по мере изменения объектов в программе? Что будет, если машину с сервисом просто обесточат, изменения потеряются?
                                                Цитата Raino @
                                                Почему не сохранять информацию по мере изменения объектов в программе? Что будет, если машину с сервисом просто обесточат, изменения потеряются?

                                                :yes:
                                                GoldenJoe, сохраняй при входе, коль уж это не логи всей работы.
                                                  Raino, Spawn.NET
                                                  Ага, это еще и надежнее. Наверное, так и сделаю.
                                                  А возможно ли не сериализовывать весь список заново, например, из-за 1 пользователя? (т.е. сохранить изменения, не выполняя повторную сериализацию всего списка)
                                                    Цитата GoldenJoe @
                                                    Имхо, сохранять надо именно по завершению работы консольной программы-хоста (а соответственно и сервиса). Чтобы при следующем запуске сервис загрузил список пользователей из xml файла и спокойно продолжил работать (иначе после перезапуска сервиса всем пользователям придеться заново регистрироваться)


                                                    вот как раз то что рвало мой мозг :), как сказал бы мой шеф "двоечник, тащи ремень, пороть будем" :D

                                                    Во первых, создание списка пользователей динамически уже бред. Во вторых что значит

                                                    Цитата GoldenJoe @
                                                    иначе после перезапуска сервиса всем пользователям придется заново регистрироваться


                                                    вообще то пользователь авторизуется при каждом обращении к сервису с предоставлением учетных данных. То есть при первом запуске приложения пользователь в клиентском приложении вводит логин/пароль, клиентское приложение отправляет эту пару сервису и при удачной авторизации возвращает учетные данные клиента, которые далее клиент при каждом обращении к сервису обязан предоставить. Следовательно получаем, есть статический список пользователей, например в базе, в XML хоть просто в текстовом файлике из которого сервис при первой авторизации получает данные и отдает их клиенту. Теперь касаемо управления пользователями, то есть добавление/удаление, изменение данных и прав - это обязанность либо отдельной программки, либо части клиентского приложения доступного опять же определенным учетным записям, выбирай сам.

                                                    Вот примерно вот так :)

                                                    ЗЫ: еще покури на тему System.Security и System.IdentityModel.Policy, WCF поддерживает аутентификацию на основе пользовательских и доменных политик
                                                    Сообщение отредактировано: Pit-Bul -
                                                      Цитата GoldenJoe @
                                                      (т.е. сохранить изменения, не выполняя повторную сериализацию всего списка)

                                                      Сам на свой вопрос отвечаешь. Вручную дописать изменения, значит открыть файл, внести изменения, сохранить, закрыть... Проще сериализовать :)
                                                        Т.е. тут без вариантов - заново сериализовать весь список, так?
                                                          Ну, можешь, только нужный node исправлять, но это уже вручную.
                                                            Цитата GoldenJoe @
                                                            Pit-Bul, работает. Но Dispose вызывается каждый раз, когда отключается один из клиентов. Мне это не нужно, по этому ставлю InstanceContextMode=InstanceContextMode.Single (чтобы для каждого клиента не создавался отдельный экземпляр службы). Теперь Dispose вообще не вызывается, даже при закрытии окна консоли.


                                                            ExpandedWrap disabled
                                                              WcfService _service = null;
                                                              ....
                                                              using(_service = new WcfService(Uri))
                                                              {
                                                                _service.Open();
                                                               
                                                                 ....
                                                                 Console.ReadLine(); //просто для демонстрации :)
                                                               
                                                                _service.Close();
                                                              } //После выхода из using будет вызван Dispose() для _service;


                                                            Так-же можно подписаться на события закрытия и вызывать Dispose. Метод Dispose не вызывается сервисом WCF т.к. для него не очевидно, что это необходимость делать. И сей момент переложен на плечи внешнего кода.

                                                            Добавлено
                                                            Цитата
                                                            А возможно ли не сериализовывать весь список заново, например, из-за 1 пользователя? (т.е. сохранить изменения, не выполняя повторную сериализацию всего списка)

                                                            Зачем при каждом входе то?? Если пользователей станет много, то сервис только сериализацией и будет заниматься...

                                                            Создай подсистему активных пользователей и запусти поток, пусть с определенным интервалом смотрит на активных пользователей, кто долго неактивен, логаути и сохраняй.
                                                              Цитата Pit-Bul @
                                                              WCF поддерживает аутентификацию на основе пользовательских и доменных политик

                                                              Почитал. Может, стоит перейти со своего велосипеда:
                                                              ExpandedWrap disabled
                                                                public interface IService
                                                                {
                                                                    [OperationContract]
                                                                    bool Register(string userName, string password); // Регистрация нового пользователя. Аналогично регистрации на каком-нибудь сайте.
                                                                                                                     // На данный момент выполняю сериализацию списка пользователей в методе Register.
                                                                                                                     // Можно и в Dispose. Но! (см. далее)
                                                                 
                                                                    [OperationContract]
                                                                    bool LogOn(string userName, string password); // Войти
                                                                 
                                                                    [OperationContract]
                                                                    bool LogOff(); // Выйти
                                                                }

                                                              на это?
                                                              ExpandedWrap disabled
                                                                <serviceCredentials>
                                                                  <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="CustomUserNameValidator, MyService" />
                                                                </serviceCredentials>


                                                              Цитата maxim84_ @
                                                              После выхода из using будет вызван Dispose() для _service;

                                                              Все правильно, если закрывать программу-хост нажатием <enter> (Console.ReadLine() ведь). А если "крестиком" - не вызывается. Инфа 100% - ставил breakpoint и проверял. Сейчас кто-нибудь ответит "закрывай enter'ом и не парься". Но все-таки интересно, почему Dispose не вызывается, если закрывать "крестом". Если решить эту проблему, можно, в принципе, выполнять сериализацию в Dispose, а не в Register. Преимущество - сериализация списка пользователей выполняется всего 1 раз - при закрытии программы-хоста (Кэп намекает, что если делать это в методе Register, сериализация будет выполняться каждый раз, когда регистрируется новый пользователь. "Если пользователей станет много, то сервис только сериализацией и будет заниматься..." - как-то так.). И недостаток сериализации в Dispose - потеря данных в случаи отключения питания компьютера, на котором запущен сервис.
                                                              Так что либо большая нагрузка на сервис (сериализация в Register) либо возможность потерять данные (сериализация в Dispose). Наверное, лучше 1 вариант.
                                                                Про закрытие консоли 2 раза уж спрашивали на прошлой неделе, поищи тему
                                                                  Цитата
                                                                  Так что либо большая нагрузка на сервис (сериализация в Register) либо возможность потерять данные (сериализация в Dispose). Наверное, лучше 1 вариант.

                                                                  При больших нагрузках 1 вариант вообще никакой...я уже сказал, чем это грозит.

                                                                  Цитата
                                                                  А если "крестиком" - не вызывается.

                                                                  Сервис? крестиком...хм...ну не знаю. Нафига? Если это фоновое приложение и регистрировать должна как служба на сервисе. А при разработке можно и Enter нажать. Ну не суть...

                                                                  Цитата
                                                                  Но все-таки интересно, почему Dispose не вызывается, если закрывать "крестом".

                                                                  Уже ответил почему. Подпишись на event от консольки, говорящий о том, что ее закрыли.

                                                                  Если хочешь, можешь попробовать еще "опасный" метод:
                                                                  ExpandedWrap disabled
                                                                    class WcfService : IService
                                                                    {
                                                                      ~WcfService()
                                                                      {
                                                                         this.Dispose();
                                                                      }
                                                                    }
                                                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                  0 пользователей:


                                                                  Рейтинг@Mail.ru
                                                                  [ Script execution time: 0,0623 ]   [ 17 queries used ]   [ Generated: 23.04.24, 15:05 GMT ]