Reputation: 73
My wsdl put a wrong domain in address location, How to fix it?
- <wsdl:service name="XWebService">
- <wsdl:port name="XServiceSoap" binding="tns:XWebServiceSoap">
<soap:address location="https://machine.wrongdomain.com.br/webservices/MapleStoryWebService.asmx" />
</wsdl:port>
- <wsdl:port name="XWebServiceSoap12" binding="tns:XWebServiceSoap12">
<soap12:address location="https://machine.wrongdomain.com.br/webservices/XWebService.asmx" />
</wsdl:port>
- <wsdl:port name="XWebServiceHttpGet" binding="tns:XWebServiceHttpGet">
<http:address location="https://machine.wrongdomain.com.br/webservices/MapleStoryWebService.asmx" />
</wsdl:port>
- <wsdl:port name="XWebServiceHttpPost" binding="tns:XWebServiceHttpPost">
<http:address location="https://machine.wrongdomain.com.br/webservices/XWebService.asmx" />
</wsdl:port>
</wsdl:service>
The true domain is like https://machine.goodDomain.com.br
Upvotes: 3
Views: 20857
Reputation: 496
There are few solution, I will sort them from simplicity to accuracy. :)
Url
property on a client side, like in that case: public class MyWebService : RemoteService
{
public MyWebService() : base()
{
Url = ConfigurationManager.AppSettings["MyServiceCustomUrl"];
}
}
Obvious drawback: most probably you will not able to test the service properly using generated html (I mean generated forms for web methods).
wsdlHelpGenerator
.I didn't test this solution, but at a glance it looks simply enough if you create your own based on original DefaultWsdlHelpGenerator.aspx (you can find it in C:\Windows\Microsoft.NET\Framework* folders, in my case it was C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\DefaultWsdlHelpGenerator.aspx).
soapExtensionReflectorTypes
. It will allow you to do anything with your HttpSoap protocol addresses.Create a handler (sample below will change http to https):
public class HttpsReflector : SoapExtensionReflector
{
public override void ReflectMethod()
{
// nothing to override
}
public override void ReflectDescription()
{
ServiceDescription description = ReflectionContext.ServiceDescription;
foreach (System.Web.Services.Description.Service service in description.Services)
{
foreach (Port port in service.Ports)
{
foreach (ServiceDescriptionFormatExtension extension in port.Extensions)
{
if (extension is SoapAddressBinding binding)
{
binding.Location = binding.Location.Replace("http://", "https://");
}
}
}
}
}
}
Register it in web.config:
<system.web>
<webServices>
<soapExtensionReflectorTypes>
<!-- Required to replace http in addresses for HttpSoap protocol -->
<add type="MyWebServices.WsdlFixHttp.HttpsReflector, MyWebServices"/>
</soapExtensionReflectorTypes>
</webServices>
</system.web>
A drawback: no control over HttpPost/HttpGet protocols.
Create 2 classes, stream decorator:
public class StreamWatcher : Stream
{
private readonly Stream _base;
private readonly MemoryStream _memoryStream = new MemoryStream();
public StreamWatcher(Stream stream)
{
_base = stream;
}
public override void Flush()
{
_base.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _base.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
_memoryStream.Write(buffer, offset, count);
_base.Write(buffer, offset, count);
}
public override string ToString()
{
return Encoding.UTF8.GetString(_memoryStream.ToArray());
}
public override bool CanRead => _base.CanRead;
public override bool CanSeek => _base.CanSeek;
public override bool CanWrite => _base.CanWrite;
public override long Seek(long offset, SeekOrigin origin) => _base.Seek(offset, origin);
public override void SetLength(long value) => _base.SetLength(value);
public override long Length => _base.Length;
public override long Position
{
get => _base.Position;
set => _base.Position = value;
}
}
and the module:
public class WsdlFixHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.EndRequest += (s, e) => OnEndRequest(s, e);
context.BeginRequest += (s, e) => OnBeginRequest(s, e);
}
private void OnBeginRequest(object sender, EventArgs e)
{
HttpContext httpContext = HttpContext.Current;
if (httpContext.Request.Url.Query.Equals("?WSDL", StringComparison.InvariantCultureIgnoreCase)
|| IsAsmxGetRequest(httpContext))
{
httpContext.Response.Filter = new StreamWatcher(httpContext.Response.Filter);
}
}
private void OnEndRequest(object sender, EventArgs e)
{
HttpContext httpContext = HttpContext.Current;
string oldValue = "", newValue = "";
bool replacementRequired = false;
if (httpContext.Request.Url.Query.Equals("?WSDL", StringComparison.InvariantCultureIgnoreCase))
{
oldValue = ":address location=\"http://";
newValue = ":address location=\"https://";
replacementRequired = true;
}
else if (IsAsmxGetRequest(httpContext))
{
oldValue = "<form target=\"_blank\" action='http://";
newValue = "<form target=\"_blank\" action='https://";
replacementRequired = true;
}
if (replacementRequired)
{
string wsdl = httpContext.Response.Filter.ToString();
wsdl = wsdl.Replace(oldValue, newValue);
httpContext.Response.Clear();
httpContext.Response.Write(wsdl);
httpContext.Response.End();
}
}
private static bool IsAsmxGetRequest(HttpContext httpContext)
{
return httpContext.Response.ContentType == "text/html"
&& httpContext.Request.CurrentExecutionFilePathExtension.Equals(".asmx", StringComparison.InvariantCultureIgnoreCase)
&& httpContext.Request.HttpMethod == "GET";
}
public void Dispose()
{
}
}
Then register the module in web.config:
<system.webServer xdt:Transform="Insert">
<modules>
<!-- Required to replace http in addresses for HttpPost/HttpGet protocols -->
<add name="WsdlFixHttpModule" type="MyWebServices.WsdlFixHttp.WsdlFixHttpModule, MyWebServices"/>
</modules>
</system.webServer>
Please note, the registration above is for integration mode, for classic one you need to register it inside system.web
.
So, in our legacy project I used 3+4 approach, but if I'd want to do that again, I will try to use #2 approach instead. :)
Upvotes: 0
Reputation: 406
Another option is to use the IIS URL Rewrite module (http://www.iis.net/downloads/microsoft/url-rewrite)
First up - capture the output from XWebService.asmx?WSDL and save it as an HTML file (e.g. wsdl.htm).
Edit this file and change the location to the alternative address
... from thishost.domain.com:
- <wsdl:port name="XWebServiceHttpPost" binding="tns:XWebServiceHttpPost">
<http:address location="http://thishost.domain.com/XWebService.asmx" />
</wsdl:port>
...to thathost.domain.com:
- <wsdl:port name="XWebServiceHttpPost" binding="tns:XWebServiceHttpPost">
<http:address location="http://thathost.domain.com/XWebService.asmx" />
</wsdl:port>
In IIS - find the URL Rewrite icon in the website/virtual Feature View . Then click Add Rule(s) and choose Inbound Rule - Blank rule.
With the rule - name it appropriately and set the pattern match for the webservice URL that will receive the WSDL request. For RegEx:
(.*)XWebservice.asmx
For the conditions match {QUERY_STRING} to WSDL and {REQUEST_METHOD} to GET.
For the Action - set it to Rewrite (so this is transparent to the client) and choose the file that we saved it as earlier (wsdl.htm).
This also adds a new rewrite section to the system.webServer section of the web.config
<system.webServer>
<rewrite>
<rules>
<rule name="WSDL Rewrite" stopProcessing="true">
<match url="(.*)XWebService.asmx" />
<conditions>
<add input="{QUERY_STRING}" pattern="WSDL" />
<add input="{REQUEST_METHOD}" pattern="GET" />
</conditions>
<action type="Rewrite" url="wsdl.htm" />
</rule>
</rules>
</rewrite>
</system.webServer>
Upvotes: 2
Reputation: 7513
Why not just manually edit the address in the WSDL file to what it should be?
If the WSDL is generated by some other tool, then let us know how it is being generated and perhaps we can help. Otherwise, there is no law against modifying the generated file to suit your needs. If all that is wrong with the WSDL for the original users's environment is that the URL is wrong then it is perfectly legitimate to modify the URL directly.
Upvotes: 1
Reputation: 2015
The initial response is correct. The default URL in the WSDL is dependent upon the URL used to access the WSDL.
The way my team handled changing service URLs in the past (for instance, transitioning from a development to a testing or production environment) is to use wsdl.exe to generate a code proxy for your web service (a proxy is actually created by making a web or service reference as well, but is not displayed in Visual Studio by default), you can edit the generated proxy class to read the service's URL from (??) wherever you want to store it - database, config file etc.
Upvotes: 0
Reputation: 1245
The address is taken from the URL used to access the WSDL. If it's different than the server you want to actually serve from, then you could change it by creating a class that extends SoapExtensionReflector. Here's a sample article on how to change the URL:
http://blogs.msdn.com/kaevans/archive/2005/11/16/493496.aspx
Upvotes: 4