WCF service versioning with single SVC - wcf

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?

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

Related

Asp.NET Core 2.2 WCF Warning: Policy

I'm trying to add wsdl using WCF. But at first I get an warning like this;
enter image description here
Here is the details:
The following Policy Assertions were not Imported:
XPath://wsdl:definitions[#targetNamespace='urn:sap-com:document:sap:soap:functions:mc-style']/wsdl:binding[#name='zz_binding_SOAP12']
Assertions:
<saptrnbnd:OptimizedXMLTransfer xmlns:saptrnbnd='http://www.sap.com/webas/710/soap/features/transportbinding/'>..</saptrnbnd:OptimizedXMLTransfer>
<sapattahnd:Enabled xmlns:sapattahnd='http://www.sap.com/710/features/attachment/'>..</sapattahnd:Enabled>
The following Policy Assertions were not Imported:
XPath://wsdl:definitions[#targetNamespace='urn:sap-com:document:sap:soap:functions:mc-style']/wsdl:binding[#name='zz_binding']
Assertions:
<saptrnbnd:OptimizedXMLTransfer xmlns:saptrnbnd='http://www.sap.com/webas/710/soap/features/transportbinding/'>..</saptrnbnd:OptimizedXMLTransfer>
<sapattahnd:Enabled xmlns:sapattahnd='http://www.sap.com/710/features/attachment/'>..</sapattahnd:Enabled>
The optional WSDL extension element 'Policy' from namespace 'http://schemas.xmlsoap.org/ws/2004/09/policy' was not handled.
XPath: //wsdl:definitions[#targetNamespace='urn:sap-com:document:sap:soap:functions:mc-style']/wsdl:portType[#name='zz_test_web_structure']/wsdl:operation[#name='ZzTestWebService']
The optional WSDL extension element 'Policy' from namespace 'http://schemas.xmlsoap.org/ws/2004/09/policy' was not handled.
XPath: //wsdl:definitions[#targetNamespace='urn:sap-com:document:sap:soap:functions:mc-style']/wsdl:portType[#name='zz_test_web_structure']
I still can't run the wcf service after adding it. Does anyone know about this?
Microsoft WCF Web Service Reference Provider tool based on the Mex service endpoint, namely metadata exchange service endpoint instead of the Web service definition language(WSDL page).
<services>
<service name="WcfService1.Service1">
<endpoint address="" binding="basicHttpBinding" contract="WcfService1.IService1" bindingConfiguration="mybinding"></endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"></endpoint>
</service>
</services>
Or,
Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding();
sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");
If you prefer to generate a client proxy class by using WSDL, you could try the SVCUtil.exe tool.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/servicemodel-metadata-utility-tool-svcutil-exe
All the above ways can generate a client proxy class.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/accessing-services-using-a-wcf-client
Besides, In WCF4.5 there is a new feature called SingleWSDL, which contains the whole WSDL with the related schema. It could be consumed perfectly by a third-party system.
What is the difference between ?wsdl and ?singleWsdl parameters
https://learn.microsoft.com/en-us/dotnet/framework/wcf/whats-new
Feel free to let me know if there is anything I can help with.

two endpoint within one service host

I have 3 projects in a solution as following:
WCF Service Library "ServiceLib"(contract ICalculator and its implementation Calculator1).
Console Application "ServiceHost" to host WCF Service Library(and another ICalculator implementation Calculator2);
add Calculator1 & Calculator2 into an instance of ServiceHost using method AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "Calculator1"),
AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "Calculator2")
Add Service Reference to "ServiceHost" to my client application(type of Console Application);
an app.config(auto-generated) within this project
question is: How to consume these two Calculators(different logic) from client app side, does it necessary to create two different types of client proxy or other way to do that?
thanks for your hand!
<endpoint address="http://localhost:8000/Calculator" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_ICalculator" contract="Services_BaseAddress.ICalculator"
name="WSHttpBinding_ICalculator">
</endpoint>
<endpoint address="http://localhost:8000/DoubleCalculator" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_ICalculator1" contract="Services_BaseAddress.ICalculator"
name="WSHttpBinding_ICalculator1">
</endpoint>

How can I programmatically create an endpoint and use it in my service instead of obtain it from the web.config?

