Есть ли лучший способ настроить заголовки SOAP в С#?

В прошлом мне приходилось создавать собственные заголовки SOAP в проекте C#, который использовал импортированную веб-ссылку WSDL. Я нашел способ сделать это, но я никогда не был доволен этим, и я задавался вопросом, есть ли лучший способ. Что я сделал, так это создал заголовок, производный от SoapHeader:

[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://model.test.net")]
[System.Xml.Serialization.XmlRootAttribute("securitytoken", Namespace = "http://model.test.net", IsNullable = false)]
public class SpecialHeader : SoapHeader
{ 
  [System.Xml.Serialization.XmlTextAttribute()]
  public string aheadervalue;
}

Затем мне пришлось изменить код, сгенерированный из WSDL, и добавить ссылку на экземпляр нового заголовка и следующее перед каждым веб-вызовом, который я хотел содержать в своем заголовке:

[System.Web.Services.Protocols.SoapHeaderAttribute("instancename", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)]

Где «instancename» — это имя переменной экземпляра пользовательского заголовка в сгенерированном классе.

Это прекрасно работает, за исключением того, что любое изменение в WSDL требует, чтобы все это было сделано снова, поскольку оно перегенерирует класс. В других языках заголовки могут быть добавлены вне сгенерированного кода, поэтому, возможно, мне не хватает того, как это делается в С#. Есть ли лучшие способы сделать это?


person carson    schedule 01.12.2008    source источник


Ответы (4)


Похоже, вы используете веб-сервисы .Net 2.0 и asmx. Знаете ли вы, что в .Net 3.0 существует инфраструктура под названием WCF (Windows Communication Framework). Я знаю, что перейти на новый фреймворк непросто, но с WCF вы получаете так много. Кроме того, WCf можно использовать не только для веб-служб (удаленное взаимодействие, msmq и т. д.). Это платформа, на которую Microsoft делает ставку в будущем. Т.е. манипулирование мыльным заголовком выполняется с помощью MessageContracts.

Итак, ответ заключается в том, что в WCF вы можете сделать это с помощью MessageContracts.

person khebbie    schedule 17.12.2008
comment
@khebbie: я новичок в WCF и также пытаюсь настроить собственные заголовки. Контракты сообщений звучат как путь. Вы знаете хороший ресурс, где я могу прочитать об этом? - person Adam; 06.04.2010

Поскольку сгенерированный класс является частичным классом. Вы можете определить его в другом файле с тем же пространством имен и именем класса (опять же частичный класс). Затем вы можете переопределить его виртуальные методы и определить его один раз.

Это предотвращает дальнейшие изменения в регенерированном классе, не влияет на тот, который вы написали.

В новом файле класса вы можете использовать «GetWriterForMessage», чтобы переопределить и добавить к нему новые заголовки SOAP.

public partial class SampleService
{
    public string MessageID { get; set; }

    protected override System.Xml.XmlWriter GetWriterForMessage(System.Web.Services.Protocols.SoapClientMessage message, int bufferSize)
    {
        message.Headers.Add(new UsernameSoapHeader("Username"));
        message.Headers.Add(new PasswordSoapHeader("Password"));
        message.Headers.Add(new MessageIDSoapHeader(MessageID));
        return base.GetWriterForMessage(message, bufferSize);
    }
}
person vardars    schedule 30.06.2011

Есть способ сделать это, своего рода; это не обязательно красиво, и на очень простом веб-сервисе это может не стоить усилий, но, по крайней мере, избавляет вас от необходимости повторно добавлять атрибуты при повторной генерации кода.

Поскольку генератор генерирует частичные классы, вы можете:

  1. Добавьте в свой проект файл, который расширяет класс веб-службы (производный от SoapHttpClientProtocol) другим разделом "partial" (т. е. используйте то же пространство имен и имя, что и сгенерированный класс, и пометьте его как "partial").

  2. Скопируйте методы, к которым вы хотите добавить заголовки (т. е. те же методы, к которым вы уже добавляли атрибуты), из сгенерированного кода и вставьте их в раздел расширения.

  3. Слегка переименуйте методы, чтобы они не конфликтовали с методами в сгенерированном коде, и измените имена, которые передаются в Invoke, чтобы они совпадали. (Возможно, вам придется также настроить другие атрибуты методов, чтобы убедиться, что они по-прежнему сопоставляются с правильными вызовами в WSDL.)

  4. Добавьте настраиваемый атрибут заголовка в переименованные методы, а также поле экземпляра заголовка в раздел расширения.

  5. Вызовите переименованные версии из своего кода вместо исходных версий.

Пока сигнатуры методов не меняются в WSDL, вам не придется ничего менять в коде, даже если вы будете генерировать заново. (Поскольку вы копируете только относительно короткие реализации методов, любые другие структуры из WSDL все равно будут выходить из сгенерированного кода, поэтому, если они изменятся, вы автоматически получите обновленные версии при повторной генерации. Конечно, если WSDL не имеют какие-либо другие структуры, полезность этого, вероятно, несколько ограничена.)

Это все еще не идеально, но если не считать попытки перехватить необработанное XML-сообщение и поместить заголовок напрямую (что вы, вероятно, могли бы сделать, но это было бы неприятно), на самом деле нет никаких других вариантов, о которых я знаю (без перемещения в любом случае к WCF).

person Eric Rosenberger    schedule 02.12.2008

Я столкнулся с этой проблемой сегодня. Я закончил создание класса, производного от автоматически сгенерированного класса, и переопределения GetWriterForMessage, чтобы убедиться, что мой заголовок всегда присутствует. Я бы обновлял значение заголовка при каждом вызове метода.

person Hasani Blackwell    schedule 13.04.2010