I have build a custom web service I deployed within SharePoint (under _vti_bin
.
The code is :
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[BasicHttpBindingServiceMetadataExchangeEndpoint]
public class SimpleWebService : ISimpleWebService
{
public string WhereIAm()
{
return SPContext.Current.Web.Url;
}
}
[ServiceContract]
public interface ISimpleWebService
{
[OperationContract]
string WhereIAm();
}
And the svc file contains
<%@ServiceHost Language="C#"
Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressBasicHttpBindingServiceHostFactory, Microsoft.SharePoint.Client.ServerRuntime, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
Service="ReproIssue.Services.SimpleWebService, $SharePoint.Project.AssemblyFullName$" %>
As you can see, the result of the single method WhereIAm
is expected to be the url of the target site.
However, the root web (root of the web application) url is always returned, whatever the url is. Actually, the web service is called from a 3rd party app (I can't control the behavior of this app).
Digging the issue, I guess this is due to the WSDL generation.
Especially, when navigating to the WSDL in any site (using the url http://myserver/sites/mysite/_vti_bin/reproissue/simplewebservice.svc/mex for exemple) always returns http://myserver/_vti_bin/reproissue/simplewebservice.svc/mex (in the <soap:address location="http://myserver/_vti_bin/reproissue/simplewebservice.svc" />
section.
As a comparison, if I navigate to http://myserver/sites/mysite/_vti_bin/lists.asmx?wsdl
, I can clearly see this service exports correct urls in the wsdl.
I suspect the app to "follow" the url in the WSDL.
How to properly fix WSDL generation to actually target the site on which the WSDL is called ?
In order to tweak the exported url, I tried to implement a custom behavior :
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
internal sealed class MyAttribute : Attribute, IWsdlExportExtension, IContractBehavior
{
public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
{
Debug.WriteLine("x");
EndpointAddress address = context.Endpoint.Address;
Debug.WriteLine(address);
var newUri = new Uri(SPContext.Current.Web.Url.TrimEnd('/') + address.Uri.PathAndQuery);
context.Endpoint.Address = new EndpointAddress(
newUri,
address.Identity,
address.Headers,
address.GetReaderAtMetadata(),
address.GetReaderAtExtensions()
);
context.Endpoint.ListenUri = newUri;
}
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime) { }
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime) { }
public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context) { }
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) { }
}
Unfortunately, even though I can step into the code and check the endpoints URI are actually changed to the correct values, the exported WSDL still contains the old values (root web url based).
Thanks in advance.