Basically I want to create this binding that will listen to azure service bus queue:
<services>
<service name="myServiceName">
<endpoint address="sb://****.servicebus.windows.net"
listenUri="sb://****.servicebus.windows.net"
binding="netMessagingBinding"
bindingConfiguration="netMessagingBinding"
behaviorConfiguration="myConfiguration"
name="myServiceEndpoint"
contract="****" />
</service>
I also need to know how I can use it in my service.
Look at your servicehost file (.SVC) it can contain a reference to the factory class that generates your service file. More info here: http://msdn.microsoft.com/en-us/library/aa967286.aspx
By providing your own factory you get an ability to override the generation of your service class via CreateServiceHost method. That will give you more control as to how your service class is created. You can inject your own URL's,l etc.
HTH

Content Type text/xml; charset=utf-8 was not supported by service

I have a problem with a WCF service.
I have a console application and I need to consume the service without using app.config, so I had to set the endpoint, etc. by code.
I do have a service reference to the svc, but I can't use the app.config.
Here's my code:
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http://localhost:8731/WcfServicio/MiServicio");
MiServicioClient svc = new MiServicioClient(binding, address);
object ob = svc.PaisesObtener();
At the last line when I do svc.PaisesObtener() I get the error:
Content Type text/xml; charset=utf-8 was not supported by service
http://localhost:8731/WcfServicio/MiServicio. The client and service bindings may be mismatched.
First Google hit says:
this is usually a mismatch in the client/server bindings, where the message version in the service uses SOAP 1.2 (which expects application/soap+xml) and the version in the client uses SOAP 1.1 (which sends text/xml). WSHttpBinding uses SOAP 1.2, BasicHttpBinding uses SOAP 1.1.
It usually seems to be a wsHttpBinding on one side and a basicHttpBinding on the other.
Do not forget check the bindings-related code too.
So if you wrote:
BasicHttpBinding binding = new BasicHttpBinding();
Be sure that all your app.config files contains
<endpoint address="..."
binding="basicHttpBinding" ...
not the
<endpoint address="..."
binding="wsHttpBinding" ...
or so.
I've seen this behavior today when the
<service name="A.B.C.D" behaviorConfiguration="returnFaults">
<endpoint contract="A.B.C.ID" binding="basicHttpBinding" address=""/>
</service>
was missing from the web.config. The service.svc file was there and got served. It took a while to realize that the problem was not in the binding configuration it self...
I saw this problem today when trying to create a WCF service proxy, both using VS2010 and svcutil.
Everything I'm doing is with basicHttpBinding (so no issue with wsHttpBinding).
For the first time in my recollection MSDN actually provided me with the solution, at the following link How to: Publish Metadata for a Service Using a Configuration File. The line I needed to change was inside the behavior element inside the MEX service behavior element inside my service app.config file. I changed it from
<serviceMetadata httpGetEnabled="true"/>
to
<serviceMetadata httpGetEnabled="true" policyVersion="Policy15"/>
and like magic the error went away and I was able to create the service proxy. Note that there is a corresponding MSDN entry for using code instead of a config file: How to: Publish Metadata for a Service Using Code.
(Of course, Policy15 - how could I possibly have overlooked that???)
One more "gotcha": my service needs to expose 3 different endpoints, each supporting a different contract. For each proxy that I needed to build, I had to comment out the other 2 endpoints, otherwise svcutil would complain that it could not resolve the base URL address.
I was facing the similar issue when using the Channel Factory. it was actually due to wrong Contract specified in the endpoint.
For anyone who lands here by searching:
content type 'application/json; charset=utf-8' was not the expected type 'text/xml; charset=utf-8
or some subset of that error:
A similar error was caused in my case by building and running a service without proper attributes. I got this error message when I tried to update the service reference in my client application. It was resolved when I correctly applied [DataContract] and [DataMember] attributes to my custom classes.
This would most likely be applicable if your service was set up and working and then it broke after you edited it.
I was also facing the same problem recently. after struggling a couple of hours,finally a solution came out by addition to
Factory="System.ServiceModel.Activation.WebServiceHostFactory"
to your SVC markup file. e.g.
ServiceHost Language="C#" Debug="true" Service="QuiznetOnline.Web.UI.WebServices.LogService"
Factory="System.ServiceModel.Activation.WebServiceHostFactory"
and now you can compile & run your application successfully.
Again, I stress that namespace, svc name and contract must be correctly specified in web.config file:
<service name="NAMESPACE.SvcFileName">
<endpoint contract="NAMESPACE.IContractName" />
</service>
Example:
<service name="MyNameSpace.FileService">
<endpoint contract="MyNameSpace.IFileService" />
</service>
(Unrelevant tags ommited in these samples)
In my case, I had to specify messageEncoding to Mtom in app.config of the client application like that:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="IntegrationServiceSoap" messageEncoding="Mtom"/>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:29495/IntegrationService.asmx"
binding="basicHttpBinding" bindingConfiguration="IntegrationServiceSoap"
contract="IntegrationService.IntegrationServiceSoap" name="IntegrationServiceSoap" />
</client>
</system.serviceModel>
</configuration>
Both my client and server use basicHttpBinding.
I hope this helps the others :)
I had this error and all the configurations mentioned above were correct however I was still getting "The client and service bindings may be mismatched" error.
What resolved my error, was matching the messageEncoding attribute values in the following node of service and client config files. They were different in mine, service was Text and client Mtom. Changing service to Mtom to match client's, resolved the issue.
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMySevice" ... messageEncoding="Mtom">
...
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
I had this problem in .net 6.0
The problem was the Soap Version, the BasicHttpBinding targets Soap 1.1 by default, but the service uses Soap 1.2.
The solution was to create a custom binding that targets Soap 1.2:
private Binding GetBindingConfiguration()
{
var textBindingElement = new TextMessageEncodingBindingElement()
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None)
};
var httpsBindingElement = new HttpsTransportBindingElement()
{
MaxReceivedMessageSize = int.MaxValue,
RequireClientCertificate = true //my service require certificate
};
return new CustomBinding(textBindingElement, httpsBindingElement);
}
var binding = GetBindingConfiguration();
var address = new EndpointAddress("https://nfe.sefa.pr.gov.br/nfe/NFeAutorizacao4"); //Brazil NF-e endpoint that I had to consume.
var svc = new MyService(binding, address);
//my service requires certificate
svc.ClientCredentials.ClientCertificate.Certificate = certificado;
object ob = svc.PaisesObtener(); //call the method

