На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
> WebService: как передать custom-type?
    Создал вэб-сервис, в нём метод, возвращающий List<ACountry>,
    ExpandedWrap disabled
      namespace table
      {
          [XmlInclude(typeof(ACountry))]
          [Serializable]
          public abstract class ACountry
          {
              // ... плюс ещё много методов
       
              #region Fields
       
              [MapField("Id")]
              public abstract string m_strId { get; set; }
              [MapField("Name")]
              public abstract string m_strName { get; set; }
       
              #endregion
          }
      }


    ExpandedWrap disabled
          [WebMethod]
          //[System.Xml.Serialization.XmlInclude(typeof(ACountry))]
          public List<ACountry> GetCountriesHavingTeams()
          {
              return ACountry.GetCountryWithTeamList();
          }

    В отдельном приложении создал WebReference на этот WebService (под именем ElitaWS), и пытаюсь получить данные:
    ExpandedWrap disabled
              //[XmlInclude(typeof(ElitaWS.ACountry))]
              private void MyMethod
              {
                  ElitaWS.ws_data w = new HW.ElitaWS.ws_data();
                  HW.ElitaWS.Pair[] lstC = w.GetCountryFieldsHavingTeams();
              }

    После отработки вэб-службы (смотрю пошагово отладчиком) получаю
    Цитата
    System.Web.Services.Protocols.SoapException was unhandled by user code
    Message="System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type table.BLToolkitExtension.ACountry was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.\n at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write2_ACountry(String n, String ns, ACountry o, Boolean isNullable, Boolean needType)\n at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write6_Item(Object[] p)\n at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer5.Serialize(Object objectToSerialize, XmlSerializationWriter writer)\n at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)\n --- End of inner exception stack trace ---\n at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)\n at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle)\n at System.Web.Services.Protocols.SoapServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)\n at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)\n at System.Web.Services.Protocols.WebServiceHandler.Invoke()\n --- End of inner exception stack trace ---"
    Source="System.Web.Services"
    Actor=""
    Lang=""
    Node=""
    Role=""
    StackTrace:
    at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
    at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
    at HW.ElitaWS.ws_data.GetCountriesHavingTeams() in d:\project\tests\hw\web references\elitaws\reference.cs:line 121
    at HW.WorkflowHW.InWorkingHours(Object sender, ConditionalEventArgs e) in D:\Project\Tests\HW\Workflow1.cs:line 35
    at System.Workflow.Activities.CodeCondition.Evaluate(Activity ownerActivity, IServiceProvider provider)
    at System.Workflow.Activities.IfElseActivity.Execute(ActivityExecutionContext executionContext)
    at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(T activity, ActivityExecutionContext executionContext)
    at System.Workflow.ComponentModel.CompositeActivityExecutor`1.Execute(T activity, ActivityExecutionContext executionContext)
    at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(Activity activity, ActivityExecutionContext executionContext)
    at System.Workflow.ComponentModel.ActivityExecutionFilter.Execute(Activity activity, ActivityExecutionContext executionContext)
    at System.Workflow.ComponentModel.FaultAndCancellationHandlingFilter.Execute(Activity activity, ActivityExecutionContext executionContext)
    at System.Workflow.ComponentModel.ActivityExecutorOperation.Run(IWorkflowCoreRuntime workflowCoreRuntime)
    InnerException:

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

    Хэлп, плиз.

    Добавлено
    Добавил только что [Serializable] к классу ACountry - не помогло.

    P.S. Обычные типы (Pair, string, List<Pair>) - передаются без проблем.
    Сообщение отредактировано: Budda -
      Я не знаю тонкостей в данном вопросе, но когда я юзал WCF и передавал через него типизированные коллекции (в т.ч. деревья) никаких проблем не возникало, и всё работало правильно.
        А как у тебя были объявлены передаваемые типы? [Serializable]? Что-то ещё?
          Для дерева у меня был свой тип. он был настраеваемый (то бишь с дженериками, <T>)+ Serializable (точнее ISerializable).

          Добавлено
          Стоп! ща глянул код - я соврал.
          У меня тогда возникли какие то проблемы, и потому сериализовал код я вручнуй, а сервис передавал просто массив байт.
          :rolleyes:
            Alexus во... и я думаю, что у меня проблемы с сериализацией... скорее всего чистой декларации атрибутом [Serializable] - мало... надо ещё чё-нить добавить. Надо почитать про сериализацию


            Цитата Alexus @
            передавал просто массив байт

            ага, вот и я извращался так же, но я передавал List<Pair> :)
              Я думаю, что все нормально будет передаваться, если поступить так:

              public CountryList GetCountriesHavingTeams()
              {
              return ACountry.GetCountryWithTeamList();
              }

              где СountryList определен так:

              [Serializable]
              public class CountryList : List<Country>
              {
              }
                Цитата juice @
                public class CountryList : List<Country>
                {
                }

                -

                juice прав, у дженериков траблы с сериализацией, надо обертки писать
                  PIL
                  juice

                  Спасибо, вечером попробую - доложу.
                    Не. Сериализуется моё дерево нормально обычным форматтером (BinaryFormatter) - .Serialize(), .Deserealize() без каких либо модификаций.
                    Но вот если сериализовать объекты начинает инфраструктура WCF(а не я через форматтер), возникают проблемы.

                    Видать фишка в том, что WCF юзает BinaryFormatter как то не стандартно...
                    Я думаю, при использовании WCF нужно действительно юзать какие то дополнительные аттрибуты, управляющие тем как WCF использует стандартные механизмы сериализации.

                    Но я не стал копать глубоко - мне хватило просто того, что почти всё передаётся нормально, о довольно сложные вещи можно и передать в виде масива байт...
                      К слову, я доступался к вэб-сервису из WWF-проекта.
                        Цитата Alexus @
                        Не. Сериализуется моё дерево нормально обычным форматтером (BinaryFormatter) - .Serialize(), .Deserealize() без каких либо модификаций.
                        Но вот если сериализовать объекты начинает инфраструктура WCF(а не я через форматтер), возникают проблемы.


                        ПРоблемы возникали такие - на сервере метод отрабатывает, а клиент результата не получает - вместо этого ошибка
                        ExpandedWrap disabled
                          The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.9843750'.


                        Как видно, причины совсем не очевидны.

                        Однако с трблой я разобрался:
                        она возникает в том случае, если в контракте указан какой то базовый тип или интерфейс, а фактически передаётся его наследдник.
                        В общем, если в "serialization graph" появляется объект неожиданного типа.
                        Та же трабла есть при XML сериализации - и решается она здесь так же - аттрибутом [ServiceKnownType(...)]
                          Цитата Alexus @
                          она возникает в том случае, если в контракте указан какой то базовый тип или интерфейс, а фактически передаётся его наследдник.
                          В общем, если в "serialization graph" появляется объект неожиданного типа.
                          Та же трабла есть при XML сериализации - и решается она здесь так же - аттрибутом [ServiceKnownType(...)]

                          - для WCF - есть очень красивый выход: использование NetDataContractSerializer на клиенте и на сервере, тогда можно хоть интерфейсные ссылки, хоть женерики, все передавать. Он умеет сериализовать-десериализовать информацию о типах. Но как его применять - это наверное надо в FAQ писать, либо статью, там с десяток классов писать нужно для удобства юзания.
                            да, заморочек там предостаточно. Но цель их введения проста - обеспечить возможность клиенту работать со службой, не получая от неё никаких сборок с типами, следуя, вместо этого, опубликованному контракту на вызовы и, главное, на данные.

                            Добавлено
                            И если чётко понимать и разграничивать какие форматы данных подлежат передаче в виде контракта, а какаие - в виде сераиализованных объектов, тогда проблемы исчезают.
                            А отличие между ними в том, что в контрактных данных запрещён полиморфизм, а в сериализованных - разрешён.
                            1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                            0 пользователей:


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