Migrating a WCF application from SOAP to REST - wcf

I have a WCF application that is currently running in SOAP configuration, and I need to convert it to REST.
In theory, I have it working, but when I call the RST API using curl, I get an error:
curl -v http://localhost:8853/ClearCore/SecMyPermissions
The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
The bit where it says "Action '' cannot be processed" suggest to me that I've got the configuration wrong in such a way that it's not recognising the function name is being passed in.
C++ Code
[ServiceContract]
[Guid("5098109F-DB33-44e6-87B8-1929C879515B")]
public interface class IClearCoreSoap
{
[OperationContract]
[FaultContract(Exception::typeid)]
virtual List<System::String^>^ SecMyPermissions();
}
[ServiceBehavior(IncludeExceptionDetailInFaults = true, ConcurrencyMode = ConcurrencyMode::Multiple,
InstanceContextMode=InstanceContextMode::PerCall,
AddressFilterMode = AddressFilterMode::Any)]
public ref class ClearCoreSoap : IClearCoreSoap
{
public:
virtual List<System::String^>^ SecMyPermissions();
}
System::ServiceModel::ServiceHost^ pServiceHost = gcnew System::ServiceModel::ServiceHost(ClearCoreSoap::typeid);
pServiceHost->Open();
WCF binding
<configuration>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding maxReceivedMessageSize="1000000" name="NoSecurity">
<readerQuotas maxDepth="1000000" maxStringContentLength="65535"/>
</binding>
<binding maxBufferSize="1000000" maxReceivedMessageSize="1000000" name="BasicSecurity">
<readerQuotas maxDepth="1000000" maxStringContentLength="65535"/>
<security mode="Transport"/>
</binding>
</webHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="webHttpBehavior" name="soapcon.ClearCoreSoap">
<endpoint address="http://localhost:8853/ClearCore" binding="webHttpBinding" bindingConfiguration="NoSecurity" contract="soapcon.IClearCoreSoap" name="ClearCore"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8853/ClearCore"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="webHttpBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/>
<serviceCredentials type="System.ServiceModel.Description.ServiceCredentials">
<clientCertificate>
<authentication certificateValidationMode="None"/>
</clientCertificate>
<userNameAuthentication customUserNamePasswordValidatorType="soapcon.ADRetry_Validator, server_console_d" userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

A "ContractFilter mismatch at the EndpointDispatcher" means the receiver could not process the message because it did not match any of the contracts the receiver has configured for the endpoint which received the message.
This can be because:
You have different contracts between client and sender.
You're using a different binding between client and sender.
The message security settings are not consistent between client and
sender.
You can refer to this thread to solve the problem.
Based on the code you provided, you can try the following:
<endpoint address="http://localhost:8853/ClearCore" binding="webHttpBinding" bindingConfiguration="NoSecurity" contract="soapcon.IClearCoreSoap" name="ClearCore"/>
Try calling http://localhost:8853/ClearCore
Add behaviour configuration in <endpoint address /> tag

Related

Invoking WCF service in browser similar to asmx

I have made a WCF service in NET 4.0 and it returns the XML, I have tested it using SoapUI and i can see the required response xml. But my WCF service would be called by 3rd party software and they want to use it through a URL like asmx. I have googled and found that i need to make using REST guidelines. However i have not found a proper link showing making web-service using REST and then accessing the method from the browwer similar to web services.
Below is the interface code which i have used to return the format in XML
public interface IService1
{
[WebGet(
UriTemplate = "/GetDocument/",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Xml)]
[OperationContract, XmlSerializerFormat]
XmlElement GetDocument();
// TODO: Add your service operations here
}
Below is my config settings.
<system.serviceModel>
<services>
<service name="BritishLandXML.BritishLandXML1" behaviorConfiguration="metadataBehavior">
<endpoint address="" binding="basicHttpBinding" contract="BritishLandXML.IService1" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<webHttpBinding>
<binding>
<security mode="None"></security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="rest">
<webHttp helpEnabled="true" faultExceptionEnabled="true" automaticFormatSelectionEnabled="true" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
Please let me know how can i achieve this and what exact settings will be required.

Call HTTPS REST service from WCF

