Вопрос

У меня есть следующее:

[ServiceContract]
[ServiceKnownType(typeof(ActionParameters))]
[ServiceKnownType(typeof(SportProgram))]
[ServiceKnownType(typeof(ActionResult<SportProgram>))]
public interface ISportProgramBl  
{
    [OperationContract]
    IActionResult<ISportProgram> Get(IActionParameters parameters);
}

Когда я запускаю метод получения, я получаю следующую ошибку:

Была ошибка при попытке сериализовать параметр http://tempuri.org/:getresult. Анкет Сообщение innerexception было «тип» pps.core.domainmodel.support.action.actionResult`1 [[pps.core.domainmodel.sportprogram.isportprogram, pps.core.domainmodel, версия = 1,0.0.0, культура = нейтральная, publickeytoken = null]] 'с именем договора данных' actionResultOfAnyType: http://schemas.datacontract.org/2004/07/pps.core.domainmodel.support.action'не ожидается. Добавьте любые типы, не известные статически в список известных типов - например, с использованием атрибута известных типовпийт или добавления их в список известных типов, передаваемых DataContractSerializer. '. Пожалуйста, смотрите Innerexception для получения более подробной информации.

Из этой ошибки я вижу, что она может разрешить действие, но не может разрешить IsportProgram, хотя у меня есть Service Skellype (typeof (ActionResult <portprogram>)) На моем сервисном интерфейсе ...

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

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="SportProgramStb.ISportProgramBl")]
public interface ISportProgramBl {

    [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ISportProgramBl/Get", ReplyAction="http://tempuri.org/ISportProgramBl/GetResponse")]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.SportProgram.SportProgram))]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.Support.Action.ActionParameters))]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(PPS.Core.DomainModel.Support.Action.ActionResult<PPS.Core.DomainModel.SportProgram.SportProgram>))]
    object Get(object parameters);
}

Почему это идет не так ???? Обратите внимание, что он проходит через службу WCF правильно ... но он бросает исключение, когда результат возвращается.

Наконец, ActionResult выглядит так:

public interface IActionResult<T> 
{
    T Result { get; set; } 
}

Ура Энтони

Это было полезно?

Решение

Ну, я думаю, что это еще один случай, когда SOA против OOP «несоответствие импеданса». Два мира довольно отдельные.

В WCF все, что передается от клиента на сервер, передается как сериализованные сообщения - Ссылки не используются.

Это означает: все, что вы хотите сериализовать на клиенту, отправить его на сервер, десериализировать и использовать его там, должно быть конкретный - Вы не можете передать интерфейсы, вы не можете использовать «не разрешенные» дженерики - вам нужно изложить это. По сути, все, что передается от клиента через проволоку на сервер, должно быть выражено в схеме XML.

Это имеет много последствий:

  • Нет интерфейсов - вы не можете передать интерфейсы - вам нужно работать с конкретными типами
  • Нет «автоматического» наследования - вы не можете просто определить базовый класс и передать полученные классы на основе его - тех, кто также должен быть специфичен (это то, для чего предназначен атрибут службы.
  • Нет автоматических дженериков - опять же, вам нужно использовать конкретные типы

Это может звучать как множество ограничений - но это потому, что WCF использует все общение на основе сообщений - оно не может иметь дело с ссылками, наследством, дженериками и т. Д. - вам нужно это изложить.

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

Марк

PS: Я провел еще несколько исследований, и вопреки всем, что мое понимание, кажется, есть способ сериализовать все, что основано на интерфейсе и/или абстрактном базовом классе по всему проволоку, если вы можете быть уверены, что это всегда. Сеть на любом конце провода (т.е. нет совместимый с EG Java).

Видеть Пост в блоге Aaron Skonnard на NetDataContractSerializer и другой Сообщение блога а также еще один показывая, как использовать NetDataContractSerializer, чтобы иметь возможность передать такие вещи, как IPerson как параметры для ваших методов.

Другие советы

Это одна из проблем, с которыми я решаю ServiceStack.net - Мой открытый исходный код .NET и Mono Web Services Framework.

Служебный стек находился под сильным влиянием Martin Fowlers Permoning Pattern Объект объекта Поскольку это позволяет вам просто использовать DTO для определения ваших веб -сервисов - т.е. SOA Way :).

Я избегаю этого ограничения, которое присуще WCF, генерируя свои собственные WSDL, которые ведут себя так, как вы ожидаете. В качестве преимущества замены сложной конфигурации WCF / модели ServiceContract - SOAP Web Services также работает на Mono - Посмотрите на живую демонстрацию.

Это старый вопрос, и хотя принятый ответ абсолютно правильный, я наступил на это в поисках аналогичной проблемы и подумал, что смогу поделиться своим опытом. Это часто головная боль, но можно использовать дженерики в сочетании с интерфейсами с WCF. Вот рабочий пример другой (аналогичной) реализации, которую я сделал:

[ServiceContract]
[ServiceKnownType(typeof(CollectionWrapper<IAssociation>))]
public interface IService : 
{
    [OperationContract]
    ICollectionWrapper<IAssociation> FindAssociation(string name, int pageSize, int page);
}

public interface ICollectionWrapper<TModel>
{
    int TotalCount { get; set; }
    IEnumerable<TModel> Items { get; set; }
}

[KnownType(typeof(OrganizationDto))]
[KnownType(typeof(CompanyDto))]
public class CollectionWrapper<TModel> : ICollectionWrapper<TModel>
{
    [DataMember]
    public int TotalCount { get; set; }
    [DataMember]
    public IEnumerable<TModel> Items { get; set; }
}

public class CompanyDto :  IAssociation
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class OrganizationDto :  IAssociation
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Ключ здесь - использовать комбинацию KnownType а также ServiceKnownType.

Так что в вашем случае вы можете сделать что -то вроде этого:

[ServiceContract]
[ServiceKnownType(typeof(ActionParameters))]
[ServiceKnownType(typeof(ActionResult<ISportProgram>))] // Actual implementation of container, but interface of generic.
public interface ISportProgramBl  
{
    [OperationContract]
    IActionResult<ISportProgram> Get(IActionParameters parameters);
}

[KnownType(typeof(SportProgram))] // Actual implementation here.
public class ActionResult<T>
{
    // Other stuff here
    T FooModel { get; set; }
}

Это будет работать, если у вас есть общий контракт (доступ к фактическому интерфейсу обслуживания) и потребляет контракт с ChannelFactory<ISportProgramBl>. Анкет Я не знаю, работает ли это с сервисным ссылком.

Однако, похоже, есть некоторые проблемы с реализацией, как упомянуто здесь:

WCF с интерфейсом и общей моделью

И еще один похожий вопрос задал и ответил здесь:

Общие типы возврата с типом интерфейса Params в WCF

Вы возвращаете илиста T. Именно в том, что у системы есть проблемы, выясняющие, что такое.

Не уверен, можно ли вернуть интерфейс, а не тип.

Вы указываете интерфейсы в объектах, а не конкретных типах?

PPS.Core.DomainModel.Support.Action.ActionListResult<IList<PPS.Core.DomainModel.SportProgram.ISportProgram>>

Редактировать:

Я говорю, что это все конкретные типы, которые вы передаете в генериках (в том числе в субъекте через интерфейсы), передаваемые в списке известных типов. У нас были проблемы с последовательностью, где все типы не были известны.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top