How do I add TLS to a WCF service? - c#

I've been trying to add TLS to a WCF service, I've created.
Everything is OK until I try to access the service through https instead of http.
When adding the wcf service to the wcf test client, I get this:
Error: Cannot obtain Metadata from [THELINK] If this is a Windows (R)
Communication Foundation service to which you have access, please
check that you have enabled metadata publishing at the specified
address. For help enabling metadata publishing, please refer to the
MSDN documentation at [an MS link] Exchange Error URI: [THELINK]
Metadata contains a reference that cannot be resolved: '[THELINK]'.
There was no endpoint listening at [THELINK] that could accept the
message. This is often caused by an incorrect address or SOAP action.
See InnerException, if present, for more details. The remote server
returned an error: (403) Forbidden.HTTP GET Error URI: [THELINK]
There was an error downloading '[THELINK]'. The request failed with
HTTP status 403: Forbidden.
Sorry about the link replacing, but I'm new and I don't have the reputation, it seems :)
Regards,
Morten

do you have a
<behaviors>
<serviceBehaviors>
<behavior name="YourSerivceBehaviourName">
<serviceMetadata httpsGetEnabled="true" /> <-- this bit ?
...
...
being referenced by your
<service name="...." behaviorConfiguration="YourSerivceBehaviourName">
or a
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
in your web.config?
the Test client will also moan if the certificate isn't a real one I have found.. ie a self certed one for testing.
but the 403 seems to suggest that whatever credentials you are supplying are incorrect, what is the clientCredentialType set to in the SSL binding?
and what happens if you hit the link in a browser with customerrors off..
this might give you some more useful information

Related

wcf returning only html of metadata page

UPDATE: i have solved my issue:
the following config line needed removed:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
When i run the wcftestclient utility i get the following error and result from the services when invoking hello world. Any help is greatly appreciated. I cant seem to find the issue as to why it wont invoke the specific method and return the string for hello world.
Failed to invoke the service. Possible causes: The service is offline or inaccessible; the client-side configuration does not match the proxy; the existing proxy is invalid. Refer to the stack trace for more detail. You can try to recover by starting a new proxy, restoring to default configuration, or refreshing the service.

Can you mimic an existing service in WCF?

We have a 3rd party vendor service and an in-house service to communicate with it. Everything works perfectly with our in-house service, but I've been asked to write a fall back clone of our vendor's service. The intention is to be able to run up our clone, swap-out the client end-point and allow our in-house service to continue testing against the clone.
Is it possible to recreate/mimic a service such that an existing client can communicate with it (without modification) as if it were the original service?
So far I’ve tried 3 things and none of them work.
1st approach
Create a simple service, reference the 3rd party service to gain access to the custom types and mimic the [operation Contract]’s.
When I try to communicate with this service I get the following error.
A first chance exception of type 'System.ServiceModel.ActionNotSupportedException' occurred in System.ServiceModel.dll
Additional information: 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).
There is no security requirements as we are using basic http (no ssl). The service model portion of the config file and the service behaviour class attributes are below:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="SimpleBinding" />
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="cloneBehavior" name="MyClone">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="SimpleBinding"
contract="MyService.IMyService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/clone/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="cloneBehavior">
<serviceMetadata httpGetEnabled="True" httpGetUrl="http://localhost/clone/mex" />
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
and the service behaviour
[ServiceBehavior(Name = "CloneService",
ConfigurationName = "MyClone",
InstanceContextMode = InstanceContextMode.PerCall,
AddressFilterMode = AddressFilterMode.Any)]
public class MyService : IMyService
{
Everything looks good and I have come to my first dead end.
2nd approach
Get rid of my interface/service contract and inherit directly from the interface generated in the reference.cs file.
When I run this service up, I get the following error
System.InvalidOperationException: The operations myMethodA and myMethodB have the same action (). Every operation must have a unique action value.
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ActionDemuxer.Add(String action, DispatchOperationRuntime operation)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime..ctor(DispatchRuntime dispatch)
at System.ServiceModel.Dispatcher.DispatchRuntime.GetRuntimeCore()
at System.ServiceModel.Dispatcher.ChannelDispatcher.OnOpened()
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at Microsoft.Tools.SvcHost.ServiceHostHelper.OpenService(ServiceInfo info)
Taking a look at the generated interface for this method, they are all decorated with the following attribute:
[System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="*")]
My understanding from msdn is that WCF defaults to adding a unique action of the pattern <namespace>/<service>/<operation>[Response].
If I try setting the action to * then I can hit the service (as expected with the catch all / unmatched message handler), but I can't hit a specific method.
Nevertheless, manually making all the actions unique (and conforming to the above pattern), give this error:
The contract ‘IMyService’ in client configuration does not match the name in service contract, or there is no valid method in this contract.
…
I have clearly defined methods in the service contract and have come to a second dead end.
3rd approach
Using the wsdl.exe tool to generate a service from the wsdl. I followed the instructions from this SO post to generate an interface and inherit from it.
I’ve also tried generating the service itself by using the clientWsdl.wsdl /l:CS /server command and following the instructions in this post.
After tidying up the generated code and running it up, I’m back to my original error:
A first chance exception of type 'System.ServiceModel.ActionNotSupportedException' occurred in System.ServiceModel.dll
Additional information: 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).
At each attempt I have double checked all the config settings and updated the contract at each stage.
At this stage I'm wondering if it's even possible.
Were you ever able to mimic the service using WCF? I find myself in a similar situation where I've been tasked to write some integration tests where our method makes a call to a vendor's web service. I would have preferred to leverage Moq to write proper unit tests, but I'm constrained by 1) not being allowed to change the signature of the method that I'm testing, and 2) not really knowing anything about the web service itself except for what we send to the service and its expected response.
#jparram's suggestion was my next approach.
Note: I would have preferred to have posted this as a comment seeing that I'm not really answering your question.
If I understand your scenario, I would create wrapper service that decides which service to call. It sounds like that's what you want to do with Scenario 1. So, your client would always be calling your wrapper service, and your wrapper service would map the inputs to the required inputs of your 3rd party service or your back up service.
The error you received sounds like an issue in the generation of the proxy client where the "Action" is not getting mapped. Take a look at the generated proxy code from a known working configuration and compare it to what is in your scenario 1.
Edit
Compare the generated proxy client of your service and the 'real' service. The complaint about the Action = "" is probably due to the:
[System.ServiceModel.OperationContractAttribute(Action="", ReplyAction="")]
On your client not getting mapped to the corresponding operation.