I need to call some REST services from a third parties server over HTTPS. My thinking was that I would create myself a nice little WCF library to handle these calls and deserialise the responses. I'm coming a tad unstuck though.
The services I am trying to call have a test service that simply responds OK.
I have created an OperationContract in my interface as shown below:
[OperationContract]
[WebGet(BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Xml,
UriTemplate = "test")]
string Test();
In my service code I have a public method below:
public string Test()
{
ChannelFactory<IService1> factory = new ChannelFactory<IService1>("UMS");
var proxy = factory.CreateChannel();
var response = proxy.Test();
((IDisposable)proxy).Dispose();
return (string)response;
}
My app.config looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<client>
<endpoint address="https://61.61.34.19/serv/ums/"
binding="webHttpBinding"
behaviorConfiguration="ums"
contract="WCFTest.IService1"
bindingConfiguration="webBinding"
name="UMS" />
</client>
<services>
<service name="WCFTest.Service1" behaviorConfiguration="WCFTest.Service1Behavior">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8731/Design_Time_Addresses/WCFTest/Service1/" />
</baseAddresses>
</host>
<endpoint address ="" binding="wsHttpBinding" contract="WCFTest.IService1">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="ums">
<clientCredentials>
<clientCertificate findValue="restapi.ext-ags.801"
storeLocation="CurrentUser"
x509FindType="FindBySubjectName"/>
</clientCredentials>
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="WCFTest.Service1Behavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate" proxyCredentialType="None"/>
</security>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
I try to invoke the test method but receive the error "Could not establish trust relationship for the SSL/TLS secure channel with authority '61.61.34.19'."
Can anyone see what I'm missing here?
Any help appreciated. Cheers.
Could not establish trust relationship for the SSL/TLS secure channel with authority '61.61.34.19'.
This typically means there's a problem with the server's SSL cert. Was it self-signed? If so, you have to establish trust for the cert, typically by trusting the issuing CA or installing the cert in the windows cert store.
Try changing the webHttpBinding security setting from "Transport" to "None".

Fail to send image ( byte[] ) as parameter of WCF service

I wrote some service that have method that get image ( byte[] ) as parameter ( return void ).
I also wrote some client (client & server run on same machien - different sulotion - using IIS )that send the bitmap ( as byte[] ) to the service - and each time i try to send i get the exception:
An error occurred while receiving the HTTP response to http://localhost/WebService/Service.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down)
I added one more method that get void and return int - and i can call this method with no problem.
What can be wrong ? Do i need to define something speciel in the client service reference ?
The service method
[ServiceContract]
**public interface IService**
{
[OperationContract]
void GetPic( byte[] pic );
}
**public class Service : IService**
{
public void GetPic( byte[] pic )
{
...
}
}
Web.config file:
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="ServiceProxy.Service">
<endpoint
name="basicHttp"
address=""
binding="basicHttpBinding"
bindingConfiguration=""
contract="Contracts.IService">
</endpoint>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" >
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8731/ServiceProxy/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
You must configure your binding on server to accept large messages. By default it accepts only messages up to 65KB and arrays with 16k elements = in your case bitmap which has size less then 16KB.
Use this in your web.config (server side):
<bindings>
<basicHttpBinding>
<binding name="myBinding" maxReceivedMessageSize="1000000">
<readerQuotas maxArrayLength="1000000" />
</binding>
</basicHttpBinding>
</bindings>
In your endpoint configuration reference this binding in bindingConfiguration attribute by setting it to myBinding.

AspNetCompatibilityRequirement error when hosting a WCF service with AppFabric Endpoint in SharePoint 2010

