Question

I am calling a 3rd party SOAP service (a Magento webstore) in ASP.NET MVC4. When importing the web service reference, all of the service methods are automatically implemented by Visual Studio, eg the login soap method is implemented as

    public string login(string username, string apiKey) {
        object[] results = this.Invoke("login", new object[] {
                    username,
                    apiKey});
        return ((string)(results[0]));
    }

But when I call this method, this.Invoke sends a POST with this user-agent header automagically added:

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; 
            MS Web Services Client Protocol 4.0.30319.18444)

This header tells the 3rd party that the user agent is IE6. And many sites automatically block IE6 with a message saying something to the effect of "We do not support IE6. Go get a real browser and try again"

So the soap call breaks but only because the 3rd party site thinks we are using IE6, not because there is anything wrong with the soap call. If we could change this header to mimic the UA string of a modern web browser then this problem would not exist.

So how then do you change the UA string used by SoapHttpClientProtocol method calls? It all happens inside of the this.Invoke method, which is part of the .NET core.

EDIT:

The object this in the above autogenerated code above is a subclass of SoapHttpClientProtocol, so yes I could just manually write the user agent in there myself:

    public string login(string username, string apiKey) {
        this.UserAgent = "something, anything except for IE6";
        object[] results = this.Invoke("login", new object[] {
                    username,
                    apiKey});
        return ((string)(results[0]));
    }

BUT, this is autogenerated code and will be overwritten anytime the 3rd party updates their service (for Magento it is quite frequently), and I would have to manually add it to every single autogenerated function (a lot of them). So it's not practical to just write this.UserAgent = "not IE6" here, it needs to be a more useful solution.

Was it helpful?

Solution

The generated Web Service reference class derives itself from SoapHttpClientProtocol, something like this:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="MyGeneratedWebServiceSoap", Namespace="http://www.killroy.com/webservices/")]
public partial class MyGeneratedWebService : System.Web.Services.Protocols.SoapHttpClientProtocol
{
    ...
}

SoapHttpClientProtocol has a read/write UserAgent property, so what you could do is derive from this class again and customize the user agent like this (this way you can automatically replace all instance creations of the original class by the new one):

public class SuperWs: MyGeneratedWebService
{
    public SuperWs()
    {
        UserAgent = "Mozilla/5.0 (Killroy was here)";
    }
}

OTHER TIPS

is the autogenerated class a partial class?

When it is a partial class then you should create an own extention to the generated class like "myWebservice_partial.cs", rename the class to:

  • public partial class "GENERATEDCLASSNAME"{}

    and define/ override the constructor. within this you can set your UserAgent. This is updatesave.

This code is untested and written from my brain. I don`t know now if you have to innerhit from the SoapHttpClientProtocol (See Comment)

E.G.

FileName: WsClass_partial.cs

public partial class WsClass /* :SoapHttpClientProtocol */ {
  public WsClass(string useragent):this(){
     this.UserAgent = useragent;
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top