Могу ли я остановить мой WCF, генерирующий ArrayOfString вместо строки [] или List <string>

У меня есть небольшая проблема с прокси-серверами WCF, где сообщение содержит List<string> в качестве параметра.

Я использую ссылку "Добавить службу" в Visual Studio для создания ссылки на мою службу.

   // portion of my web service message
   public List<SubscribeInfo> Subscribe { get; set; }
   public List<string> Unsubscribe { get; set; }

Это сгенерированные свойства на моем MsgIn для одного из моих веб-методов. Вы можете видеть, что он использовал ArrayOfString, когда я использую List<string>, а другой принимает List<SubscribeInfo> -, который соответствует моему исходному объекту С# выше.

[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public System.Collections.Generic.List<DataAccess.MailingListWSReference.SubscribeInfo> Subscribe {
    get {
        return this.SubscribeField;
    }
    set {
        if ((object.ReferenceEquals(this.SubscribeField, value) != true)) {
            this.SubscribeField = value;
            this.RaisePropertyChanged("Subscribe");
        }
    }
}

[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
publicDataAccess.MailingListWSReference.ArrayOfString Unsubscribe {
    get {
        return this.UnsubscribeField;
    }
    set {
        if ((object.ReferenceEquals(this.UnsubscribeField, value) != true)) {
            this.UnsubscribeField = value;
            this.RaisePropertyChanged("Unsubscribe");
        }
    }
}

Созданный класс ArrayOfString выглядит следующим образом. Это класс, сгенерированный в моем коде - это не класс .NET. Это фактически породило меня класс, который наследует List, но не имеет "порядочности", чтобы создать мне любые конструкторы.

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
    [System.Runtime.Serialization.CollectionDataContractAttribute(Name="ArrayOfString", Namespace="http://www.example.com/", ItemName="string")]
    [System.SerializableAttribute()]
    public class ArrayOfString : System.Collections.Generic.List<string> {
    }

Проблема в том, что я часто создаю свое сообщение следующим образом:

client.UpdateMailingList(new UpdateMailingListMsgIn()
{
    Email = model.Email,
    Name = model.Name,
    Source = Request.Url.ToString(),
    Subscribe = subscribeTo.ToList(),
    Unsubscribe = unsubscribeFrom.ToList()
});

Мне очень нравится чистый взгляд, который это дает мне.

Теперь для актуальной проблемы:

Я не могу присвоить List<string> свойству Unsubscribe, который является ArrayOfString, даже если он наследует List. На самом деле я не могу найти ЛЮБОЙ способ присвоить его без дополнительных утверждений.

Я пробовал следующее:

  • new ArrayOfString(unsubscribeFrom.ToList()) - этот конструктор не существует: - (
  • изменение типа массива, используемого генератором кода, не работает - он всегда дает мне ArrayOfString (!?)
  • попробуйте применить List<string> к ArrayOfString - не удается выполнить "неактивный", даже если он компилирует только тонкие
  • create new ArrayOfString(), а затем AddRange(unsubscribeFrom.ToList()) - работает, но я не могу сделать все это в одном выражении
  • создайте функцию преобразования ToArrayOfString(List<string>), которая работает, но не так чиста, как я хочу.

Он делает это только для строки, что раздражает.

Мне что-то не хватает? Есть ли способ сказать ему не генерировать ArrayOfString - или какой-нибудь другой трюк, чтобы назначить его?

Ответ 1

Любой объект .NET, который реализует метод с именем "Добавить", может быть инициализирован так же, как массивы или словари.

Поскольку ArrayOfString реализует метод "Добавить", вы можете его инициализировать следующим образом:

var a = new ArrayOfString { "string one", "string two" };

Но если вы действительно хотите инициализировать его на основе другой коллекции, вы можете написать для этого метод расширения:

public static class U
{
    public static T To<T>(this IEnumerable<string> strings)
        where T : IList<string>, new()
    {
        var newList = new T();
        foreach (var s in strings)
            newList.Add(s);
        return newList;
    }
}

Использование:

client.UpdateMailingList(new UpdateMailingListMsgIn()
{
    Email = model.Email,
    Name = model.Name,
    Source = Request.Url.ToString(),
    Subscribe = subscribeTo.ToList(),
    Unsubscribe = unsubscribeFrom.To<ArrayOfString>()
});

Ответ 2

Я предпочитаю не возвращать общие типы через границу сервиса в первую очередь. Вместо этого верните Unsubscribe как string[] и SubscriptionInfo как SubscriptionInfo[]. При необходимости массив можно легко преобразовать в общий список на клиенте, как показано ниже:

Unsubscribe = new List<string>(unsubscribeFrom);
Subscribe = new List<SubscriptionInfo>(subscribeTo);

Ответ 3

Слишком поздно, но может помочь людям в будущем...

Использовать svcutil и явно сообщать в командной строке, что вы хотите, чтобы прокси-класс был сериализован XmlSerializer, а не DataContractSerializer (по умолчанию). Здесь образец:

svcutil/out:c:\Path\Proxy.cs/config:c:\Path\Proxy.config/async/serializer: XmlSerializer/namespace: *, YourNamespace http://www.domain.com/service/serviceURL.asmx

Обратите внимание, что веб-служба является веб-службой ASP.NET ok?!

Ответ 4

Если вы используете VS 2008 для потребления услуг, тогда есть простое решение.

Нажмите кнопку "Дополнительно..." в диалоговом окне прокси-сервера, которое отображается при добавлении сервисной ссылки. В раскрывающемся списке Тип коллекции вы можете выбрать System.Generic.List. Теперь возвращаемые методы должны работать правильно.

(Надеюсь, это то, о чем вы просили, я немного устал, и вопрос был для меня трудным для чтения.)