1

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.

1

_vti_bin is a special folder since it's "virtualized" and can be called by any valid (but non-physical in IIS/ASP.NET sense) SP Web site.

ASP.NET .asmx infrastructure (that is responsible for the dynamic .wsdl generation) is not aware of this specific case, and relies on the physical underlying path http://server/_vti_bin/... in all cases.

However, this had been taken into account on the SharePoint side, but it requires some minor changes on the Web service side. This is rather old approaches (since .asmx is not really as hype as it was back in 2000s), but you can still find articles on this matter (they're mostly about SharePoint 2007 or even 2003 but should still be valid):

However, they target pure .asmx technologies, not Web services via WCF as in your case… you'll probably need to adapt some of the steps described in those articles.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.