WCF - same service on different IIS .svc endpoints with multiple interfaces

I am trying to achieve the following:
Have one 'full' set of services for consumption by internal apps
Expose a subset of these methods to 3rd parties
The way I have tried to go about this is to create one service that implements two interfaces
For example:
Public Service Interface
[ServiceContract(Namespace = "http://www.myurl.com/public/2011/10")]
public partial interface IPublicService
{
[OperationContract]
ResponseObjOne OperationAvailableToEveryone(RequestObjOne request);
}
Private Service Interface
[ServiceContract(Namespace = "http://www.myurl.com/private/2011/10")]
public partial interface IPrivateService
{
[OperationContract]
ResponseObjOne OperationAvailableToEveryone(RequestObjOne request);
[OperationContract]
ResponseObjTwo OperationAvailableInternally(RequestObjTwo request);
}
Service class to implement both interfaces
public class Service : IPrivateService, IPublicService
{
ResponseObjOne OperationAvailableToEveryone(RequestObjOne request)
{ }
ResponseObjTwo OperationAvailableInternally(RequestObjTwo request)
{ }
}
I would now like to be able to configure this to run as two separate endpoints in IIS. So I have an .svc file with the following:
<%# ServiceHost Language="C#" Debug="true" Service="Adactus.Pulse.SOAServices.Service, Adactus.Pulse.SOAServices" %>
And added the following in the web.config:
<service name="Service">
<endpoint address="/public" binding="basicHttpBinding" contract="IPublicService" />
<endpoint address="/private" binding="basicHttpBinding" contract="IPrivateService" />
</service>
But if I browse to the .svc file I now see all operations in the WSDL and if I add /public to the URL I see a 404. So how can I achieve this?
Ideally I would like to add another .svc endpoint and be able to specify the interface as well as the service implementation class in these svc files. Then I can lock down access to the svc in IIS to secure the internal service.
the key is that some of the operations are exposed in both contracts and I don't want to duplicate their implementation.
Any ideas? Am I going about this in the wrong way?
Cheers,
Rob
While it doesn't answer your question, I would definitely not design it this way. I would create a single class library that includes both interfaces and the implementations for them and then I would create separate WCF projects that expose the different interfaces.
Observations: Your Service class to implement both interfaces seems wrong. both interfaces have same method name OperationAvailableToEveryone infact you have to implement your interfaces explicitly.
I even have same query. Infact you cannnot browse with http://localhost:8001/service.svc/public instead http://localhost:8001/public/service.svc. still you can create proxy with http://localhost:8001/service.svc and you use it as normal and your client enpoint address looks like
</client>
<endpoint address="http://localhost:8001/SOAService.svc/public"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IPublicService"
contract="SOAService.IPublicService" name="BasicHttpBinding_IPublicService" />
<endpoint address="http://localhost:8001/SOAService.svc/private"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IPrivateService"
contract="SOAService.IPrivateService" name="BasicHttpBinding_IPrivateService" />
</client>
Hope this helps.