WCF service versioning with single SVC

2019-08-29 23:35发布

问题:

Due to some certain requirement, I've got to use a single svc for multiple service versions. I've separated the interface contract for each version using different namespaces. I have only one class (partial) implementing all the service versions.

My code is as below:

namespace Application.V1
{
[ServiceContract(Namespace = "http://google.com/ApplicationService/v1.0", Name = "IMathService")]
public interface IMathService
}

namespace Application.V2
{
[ServiceContract(Namespace = "http://google.com/ApplicationService/v2.0", Name = "IMathService")]
public interface IMathService
}

The Application/MathServiceV1.cs file:

public partial class MathService : V1.IMathService { }

The Application/MathServiceV2.cs file:

public partial class MathService : V2.IMathService { }

The Application/MathService.cs file:

public partial class MathService {}

I've added the following in the service web.config:

  <service behaviorConfiguration="ServiceBehavior" name="Application.MathService">
    <endpoint address="V1" binding="wsHttpBinding" contract="Application.V1.IMathService" />
    <endpoint address="V2" binding="wsHttpBinding" contract="Application.V2.IMathService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>

I have a file MathService.svc with the following:

<%@ ServiceHost Service="Application.MathService, Application"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf"%>

If I generate a proxy with the address http://localhost:8000/MathService.svc the client endpoints are generated as below:

    <client>
        <endpoint address="http://localhost:8000/MathService.svc/V1"
            binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMathService"
            contract="MathService.IMathService" name="WSHttpBinding_IMathService">
        </endpoint>
        <endpoint address="http://localhost:8000/MathService.svc/V2"
            binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMathService1"
            contract="MathService.IMathService1" name="WSHttpBinding_IMathService1">
        </endpoint>
    </client>

My concern is that the client endpoint address is generated with MathService.svc/V1 but I'd like to see V1/MathService.svc.

If i browse the service with the address http://localhost:8000/MathService.svc/V1 i am getting HTTP 400 Bad Request error.

Any suggestions?

回答1:

Regarding your 400 bad request error - you probably dont have MEX enabled, so making a request without a payload makes no sense to the service.

Here is a question about enabling MEX: WCF How to enable metadata? Either enable MEX - or use a proper service consumer to call your service.

Regarding your addressing - you cannot do what you want to do with WCF alone. Because you are using IIS hosted WCF (I assume this because you are using an SVC file), your HTTP request must be directed to the location of your SVC file, and anything after that (/V1 for example) is used to locate the appropriate endpoint. This is just how it works in IIS. Putting the /v1/ BEFORE the file name (MathService.asmx) tells IIS to look for a folder called /v1/ before attempting to locate a file named MathService.asmx - obviously it wont find anything there!

However, you may be able to install a URL rewriter in your Web.config to redirect your preferred URI to the one mentioned above. Here is some documentation on Url rewriting in asp.net: http://www.iis.net/learn/extensions/url-rewrite-module/iis-url-rewriting-and-aspnet-routing