I am trying to host a WCF service within SharePoint 2010 with an AppFabric endpoint. I am using the basicHttpRelayBinding. When I host the service with a standard endpoint using the basicHttpBinding (not a service bus endpoint), the service works fine. However, as soon as I add the endpoint using the basicHttpRelayBinding, I receive the following error in the event log and the service does not register with the service bus.
WebHost failed to process a request.
Sender Information: System.ServiceModel.Activation.HostedHttpRequestAsyncResult/58154627
Exception: System.ServiceModel.ServiceActivationException: The service '/_vti_bin/FirstServiceFarmSolution/ListAccessService.svc' cannot be activated due to an exception during compilation. The exception message is: The ChannelDispatcher at 'sb://cliffwahl-trial.servicebus.windows.net/ListAccessService' with contract(s) '"IListAccessService"' is unable to open its IChannelListener.. ---> System.InvalidOperationException: The ChannelDispatcher at 'sb://cliffwahl-trial.servicebus.windows.net/ListAccessService' with contract(s) '"IListAccessService"' is unable to open its IChannelListener. ---> System.InvalidOperationException: The service cannot be activated because it does not support ASP.NET compatibility. ASP.NET compatibility is enabled for this application. Turn off ASP.NET compatibility mode in the web.config or add the AspNetCompatibilityRequirements attribute to the service type with RequirementsMode setting as 'Allowed' or 'Required'.
at System.ServiceModel.Activation.AspNetCompatibilityRequirementsAttribute.System.ServiceModel.Description.IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
I have tried the ws2007HttpRelayBinding and netTcpRelayBinding with the same behavior.
Here are the pertinent parts of code:
[ServiceContract]
public interface IListAccessService
{
[OperationContract]
List<Lead> GetLeads();
}
[BasicHttpBindingServiceMetadataExchangeEndpoint]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ListAccessService : IListAccessService
Service File:
<%# ServiceHost Debug="true"
Language="C#"
CodeBehind="ListAccessService.cs"
Service="FirstServiceFarmSolution.Code.ListAccessService, FirstServiceFarmSolution,Version=1.0.0.0,Culture=neutral,PublicKeyToken=625bdee8db8847ef" %>
Web Config:
<configuration>
<system.serviceModel>
<services>
<clear/>
<service name="FirstServiceFarmSolution.Code.ListAccessService"
behaviorConfiguration="ListAccessServiceBehavior">
<endpoint name="BasicHttpEndPoint"
address=""
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBindingConfig"
contract="FirstServiceFarmSolution.Code.IListAccessService">
<identity>
<dns value="sp2010" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<endpoint name="RelayEndPoint"
address="https://cliffwahl-trial.servicebus.windows.net/ListAccessService"
binding="basicHttpRelayBinding"
bindingConfiguration="HttpRelayBindingConfig"
behaviorConfiguration="sharedSecretClientCredentials"
contract="FirstServiceFarmSolution.Code.IListAccessService" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBindingConfig" />
</basicHttpBinding>
<basicHttpRelayBinding>
<binding name="HttpRelayBindingConfig">
<security relayClientAuthenticationType="None" mode="Transport"/>
</binding>
</basicHttpRelayBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ListAccessServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true" httpHelpPageEnabled="false" httpsHelpPageEnabled="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="sharedSecretClientCredentials">
<transportClientEndpointBehavior credentialType="SharedSecret">
<clientCredentials>
<sharedSecret issuerName="<my issuer name>" issuerSecret="<my issuer secret>"/>
</clientCredentials>
</transportClientEndpointBehavior>
<serviceRegistrySettings discoveryMode="Public" />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Does anyone see an issue with the setup or can someone point me to a SharePoint specific example of hosting a WCF service with a service bus endpoint?
Thanks,
Cliff

Configuring WCF JSONP and SOAP Endpoints Listening at the same URI

I JSONP enabled my WCF ServiceContract. Client is successfully calling the JSONP Service (OperationContract). I have a number of other OperationContracts (using the same ServiceContract) that I want to expose using basicHttpBinding (SOAP) endpoint - using the same URI. I think my Service WebConfig is set up correctly. When doing such a thing, should I be able to Add the Service Reference (proxy) using the VS "Add Service Reference" dialog window? Or do I need to manually generate client code in codebehind? If I need to manually do it, can anyone provide an example? Or is my Service WebConfig not configured correctly? I am calling the JSONP Service using this: http://Flixsit:1000/FlixsitWebServices.svc/jsonp
Thanks so much...
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="DefaultBehaviors">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="JSONPBinding" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
<basicHttpBinding>
<binding name="SOAPBinding" />
</basicHttpBinding>
</bindings>
<services>
<service name="Flixsit.Services.FlixsitWebServices" behaviorConfiguration="DefaultBehaviors">
<clear />
<endpoint name="JSONPEndPoint" address="jsonp"
binding="webHttpBinding"
bindingConfiguration="JSONPBinding"
contract="Flixsit.Services.IFlixsitWebServices"
behaviorConfiguration="webHttpBehavior" />
<endpoint name="HttpEndPoint" address=""
binding="basicHttpBinding"
bindingConfiguration="SOAPBinding"
contract="Flixsit.Services.IFlixsitWebServices" />
<host>
<baseAddresses>
<add baseAddress="http://Flixsit:1000/FlixsitWebServices.svc" />
</baseAddresses>
</host>
</service>
</services>
After tooling around for a while I am creating the ChannelFactory like below (in codebehind). Services are now exposed at both endpoints.
try
{
EndpointAddress address = new EndpointAddress("http://Flixsit:1000/FlixsitWebServices.svc");
WSHttpBinding binding = new WSHttpBinding();
ChannelFactory<IFlixsitWebServices> factory = new ChannelFactory<IFlixsitWebServices>(binding, address);
IFlixsitWebServices channel = factory.CreateChannel();
//call the service operation
var customer = channel.GetCustomers();
GridView1.DataSource = customer;
GridView1.DataBind();
//close the channel
((ICommunicationObject)channel).Close();
//close factory
factory.Close();
}
catch (Exception ex)
{
//log ex;
}