I've a WCF library with some functions I use from Powershell and C# clients. Now I would like to use a couple of util functions directly from a browser but I'm not sure how to do.
First I added a webHttpBinding endpoint in the Web.config file, here is a slice
<services>
<service name="MI_lib.MainService">
<endpoint name="basic" address="" binding="basicHttpBinding" bindingConfiguration="MI_lib_http" contract="MI_lib.InterfaceMainService"></endpoint>
<endpoint name="web" address="web" binding="webHttpBinding" bindingConfiguration="MI_lib_web" contract="MI_lib.InterfaceMainService"></endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="MI_lib_http" />
</basicHttpBinding>
<webHttpBinding>
<binding name="MI_lib_web" crossDomainScriptAccessEnabled="true">
<security mode="None"></security>
</binding>
</webHttpBinding>
</bindings>
A simple function define for test purposes is this
[OperationContract]
[WebGet]
string GetData(int value);
Then if I connect to http://localhost/MI_lib/MI_lib.MainService.svc/web I get the following fault message
<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
<Code>
<Value>Sender</Value>
<Subcode>
<Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:ActionNotSupported</Value>
</Subcode>
</Code>
<Reason>
<Text xml:lang="de-CH">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).</Text>
</Reason>
</Fault>
Any hint on what to check or which other information to provide?
To define a web endpoint, you need, in addition to using the webHttpBinding, to add a web http behavior to your endpoint, as shown below:
<services>
<service name="MI_lib.MainService">
<endpoint name="basic" address="" binding="basicHttpBinding" bindingConfiguration="MI_lib_http" contract="MI_lib.InterfaceMainService"></endpoint>
<endpoint name="web"
address="web"
binding="webHttpBinding"
bindingConfiguration="MI_lib_web" contract="MI_lib.InterfaceMainService"
behaviorConfiguration="MyWeb">
</endpoint>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="MI_lib_http" />
</basicHttpBinding>
<webHttpBinding>
<binding name="MI_lib_web" crossDomainScriptAccessEnabled="true">
<security mode="None"></security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="MyWeb">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
Also, the URL that you need to use also includes the method name, so you'll need to connect to
http://localhost/MI_lib/MI_lib.MainService.svc/web/GetData?value=123
Related
Assumption:
I'm working with a WCF application called DemoWCF, in which I have a simple wcf service called Calculator.
The purpose of the application is obviously a demo, the WCF service has to take two numbers as parameters and make the sum of them.
Service Class:
public class Calculator : ICalculator
{
public int Sum(int firstValue, int secondValue)
{
return firstValue + secondValue;
}
}
Service Contract :
[ServiceContract(Namespace="http://ROCKET/Calculator")]
public interface ICalculator
{
[OperationContract]
int Sum(int firstValue, int secondValue);
}
Web.config, service model configuration:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpsBinding">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="DemoWCF.Services.ServiceClasses.Calculator">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpsBinding" contract="DemoWCF.Services.ServiceContracts.ICalculator" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
When I deploy the WCF application on my IIS and I try to consume the WCF service in SOAP UI or in an ASP.NET MVC application, everything works fine.
Goal:
When I consume the WCF service in SOAP UI, I note that from the wsdl of the web service is automatically generated the binding "WSHttpBinding_ICalculator".
When I consume the WCF service in an ASP.NET MVC application, I note that the from the wsdl of the web service is automatically generated the service model, precisely:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ICalculator">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://rocket/ServiceClasses/Calculator.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICalculator" contract="Calculator.ICalculator" name="WSHttpBinding_ICalculator" />
</client>
</system.serviceModel>
What I want to do, is to rename the Service Name and the Binding Name of the WCF Service.
It's possibile to omit this WCF behavior of generating binding's name with the format : "BindingType_IServiceInterface" ?
What I have to do, if I want to rename my service name and binding name in "Calculator" ?
I have looked at several posts on SO which are showing how to add multiple endpoints for same service, but non of them is actually using HTTPS, which is why I am asking this question.
What I have
I have a web service,
https://portal.gov.com/us/216/_vti_bin/external/gov.svc
What I want
I want to call this web services using two different configurations, and bindings with different ENDPOINTS but SAME URL ?. (Sorry maybe I am confused with concept of EndPoints)
Here is what my web.config looks like,
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="Gov_ServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="restBehavior">
<webHttp defaultBodyStyle="Wrapped" defaultOutgoingResponseFormat="Json" automaticFormatSelectionEnabled="true" />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="Gov_webHttpBinding">
<security mode="Transport">
<transport clientCredentialType="InheritedFromHost" />
</security>
</binding>
</webHttpBinding>
<!--<basicHttpBinding>
<binding name="Gov_BasicHttpBinding">
<security mode="Transport">
<transport clientCredentialType="InheritedFromHost" />
</security>
</binding>
</basicHttpBinding>-->
</bindings>
<services>
<service name="Portal.WebServices.External.Gov" behaviorConfiguration="Gov_ServiceBehavior">
<endpoint address="" binding="webHttpBinding" behaviorConfiguration="restBehavior" contract="Portal.WebServices.External.IGov" bindingConfiguration="Gov_webHttpBinding"/>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
<!--<endpoint address="basic" binding="basicHttpBinding" contract="Portal.WebServices.External.IGov" bindingConfiguration="Gov_BasicHttpBinding"/>-->
</service>
</services>
</system.serviceModel>
</configuration>
WHERE IS THE PAIN
IT only works until I keep basicHttpBinding commented out and it's endpoint, as soon as I include it, I get silent error.
According to this - https://msdn.microsoft.com/en-us/library/ms751515(v=vs.110).aspx
It should work, but it doesn't maybe because I am using HTTPS and adding BINDINGS tag to my web.Config
What you are trying to achieve is impossible. You can't apply two different bindings with exactly the same Endpoint. If you try to read again your reference here it is clear that the sample has two different endpoints :
First address is http://localhost/servicemodelsamples/service.svc and the second
is http://localhost/servicemodelsamples/service.svc/secure. These two endpoints are different to each other but share with same contract.
The second endpoint is just relative to the base address http://localhost/servicemodelsamples/service.svc.
I hope this make your mind clear about binding and endpoint.
To put into context, I have a client application that will attempt to call a webservice that will be deployed on multiple web servers. The URI list will be obtained from the Settings.settings file of the client and a foreach loop will cycle through the URIs until the available service responds.
Let's say I have a service with the following contract:
[ServiceContract]
public interface ICMMSManagerService
{
[OperationContract]
ServerInfo GetServerInfo(string systemNumber);
}
In the web.config of the service's project, I have defined CMMSManager service with the the endpoint name: BasicHttpBinding_IWorkloadMngrService
<system.serviceModel>
<services>
<service name="WorkloadMngr">
<endpoint binding="basicHttpBinding" contract="IMetadataExchange" />
</service>
<service name="CMMSManager">
<endpoint binding="basicHttpBinding" contract="IMetadataExchange" name="BasicHttpBinding_IWorkloadMngrService" />
</service>
</services>
<client>
<remove contract="IMetadataExchange" name="sb" />
</client>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding>
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
On the client side, I have the following code executed when the application starts:
private void QueryWebServiceUrls()
{
var webServiceUrls = Properties.Settings.Default.WebServiceUrls;
foreach (var webServiceUrl in webServiceUrls)
{
try
{
var client = new CMMSManagerServiceClient("BasicHttpBinding_IWorkloadManagerService");
client.Endpoint.Address = new EndpointAddress(new Uri(webServiceUrl),
client.Endpoint.Address.Identity, client.Endpoint.Address.Headers);
client.Open();
var result = client.GetServerInfo("test");
}
catch (EndpointNotFoundException e)
{
continue;
}
catch (InvalidOperationException e)
{
break;
}
}
}
But the application crashes with an InvalidOperationException when the CMMSManagerServiceClient class is instanciated.
Could not find endpoint element with name
'BasicHttpBinding_IWorkloadMngrService' and contract
'ComClientService.ICMMSManagerService' in the ServiceModel client
configuration section. This might be because no configuration file was
found for your application, or because no endpoint element matching
this name could be found in the client element.
I have the following configuration in the app.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ICMMSManagerService">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/WorkloadMngr/CMMSManagerService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICMMSManagerService"
contract="ComClientService.ICMMSManagerService" name="BasicHttpBinding_ICMMSManagerService" />
</client>
</system.serviceModel>
I thought everything was valid by passing the BasicHttpBinding_ICMMSManagerService parameter to the CMMSManagerServiceClient class. I have no clue what am I missing at the moment... Any ideas?
The error is telling you exactly what's wrong: there is no endpoint with the name BasicHttpBinding_IWorkloadMngrService. The app.config says the endpoint is called BasicHttpBinding_ICMMSManagerService so your code should be:
var client = new CMMSManagerServiceClient("BasicHttpBinding_ICMMSManagerService");
Hope this helps.
Similar questions are flowing around and I looked at all of them. It appears none solve my issue.
-- UPDATE: --
I am trying to upload a document (pdf, doc, or whatever) to a database using WCF Service.
The call to the service looks like this:
using (var cw = new WCFClientWrapper<ICommonService>())
{
cw.Channel.DocumentInsert(content, filename, contentType);
}
Here is signature for the contract:
[OperationContract]
void DocumentInsert(byte[] content, string fileName, string contentType);
Please note that I am passing byte array for the content as this is what needs to be passed to store things in DB.
-- End of Update --
I can successfully upload a small file (couple kb). However, when I try to upload something larger (20kb), I get an Exception:
The formatter threw an exception while trying to deserialize the
message: Error in deserializing body of request message for operation
'DocumentInsert'. The maximum array length quota (16384) has been
exceeded while reading XML data. This quota may be increased by
changing the MaxArrayLength property on the XmlDictionaryReaderQuotas
object used when creating the XML reader. Line 1, position 31774.
The error seems to be obvious... just go and increase the MaxArrayLength. I have done that without any successful result. Below are the relevant parts from my web.configs
Client:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="SecureBehavior">
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="WSHttpBinding_Service" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="262144" messageEncoding="Text"
textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="2147483646" maxBytesPerRead="4096" maxNameTableCharCount="5242880" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://dev.svc.someurl.com/CommonService.svc"
binding="basicHttpBinding"
bindingConfiguration="WSHttpBinding_Service"
behaviorConfiguration="SecureBehavior"
contract="MyApp.Contracts.ServiceContracts.ICommonService"
name="MyApp.Contracts.ServiceContracts.ICommonService">
</endpoint>
</client>
</system.serviceModel>
Service:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 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>
<bindings>
<basicHttpBinding>
<binding name="MyBasicHttpBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="MyApp.WCFServices.CommonService">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="MyBasicHttpBinding"
contract="MyApp.Contracts.ServiceContracts.ICommonService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
<service name="MyApp.WCFServices.AccountService">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="MyBasicHttpBinding"
contract="MyApp.Contracts.ServiceContracts.IAccountService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Attaching diagnostics shows:
Construct Service: no errors/warnings
Open Service: warning - Configuration evaluation context not found - No matching tag was found. Default endpoints added.
Listen at 'http://dev.svc.someurl.com/CommonService.svc' : no
errors/warnings
Processing message 1 : no errors/warnings
Processing Action 'http://tempuri.org/ICommonService/DocumentInsert'.
: throws exception that I wrote at the very beginning.
Any help is appreciated.
I have came across with the same exception a few months ago. To send/receive large data to/from WCF service you have to set transferMode="Streamed". When use transfermode as Buffered, it actually puts the entire file in memory before uploading/downloading. Therefore a large buffer is required on both the web client and the WCF service host.Whereas Streamed transfers can improve the scalability of a service by eliminating the need for large memory buffers. For more information on transfermode, see the MSDN article on TransferMode Enumeration
All right, after a day of struggling I finally found an issue.
I just had to make sure that the name of the tag in WCF web.config matches the namespace and the name of the service:
<service name="ServicesImplementation.WcfServices.CommonService">
Unfortunately it was not something that you guys would see based on the information that I provided.
I am using VSTS 2008 + C# + .Net 3.0. I am using self-hosted WCF. When executing the following statement (host.Open()), there is the following binding not found error. I have posted my whole app.config file, any ideas what is wrong?
ServiceHost host = new ServiceHost(typeof(MyWCFService));
host.Open();
Error message,
The value of the property 'algorithmSuite' cannot be parsed. The error is: The value 'Aes128' is not a valid instance of type 'System.ServiceModel.Security.SecurityAlgorithmSuite'.
EDIT1: I have changed the algorithm suit option value to Default, but met with a new error when executing Open(), error message is, any ideas what is wrong,
Binding validation failed because the WSHttpBinding does not support reliable sessions over transport security (HTTPS). The channel factory or service host could not be opened. Use message security for secure reliable messaging over HTTP.
Full app.config,
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="MyBinding"
closeTimeout="00:00:10"
openTimeout="00:00:20"
receiveTimeout="00:00:30"
sendTimeout="00:00:40"
bypassProxyOnLocal="false"
transactionFlow="false"
hostNameComparisonMode="WeakWildcard"
maxReceivedMessageSize="100000000"
messageEncoding="Mtom"
proxyAddress="http://foo/bar"
textEncoding="utf-16"
useDefaultWebProxy="false">
<reliableSession
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Digest"
proxyCredentialType="None"
realm="someRealm" />
<message clientCredentialType="Windows"
negotiateServiceCredential="false"
algorithmSuite="Default"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="MyWCFService"
behaviorConfiguration="mexServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://localhost:9090/MyService"/>
</baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="MyBinding" contract="IMyService"/>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="mexServiceBehavior">
<serviceMetadata httpsGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>
thanks in advance,
George
You need to update your service behavior, too, if you change the MEX endpoint from http to https - you need to enable the httpsGetEnabled setting (not the httpGetEnabled):
<behaviors>
<serviceBehaviors>
<behavior name="mexServiceBehavior">
<serviceMetadata httpsGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
UPDATE:
George, check out this MSDN link - there is no "Aes128" algorithm - you must pick one of the existing ones.
UPDATE 2:
Can you try this config - reduce to the max! :-)
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="MyBinding"
maxReceivedMessageSize="100000000"
messageEncoding="Mtom"
proxyAddress="http://foo/bar"
textEncoding="utf-16"
useDefaultWebProxy="false">
<reliableSession enabled="false" />
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="MyWCFService"
behaviorConfiguration="mexServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://localhost:9090/MyService"/>
</baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="MyBinding" contract="IMyService"/>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="mexServiceBehavior">
<serviceMetadata httpsGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Can you start up your service,and can you add service reference from Visual Studio?
UPDATE 3:
George, I'd recommend you have a look at those security-related links and get some feel for what you really need and want - and how to achieve it.
WCF Security Guide
WCF Security Fundamentals
Fundamentals of WCF Security
MSDN Webcast Series "WCF Top To Bottom"
esp. Episode 10 - Security Fundamentals
Marc
The error message is correct, you don't get reliable messages over WSHttp, you need to use a custom binding and protocol.