WCF DataContract со списком регулярных выражений не будет сериализован должным образом

#regex #wcf #serialization #datacontract #datamember

#регулярное выражение #wcf #сериализация #datacontract #элемент данных

Вопрос:

У меня есть класс, который выглядит примерно так:

 [DataContract]
public class InboundMailbox
{
    public const char EmailSeparator = ';';

    [DataMember]
    public string POP3Host { get; set; }

    [DataMember]
    public string EmailId { get; set; }

    [DataMember]
    public string WebServiceURL { get; set; }

    [DataMember]
    public List<Regex> Allowed { get; set; }

    [DataMember]
    public List<Regex> Disallowed { get; set; }
}
  

Если Allowed и Disallowed пусты, то он отлично сериализуется в моей службе WCF. Как только один из этих списков содержит значение, я получаю это в CommunicationException:

Соединение с сокетом было прервано. Это может быть вызвано ошибкой при обработке вашего сообщения или превышением времени ожидания приема удаленным хостом, или основной проблемой с сетевыми ресурсами. Время ожидания локального сокета было ’00:00:29.9899990′.

Почему мне сложно сериализовать эти два свойства? Заранее спасибо.

Комментарии:

1. Насколько велик список регулярных выражений, которые вы отправляете по проводам?

2. Если я помещу одно регулярное выражение в один из списков, я получу исключение. И сами регулярные выражения не такие длинные, вероятно, <20 символов.

Ответ №1:

Regex Класс реализует ISerializable интерфейс, что означает, что он сериализуется как пакет свойств (словарь строки / объекта). Рассматривая реализацию ISerializable.GetObjectData для Regex класса в Reflector, он показывает, что он сериализует как шаблон (строку), так и параметры (типа RegexOptions ). Поскольку тип есть ISerializable , WCF не знает об RegexOptions этом, поэтому он не сможет сериализовать этот тип.

Одно простое решение — просто «сообщить» WCF, что это известный тип, поэтому сериализация будет работать (его легко объявить, используя [KnownType] атрибут в InboundMailbox классе (см. Ниже). Другим вариантом было бы использовать элемент данных в качестве шаблона регулярных выражений вместо самого Regex себя (и, возможно, также параметров).

 public class StackOverflow_7909261
{
    [DataContract]
    [KnownType(typeof(RegexOptions))]
    public class InboundMailbox
    {
        public const char EmailSeparator = ';';

        [DataMember]
        public string POP3Host { get; set; }

        [DataMember]
        public string EmailId { get; set; }

        [DataMember]
        public string WebServiceURL { get; set; }

        [DataMember]
        public List<Regex> Allowed { get; set; }

        [DataMember]
        public List<Regex> Disallowed { get; set; }
    }

    public static void Test()
    {
        MemoryStream ms = new MemoryStream();
        InboundMailbox obj = new InboundMailbox
        {
            POP3Host = "popHost",
            EmailId = "email",
            WebServiceURL = "http://web.service",
            Allowed = new List<Regex>
            {
                new Regex("abcdef", RegexOptions.IgnoreCase),
            },
            Disallowed = null,
        };
        DataContractSerializer dcs = new DataContractSerializer(typeof(InboundMailbox));
        try
        {
            dcs.WriteObject(ms, obj);
            Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    }
}
  

Кстати, вы бы обнаружили ошибку, если бы включили трассировку на стороне сервера; у него было бы исключение, в котором говорилось, что тип RegexOptions не ожидался.

Комментарии:

1. Ты когда-нибудь знал, что ты мой герой и все, чем я хотел бы быть? Я могу летать выше орла, потому что ты ветер под моими крыльями.