Silverlight ServiceReference вызывает исключение MethodAccessException

У меня есть операция WCF MyGetVersion(), которая возвращает System.Version. При отладке вызова из ссылки на службу Silverlight я убедился, что служба возвращает правильный объект System.Version. В сервисной справке автоматически сгенерированный метод:

       public System.Version EndMyGetVersion(System.IAsyncResult result) {
            object[] _args = new object[0];
            System.Version _result = ((System.Version)(base.EndInvoke("MyGetVersion", _args, result)));
            return _result;
        }

вызывает исключение:

Попытка методом «DynamicClass.ReadVersionFromXml(System.Runtime.Serialization.XmlReaderDelegator, System.Runtime.Serialization.XmlObjectSerializerReadContext, System.Xml.XmlDictionaryString[], System.Xml.XmlDictionaryString[])» для доступа к методу «System.Version.. ctor()' не удалось.

Чтобы увидеть это, мне пришлось включить помощник «прерывать исключение CLR». В противном случае это TargetInvocationException. Насколько я могу судить, конструктор System.Version() общедоступен. Что я делаю неправильно?


person Scott Anderson    schedule 20.07.2011    source источник


Ответы (1)


Проблема в том, что конструктор System.Version общедоступен в .NET Framework, но не в Silverlight (это внутренний, согласно Reflector). Таким образом, хотя тип сериализуем в полной структуре, его нет в Silverlight, и инструмент «Добавить ссылку на службу» должен был заменить его эквивалентным типом в SL — это ошибка в инструменте (я сообщу об этом команде разработчиков). , спасибо, что нашла).

В качестве обходного пути я бы предложил использовать «суррогатный» тип для версии и использовать его в вашем сервисном контракте только для передачи данных:

[DataContract]
public class VersionDTO
{
    [DataMember]
    public int Major { get; set; }
    [DataMember]
    public int Minor { get; set; }
    [DataMember]
    public int Build { get; set; }
    [DataMember]
    public int Revision { get; set; }

    public VersionDTO(Version version) {
        this.Major = version.Major;
        this.Minor = version.Minor;
        this.Build = version.Build;
        this.Revision = version.Revision;
    }
}

[ServiceContract]
public interface ITest
{
    [OperationContract]
    VersionDTO GetVersion();
}

Другой вариант, учитывая проблему, которую вы упомянули в комментарии, — заменить ссылку на класс Version в сгенерированном прокси-сервере для Silverlight классом, эквивалентным ему. Приведенный ниже класс можно использовать для десериализации объекта Version в SL из .NET.

    [DataContract(Name = "Version", Namespace = "http://schemas.datacontract.org/2004/07/System")]
    public class SLVersion
    {
        [DataMember(Order = 1, Name = "_Build")]
        public int Build { get; set; }
        [DataMember(Order = 2, Name = "_Major")]
        public int Major { get; set; }
        [DataMember(Order = 3, Name = "_Minor")]
        public int Minor { get; set; }
        [DataMember(Order = 4, Name = "_Revision")]
        public int Revision { get; set; }
    }
person carlosfigueira    schedule 20.07.2011
comment
Спасибо, к сожалению, контракт используется другими службами, и другие клиенты ожидают System.Version. Возможно, мне придется добавить еще одну операцию, которая просто возвращает ее в виде строки для клиента Silverlight. - person Scott Anderson; 21.07.2011
comment
Вы также можете изменить сгенерированный прокси для SL, как я добавил в ответе выше. Единственная проблема с этим подходом заключается в том, что всякий раз, когда вы обновляете ссылку на службу из Silverlight, вам придется снова заменять класс. - person carlosfigueira; 21.07.2011