Is there a better way of customizing SOAP headers in C#

风流意气都作罢 提交于 2019-12-07 00:46:26

It seems that you are using .Net 2.0 and asmx webservices. Do you know that there is a framework called WCF (Windows Communication Framework) in .Net 3.0. I know that it is not easy to migrate to a new framework, but with WCF you get so much. Furthermore WCf can be used for so much more than WebServices (remoting, msmq and more). It is the framework that Microsoft is betting on for the future. Ie. manipulation a soap header is done using MessageContracts.

So the answer is that in WCF you can do this with MessageContracts.

Beacuse of generated class is a partial class. You can define it on another file with same namespace and class name (again partial class). Then you can override its virtual methods and define it once.

This prevents further changes on regenerated class doesn't effect the one you wrote.

On new class file you can use "GetWriterForMessage" to override and add new SOAP headers to it.

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);
    }
}

There is a way to do it, sort of; it's not necessarily pretty, and on a very simple web service it may not be worth the effort, but it at least saves you from having to re-add the attributes in when you regenerate the code.

Since the generator generates partial classes, you can:

  1. Add a file to your project that extends the web service class (the one derived from SoapHttpClientProtocol) with another "partial" section (i.e., use the same namespace and name as the generated class, and mark it "partial").

  2. Copy the methods you want to add the headers to (i.e., the same methods you've already been adding the attributes to) out of the generated code and paste them into your extension section.

  3. Rename the methods slightly so that they don't conflict with the ones in the generated code, and change the names that get passed to Invoke to match. (You may have to also tweak the other attributes on the methods to make sure they still map to the proper calls in the WSDL.)

  4. Add the custom header attribute to the renamed methods, and the header instance field to your extension section as well.

  5. Call the renamed versions from your code instead of the original versions.

As long as the method signatures don't change in the WSDL, you won't have to change anything in your code even if you regenerate. (Since you only copy the relatively short method implementations, any other structures from the WSDL will still come out of the generated code, so if they change you'll automatically get the updated versions when you regenerate. Granted, if the WSDL doesn't have any other structures in it, the utility of this is probably somewhat limited.)

It's still not ideal, but short of trying to intercept the raw XML message and put the header in directly (which you could probably do, but it would be nasty), there aren't really any other options that I know of (without moving over to WCF anyway).

I ran into this problem today. I ended creating a class that derives from the autogenerated class and overriding the GetWriterForMessage method to ensure my header was always present. I would update the header value on every call to the method.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!