На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
> Не могу перекинуть OleDbConnection через Remoting
    Если объект, вызываемый через Remouting, содержит член типа OleDbConnection, то при вызове выскакивает исключение: "Из-за ограничений по соображениям безопасности тип System.Runtime.Remoting.ObjRef недоступен"

    ВОПРОС РЕШЕН. Похоже, TypeFilterLevel=TypeFilterLevel.Full; помог.
    Сообщение отредактировано: Jupiter -
      Jupiter, здается мне, если через ремотинг перекидывается объект подключения к базе данных - в приложении серьезные проблемы с архитектурой
        Передавать объект подключения к базе через Remoting - не плохая идея, если у меня база реализована в виде MS Access (.mdb) на сервере (служба), а клиент подключается к базе удаленно. Это должно позволить мне избежать использования SQL сервера. (Ну вот так у нас получается исторически).

        Проблема, как оказаласть, не решена. Когда я конкретно начинаю использовать это соединение, то получаю исключение:

        ExpandedWrap disabled
                  private void YYYY(OleDbConnection conn)
                  {
                      DataTable customerTable = new DataTable();
                      OleDbCommand myCmd = new OleDbCommand();
                      DataSet ds = new DataSet();
                                
                      try {
                          if (conn.State == ConnectionState.Closed) conn.Open();
                          myCmd.Connection = conn;
                          myCmd.CommandText = "SELECT * FROM trModules";
                          
                          OleDbDataAdapter da = new OleDbDataAdapter(myCmd);
                          OleDbCommandBuilder db = new OleDbCommandBuilder(da);
                          DataTable dt = new DataTable();
                          
                          /////////////////////
                          da.Fill(dt);       // Все, приехали...
                          /////////////////////
                      }
                      // ...
                 }


        Вот такое исключение:

        --------------------------------------------------------------------------------------------------------------------------

        Failed to connect to data source -- System.Runtime.Remoting.RemotingException: Отказано в разрешении: удаленный вызов статических методов и методов, не являющихся общими.

        Server stack trace:
        в System.Runtime.Remoting.Channels.ChannelServices.DispatchMessage(IServerChannelSinkStack sinkStack, IMessage msg, IMessage& replyMsg)

        Exception rethrown at [0]:
        в System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
        в System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
        в System.Data.OleDb.OleDbConnection.CheckStateOpen(String method)
        в System.Data.OleDb.OleDbCommand.ValidateConnection(String method)
        в System.Data.OleDb.OleDbCommand.ValidateConnectionAndTransaction(String method)
        в System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method)
        в System.Data.OleDb.OleDbCommand.ExecuteReader(CommandBehavior behavior)
        в System.Data.OleDb.OleDbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
        в System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
        в System.Data.Common.DbDataAdapter.Fill(DataTable[] dataTables, Int32 startRecord, Int32 maxRecords, IDbCommand command, CommandBehavior behavior)
        в System.Data.Common.DbDataAdapter.Fill(DataTable dataTable)
        в XXX.fModules.YYYY(OleDbConnection conn) в D:\Projects\XXX\fModules.cs:строка 65
          Цитата Jupiter @
          Передавать объект подключения к базе через Remoting - не плохая идея, если у меня база реализована в виде MS Access (.mdb) на сервере (служба), а клиент подключается к базе удаленно.

          Идея не хорошая. Мне кажется, что ты не совсем правильно понимаешь концепцию. Хорошая идея, когда сервер общается с БД, а клиент вызывает методы сервера, для получения и отпраки данных.
            Да, мне это и нужно. Подскажи, если не в лом, (в общих словах) как реализовать обмен данными между клиентом и сервером. Я расчитывал, что (грубо говоря) от клиента к серверу будут идти SQL-инструкции, а от сервера к клиенту - DataSet'ы. Но похоже, с передачей ДатаСетов - напряженка. Что тогда? Массивы?
            Спасибо.
              Jupiter, вариантов много.

              1. Простой и довольно эффективный использовать DataTabel как трансферный объект. Достоинства простота реализации, довольно высокая скорость передачи данных. В данном случае по Фаулеру ты используешь "шлюз доступа к таблице".
              Имеем например таблицу Persons, а в коде класс Persons который по сути есть врапером над DataTable и имеет методы по инициализации его из БД и обновлению данных в нем. Громадный недостаток отстутствие типизации.

              2. Использовать коллекции. Это обычно более правильный в сложных проектах путь. В данном случае ты имеешь класс Person представляющий абстракцию строки из таблицы в БД (шлюз доступа к строке), соответственно коллекция (List<Person>) таких объектов есть представление таблицы. Паралельно пишешь контролеры, которые сводишь например в репозиторий. С их помощью ты будешь выбирать данные. Ответственность на сохранение и обновление объектов обычно ложится на сами шлюзы. Достоинство, код обычно более точно характеризует то, что ты реально программируешь и соответствует предметной области. Код строго типизирован и с ним легко работать клиенту. Из недостатков, намного больше писанины. Поэтому в таких случаях обычно используют объектно реляционный преобразователь, который твои объекты отображает на БД и обратно.

              Ну и на последок, нужно всегда помнить, что распределенное приложение очень требовательно к объему передаваемых по сети данных, их нужно минимизировать. Лично я обычно использую фасадный класс, который по возможности имеет простой интерфейс для удаленного взаимодействия клиента с сервером. Методы которого возвращают DTO (Data Transfer Object) если смотреть на вариант 1 и принимает по возможности максимально простой список аргуметов. И не забывай, что клиенту никогда не понадобится 1000 000 записей ;)
                Понятно, спасибо. Мне понравился первый метод. Только не ясно что такое "по Фаулеру".

                Цитата
                Имеем например таблицу Persons, а в коде класс Persons который по сути есть врапером над DataTable

                Как хранятся записи таблицы в этом классе?
                Сообщение отредактировано: Jupiter -
                  Цитата Jupiter @
                  Не понятны слова "по Фаулеру"

                  Есть книга одна умная им написаная где он пытался обобщить опыт в виде шаблонов для корпоративніх приложений.

                  Цитата Jupiter @
                  "врапером"

                  обвертка над чем либо.

                  Цитата Jupiter @
                  Как я понял, класс Persons представляет ВСЮ таблицу, а не одну запись. Как в нем хранятся записи?

                  В виде объекта DataTable

                  выглядеть в примитивном виде может так:

                  ExpandedWrap disabled
                    public class Persons
                    {
                        private DataTable _table;
                        private DbConnection _connection;
                        private DbDataAdapter _adapter;
                     
                        public Persons()
                        {
                            // инициализация объектов
                        }
                     
                        public DataTable GetData()
                        {
                            // заполняем-возвращаем
                        }
                     
                        public void Update(DataTable changedData)
                        {
                             // обновляем записи в БД.
                        }
                     
                        ...
                    }


                  При этом логичным выглядит вынести общую логику в абстрактный класс, возможно с использованием Generic
                  Далее все такие классы сводятся к единому контексту который может содержать их коллекцию чем-то похоже на DataSet, но при этом иметь методы вроде SubminChanged .. или явные методы по получению наборов записей из классов аналогичных Persons. Вариантов тьма. Потом ты используешь эти классы уже в своем фасаде, который делегирует вызовы, уже конкретным шлюзам или контексту, там же можно расположить и различные бизнесс правила. Вообще вариант решения в лоб. Так часто делают, когда проекты не большие или ориентированы исключительно на работу с данными.

                  Добавлено
                  Цитата Jupiter @
                  Только не ясно что такое "по Фаулеру".

                  http://www.books.ru/shop/books/156126

                  Есть просто много авторов и у каждого из них часто своя терминология.
                    Все теперь ясно. Спасибо. Фишка в том, что через Remoting вместо объекта Connection мы передаем DataTable :) Попробуем...
                      Да, действительно, DataTable успешно передается через Remoting!!! (не знаю уж почему OleDbConnection не передается, а DataTable - передается). Вот такой примитивный метод, реализованный в Remoting-классе, уже позволяет удаленно извлекать данные по sql-запросу:

                      ExpandedWrap disabled
                                public DataTable GetDataTable(string sql)
                                {
                                    OleDbCommand myCmd = new OleDbCommand(sql, _domainDbConn);
                                    OleDbDataAdapter da = new OleDbDataAdapter(myCmd);
                                    OleDbCommandBuilder db = new OleDbCommandBuilder(da);
                                    DataTable dt = new DataTable();
                                    da.Fill(dt);
                                    return dt;
                                }

                      :) :) :)
                        Цитата Jupiter @
                        такой примитивный метод, реализованный в Remoting-классе, уже позволяет удаленно извлекать данные по sql-запросу

                        Надеюсь ты так не станешь делать в своем приложении, а код привел исключительно для демонстрации :)
                          Цитата
                          Надеюсь ты так не станешь делать в своем приложении, а код привел исключительно для демонстрации
                          Ну да, там должно быть все упрятано внутрь, под предметную область. СПАСИБО!
                            Добрый день.
                            Также прошу помощи, т.к. столкнулся с такой же "проблемой" и не совсем понятна суть предлагаемого решения
                            Итак, есть
                            клиент
                            сервер в режиме синглетон
                            БД

                            клиент запрашивает получить, к примеру, спискок сотрудников.
                            Если я правильно понял, то правильное решение -- сделать "обертку" для этих данных -- для чего juice как пример привел класс Person.
                            Вопрос -- как и где вызывать "создание", получение данных. понятно, что на сервере. мне не совсем ясна реализация

                            т.е.
                            Клиент вызывает
                            remoteobject.GetPerson();

                            или

                            Person prs = new Person();
                            prs.GetData();
                            но как тогда быть с коннекшеном, который требуется для получения данных?

                            как правильно?
                            Сорри, может за сумбурное вопрос, но пли -- нид хелп :)
                              Shogunx, у удаленного объект реализует интерфес:

                              ExpandedWrap disabled
                                List<Person> AllPerson();
                                Person GetPersonForId(long id);
                                ...
                              Тогда ты на клиенте будешь вызывать так:

                              ExpandedWrap disabled
                                List<Peroson> persons = remoteobject.AllPerson();
                              или
                              ExpandedWrap disabled
                                Person person = remoteObject.PersonForId(long id);
                              а
                              ExpandedWrap disabled
                                Person person = new Person()
                              дальше заполняем объект ты будешь создавать на клиенте только для того, что бы сохранить его на сервере:
                              ExpandedWrap disabled
                                remoteObject.AddPerson(Person person) //часто предпочтительней передать просто список парамметров, а конструировать Person на сервере
                              Мысль думаю понятна. Для взаимодействия .NET to .NET, типы вроде Person должны быть объявлены в отдельной сборке доступной как клиенту так и серверу.

                              Теперь о том, что делает сервер.

                              Рассмотрим пример метода:

                              ExpandedWrap disabled
                                public List<Person> AllPerson()
                                {
                                     return Database.PersonProvider.GetAll();
                                }


                              А вотстатическое свойство PersonProvider объекта Database возвращает ссылку на экземпляр какого нибудь PersonController, может быть реализовано примерно так:

                              ExpandedWrap disabled
                                public class PersonController : EntityController
                                {
                                    public List<Person> GetAll()
                                    {
                                        Выбыраем их БД данные и возврящаем клиенту.
                                    }    
                                }


                              При этом объект вроде EntityController и должен содержать объект Connection и прочую общую ерунду.
                                juice, спасибо большое за помощь, более менее стало приходит озарение :), но все-таки можно тебя еще помучать

                                итак, я накидал вот такой код

                                ExpandedWrap disabled
                                      public class EntityController
                                      {
                                          private SqlConnection sqlConnection = new SqlConnection();
                                   
                                          public string BuildConnectionString()
                                          {
                                              return null;
                                          }
                                   
                                          public EntityController()
                                          {
                                          }
                                      }
                                   
                                      public class PersonController : EntityController
                                      {
                                          public DataTable GetList()
                                          {
                                              return null;
                                          }
                                   
                                          public PersonController()
                                          {
                                          }
                                      }
                                   
                                   
                                      public class Databases
                                      {
                                          public static PersonController persons;
                                   
                                          public Databases()
                                          {
                                   
                                          }
                                      }
                                   
                                      public interface IRemoteObject
                                      {
                                   
                                          DataTable GetAllPerson();
                                      }
                                   
                                      public class RemoteObject : MarshalByRefObject, IRemoteObject
                                      {
                                          private Databases rData = new Databases();
                                   
                                          public DataTable GetAllPerson()
                                          {
                                              rData.persons.GetList();
                                          }
                                      }


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

                                Далее, клиент подключается к серверу, который уже "держит" соединение с БД.
                                Соответственно на сервере есть уже созданный объект EntityController.

                                Но вот здесь по коду возникает затык, а именно в

                                ExpandedWrap disabled
                                  rData.persons.GetList();


                                Сорри, если написал бред :))
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:


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