Wcf ignore MaxItemsInObjectGraph value

Our WCF service has the following exception:
Maximum number of items that can be serialized or deserialized in an object graph is '32767'. Change the object graph or increase the MaxItemsInObjectGraph quota.
We change the config to:
<behavior name="large">
<dataContractSerializer maxItemsInObjectGraph="214783647"/>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
But no change.
In debug mode when the service host is open the value of the DataContractSerializer is 214783647 and the exception is still occur.
Changing the value programmaticly doesn't help.
Add an attribute of ServiceBehavior on the service doesn't help.
Change the machine.config like here - doesn't help.
Any ideas?
Thanks.
You may want to confirm that the error is not coming from the other side (client) of the transaction.
One way to verify, is to configure and enable WCF diagnostic event tracing and message logging, then rerun the test transaction and review the service trace log file. The following link demonstrates how to enable tracing and message logging.
http://msdn.microsoft.com/en-us/library/ms751526.aspx
Thanks to my college the problem solved with removing ReferencePreservingDataContractFormat attribute, we think it's because this attribute create it's own DataContractSerializer that ignore the configuration.
More details

WCF upload large images as wsHttpBinding

I've created a WCF Service to upload images. It works fine with images < 50KB or so but I get "The remote server returned an error: (400) Bad Request." with larger images.
I've been looking for ages and tried lots of different things, including setting the maxRequestLength and several other settings.
On the client-side of things the web.config is picking it up as a basicHttpBinding and I'm after a wsHttpBinding (for the more up-to-date feature-set). If I manually change the the binding type to wsHttpBinding and change the corresponding options, I get a Unsupported Media Type error.
Lookingin the WCF Test Client it shows the service as a basicHttpBinding too.
So my question is two-fold really.
What do I need to do to allow my service to handle files > 50KB?
What do I need to change for my service to be recognised as wsHttp instead of basicHttp?
Apologies if there is a question answering these - I have scoured stackoverflow and tried a few suggestions but it is possible I've missed it!
EDIT: As is always the way, I've managed to solve the wsHttpBinding issue now by fiddling around with the service web.config and manually changing the endpoint to wsHttpBinding. Still getting the large upload filesize issue though.
you will need to update your bindings in you web.config
e.g. this is how i did in my wcf restful service. i believe it will be very similar in your case as well
<bindings>
<webHttpBinding>
<!-- buffer: 64KB; max size: 64MB -->
<binding name="StreamedBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" transferMode="Streamed"
maxBufferPoolSize="67108864" maxBufferSize="65536" maxReceivedMessageSize="67108864">
</binding>
</webHttpBinding>
</bindings>
<service name="WCFRestFul.ApiRestful">
<endpoint address="" binding="webHttpBinding"
bindingConfiguration="StreamedBinding" bindingName="StreamedBinding"
contract="WCFRestFul.IApiRestful" behaviorConfiguration="web" />
</service>

WCF, IIS, and Endpoints

Learning WCF (I know, late to the party)
I am working through Juval Lowy's Programming WCF book. I see that I can configure multiple endpoints (including URI's) for my service.
However, when I host these in IIS, only the location of the .svc file seems to matter. Is the multiple endpoints/addresses thing only applicable if you are self-hosting? Am I missing something about hosting services in IIS?
"only the location of the .svc ", you're heading to this because baseaddress are provided by IIS in case of web-hosting (IIS hosting) unless you're using CustomServiceHostFactory. Then whatever value you provide in address, are appended to baseaddress (.svc/..)
You needs to give several host name in IIS for the the same WCF and set several endpoints in the client section of web.config as:
<client>
<endpoint address="hostname1/myservice.svc" ... />
<endpoint address="hostname2/myservice.svc" ... />
<endpoint address="hostname3/myservice.svc" ... />
</client>
Then you can consume them as:
hostname1/myservice.svc
hostname2/myservice.svc
hostname3/myservice.svc

Categories

Resources