WCF: relativeAddress,baseAddress and binding - wcf

I am new in WCF and start my experience with a simple file-less application part of which (web.config) you can see below:
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
<serviceActivations>
<add
factory="System.ServiceModel.Activation.ServiceHostFactory"
relativeAddress="./RelativeAddress.svc"
service="WCF_Transactions.MyService1"/>
</serviceActivations>
</serviceHostingEnvironment>
Now I can access service at
http://localhost:18148/RelativeAddress.svc
Then I add next lines:
<services>
<service name="WCF_Transactions.MyService1" behaviorConfiguration="MyBehavior1">
<host>
<baseAddresses>
<add baseAddress="http://localhost:18148/" />
</baseAddresses>
</host>
<endpoint address="/RelativeAddressX.svc" binding="basicHttpBinding" contract="WCF_Transactions.IService1"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior1">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
So I expect that my service could be accessible through next address:
http://localhost:18148/RelativeAddressX.svc
but I can't do this. What have I misunderstood?

MSDN http://msdn.microsoft.com/en-us/library/ms733749.aspx:
*
There are two ways to specify endpoint addresses for a service in WCF.
You can specify an absolute address for each endpoint associated with
the service or you can provide a base address for the ServiceHost of a
service and then specify an address for each endpoint associated with
this service that is defined relative to this base address. You can
use each of these procedures to specify the endpoint addresses for a
service in either configuration or code. If you do not specify a
relative address, the service uses the base address.
*
So according to your example you have base adress
http://localhost:18148/
and it will be combined with RelativeAddress.svc, as a name of your svc file. And then it will try to combine this string with /RelativeAddressX.svc as a part of endpoint adress. So you will have something like
http://localhost:18148/RelativeAddress.svc/RelativeAddressX.svc.
Your endpoint must not specify the path to svc in IIS. It should containg only a logical adress, assosiated with this point.
So try to change your endpoint to the following:
<endpoint address="RelativeAddressX" binding="basicHttpBinding" contract="WCF_Transactions.IService1"></endpoint>
And it should be accessible by the path
http://localhost:18148/RelativeAddress.svc/RelativeAddressX

You don't need to specify in the config file when hosting in IIS or Cassini - the base URL is provided by the web server. The element is used when self-hosting. Cassini (VS build in web-server) will ignore it.
Here is a good page about WCF addressing:
http://msdn.microsoft.com/en-us/magazine/cc163412.aspx
Here are some related posts:
WCF Service Endpoints vs Host Base address
WCF, changing the baseAdress of an endpoint

Related

Is there way to convert just some service methods in a WCF to webMethods? Or add webmethods to an existing WCF? [duplicate]

Background
I have created ASMX web services in the past and have been able to access the service from the web browser and Ajax GET requests using the address convention: MyService.asmx/MyMethod?Param=xxx
I just got started using WCF and created a new web service in my ASP.NET project. It creates a file with the .svc extension such as MyService.svc.
Current Situation
I am able to consume the service using the WcfTestClient that comes with VS2008. I am also able to create my own WCF Client by either adding a service reference in another project or using the svcutil.exe commandline to generate the proxy and config file.
The Problem
When I try to use the service from a browser using MyService.svc/MyMethod?MyParam=xxx, I get a blank page without any errors.
What I have tried
I have already added a basicHttpBinding to the web.config and made it HttpGetEnabled in the behavior configuration. I also added the [WebGet(UriTemplate = "MyMethod?MyParam={MyParam}")] attribute to my operation contract.
I have already followed the information in this other stack overflow question:
REST / SOAP EndPoints for a WCF Service
However, I either get a blank page or an HTTP 404 Error after following those steps. There's nothing special about the code. I am just taking in a string as a parameter and returning "Hello xxx". This is a basic "Hello WCF World" proof-of-concept type thing.
UPDATE - Here's the relevant code
[ServiceContract]
public interface IMyService
{
[WebGet(UriTemplate = "MyMethod/MyParam={MyParam}")]
[OperationContract]
string MyMethod(string MyParam);
}
Web.Config - system.serviceModel Section
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyService">
<endpoint address=""
binding="wsHttpBinding" contract="IMyService" />
<endpoint address="MyService.svc"
binding="basicHttpBinding" contract="IMyService" />
<endpoint address="mex"
binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
Looking at your web.config serviceModel section, I can see that you need to add a webHttpBinding and associate an endPointBehavior that includes webHttpGet.
Your operation contract is correct. Here's how your system.serviceModel config section should look in order for you to be able to consume the service from a GET HTTP request.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyService">
<endpoint address="ws" binding="wsHttpBinding" contract="IMyService"/>
<endpoint address="" behaviorConfiguration="WebBehavior"
binding="webHttpBinding"
contract="IMyService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
Be sure to assign a different address to your wsHttpBinding endpoint, otherwise you will get an error saying that you have two endpoints listening on the same URI.
Another option is to leave the address blank in the wsHttpBinding, but assign a different address to the webHttpBinding service. However, that will change your GET address as well.
For example, if you assign the address as "asmx", you would call your service with the address "MyService.svc/asmx/MyMethod?MyParam=xxxx".
The normal WCF requests are always SOAP requests - you won't be able to get this going with just your browser, you'll need the WCF Testclient for that.
There is an add-on for WCF called the WCF REST Starter Kit (which will also be included in WCF 4.0 with .NET 4.0), which allows you to use GET/POST/PUT/DELETE HTTP commands to query WCF services and such. You need to write your services specifically for REST, though - you can't have SOAP and REST on the same service call.
Marc
As marc_s says, the REST Starter Kit can help, but you should also be aware that .NET 3.5 has support for REST services directly in it. It's not quite as complete as what you can do with the starter kit, but it is useful.
The way it works is that you put a [WebGet] attribute on your operations to indicate where in the URL the various parameters should come from:
[WebGet(UriTemplate = "helloworld/{name}")]
string Helloworld(string name);
See this portal for tons of information.
Note, you can have the same service exposed as both SOAP and REST if you specify multiple endpoints/bindings in the configuration.

Unable to access a service with absolute binding address

I am having a WCF Service Library. By default i am having a base address and i commented that out and added the complete address when specifying the end point address. Now when i try to access the wcf service through endpoint address i am not able to do that.
1.I created a WCF service library project in Visual Studio
2.By Default in the web.config we are having a base address for my service and my end point is having ""(relative address)
3.As per my understanding i am assuming that base address is not compulsory when we have complete address in EndPoint..Is my understanding correct?
3a. Now i removed my base address and added the complete url in the endpoint(please see attached config on what i did)
4.Now i tried to click on f5 in the visual studio solution then the default hosting screen came with an error.
5.Also i copied the complete url that i specified in the endpoint and pasted it in the web browser but i am getting 404 error..
6.Is it compulsory to have a base address to expose the service that was created using WCF Service library template??
So please let me know where i am committing the mistake. I am attaching my configuration.
</serviceHostingEnvironment>
<services>
<service name="WcfServiceLibrary1.Service1" behaviorConfiguration="WcfServiceLibrary.Service1Behavior">
<!--<host>
<baseAddresses>
<add baseAddress = "" />
</baseAddresses>
</host>-->
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="http://localhost:8732/Service2/pavan" binding="basicHttpBinding" contract="WcfServiceLibrary1.IService1">
</endpoint>
<!--<endpoint address="http://localhost:8732/Service2/mex" binding="mexHttpBinding" contract="IMetadataExchange"/>-->
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WcfServiceLibrary.Service1Behavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>

How config file would look at service end for multiple endpoint

i am working with wcf service application where svc file is created. now i want to design my service in such a way that people can connect to my service by http url and as well as by tcp url
so i would like to add three endpoint in my config one for wshttp, one for wsDualhttp and another one for tcp. so please someone give me sample config entry with 3 endpoints for wshttp, wsDualhttp and tcp.
in this case do i need to have three different mex endpoint for wshttp, wsDualhttp and tcp.
also tell me 3 url by which i can create proxy classes at client side. thanks
You could have something like this (assuming self-hosting, since only then can you really determine the full service addresses yourself - hosting in IIS, the service address(es) are most determined by where your .svc file lives):
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="YourNamespace.YourService" behaviorConfiguration="Default">
<endpoint name="Default"
address="http://YourServer/Services/MyService"
binding="basicHttpBinding"
contract="YourNamespace.IYourService"/>
<endpoint name="TCP"
address="net.tcp://YourServer/ServicesTCP/MyService"
binding="netTcpBinding"
contract="YourNamespace.IYourService"/>
<endpoint name="mex"
address="http://YourServer/Services/MyService/mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
<endpoint name="Dual"
address="http://YourServer/Services/MyService/Dual"
binding="wsDualHttpBinding"
clientBaseAddress="http://localhost:8001/client/"
contract="YourNamespace.IYourDualService"/>
</service>
</services>
</system.serviceModel>
This would define three endpoints:
a HTTP endpoint at http://YourServer/Services/MyService for your service
a HTTP MEX endpoint at http://YourServer/Services/MyService/mex for the metadata exchange (service discoverability)
a Net.TCP endpoint at net.tcp://YourServer/ServicesTCP/MyService for your service
You could of course also use two base addresses to make things a bit easier in the config:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="YourNamespace.YourService" behaviorConfiguration="Default">
<host>
<baseAddresses>
<add baseAddress="http://YourServer/Services"/>
<add baseAddress="net.tcp://YourServer/ServicesTCP"/>
</baseAddresses>
</host>
<endpoint name="Default"
address="MyService"
binding="basicHttpBinding"
contract="YourNamespace.IYourService"/>
<endpoint name="TCP"
address="MyService"
binding="netTcpBinding"
contract="YourNamespace.IYourService"/>
<endpoint name="mex"
address="MyService/mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
This would configure the equivalent service endpoints.
The wsDualHttpBinding is different in that it requires at least a clientBaseAddress for the callback mechanism (the WCF service will call back your client to send back e.g. status messages) - so it needs some extra tweaks and it cannot really be bolted onto an existing service that works over wsHttpBinding - it needs to be done separately. But basically - it's still pretty much all the same thing....
Update: after reading up on the topic (it's not something I use very often), it does appear that duplex communication is indeed possible also using netTcpBinding, but only if you're self-hosting your service - IIS doesn't support duplex communication over netTcpBinding.
Creating a duplex service does still require extra steps and extra code - so you cannot really have a service that's both non-duplex using basicHttpBinding or wsHttpBinding and duplex at the same time. So it really doesn't make sense to have another endpoint in this example using the wsDualHttpBinding because that service either needs to be really duplex (then you can use wsDualHttpBinding and netTcpBinding) - or it's not duplex - then you can use basicHttpBinding, wsHttpBinding, netTcpBinding and a few more "exotic" bindings (like MSMQ, named pipes etc.)

How to force a net.tcp mex endpoint (mexTcpBinding) to participate in port sharing?

I have a WCF service which is hosted as a Windows Service. We would like to enable a mex endpoint at the same address (but with a '/mex' suffix). I have been trying to do this (unsuccessfully) using the following configuration:
<system.serviceModel>
<services>
<service
name="MyCompany.MyService"
behaviorConfiguration="defaultServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost"/>
</baseAddresses>
</host>
<endpoint
address="MyService"
binding="netTcpBinding"
contract="MyCompany.IMyService"
bindingConfiguration="netTcpBindingConfig"
/>
<endpoint
address="MyService/mex"
binding="mexTcpBinding"
contract="IMetadataExchange"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="defaultServiceBehavior">
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="netTcpBindingConfig" portSharingEnabled="true" />
</netTcpBinding>
</bindings>
</system.serviceModel>
When it runs, the service host throws an AddressAlreadyInUseException complaining that "There is already a listener on IP endpoint 0.0.0.0:808". This actually makes sense to me because the port sharing service has opened that port in order to serve the MyService endpoint along with any other services requesting to share that port on this machine.
So it seems that the mex endpoint wants exlusive access to port 808. I can work around this by tweaking the mex endpoint like so:
<endpoint
address="net.tcp://localhost:818/MyService/mex"
binding="mexTcpBinding"
contract="IMetadataExchange"
/>
This means that the mex endpoint now has its own exclusive port. The downside with this is that any other service which wants to expose a mex endpoint will also need a unique port for its mex endpoint. This makes it very unpredictable when looking for mex endpoints.
Is there a way to force the mex endpoint to participate in port sharing?
Two options:
The easy way: Change the entire binding for the mex point to netTcpBinding and have it reuse your bindingConfiguration. mexTCPBinding is only meant to be a convenience and is optional. If its not working for you, don’t use it.
The hard way: You can modify the mexTCPBinding to enable sharing. The only example I’ve seen is in code here: Link

WCF base address not found

My service can work with normal WCF calls, but to expose metadata (the wsdl file) I have to change configuration in such a way the normal WCF host fails.
I've spend countless hours on google trying to solve this, big problem there is that hosting a service inside a website is never discussed (yes this is different).
requirements:
Runs in an existing web site
Use sessions
Operable with Java, and as much .net versions as possible.
Expose metadata (wsdl will be enough)
edits:
IIS cannot be used
I'm using .NET 4 and WCF 4.
In this configuration the metadata can be reached (through the wsdl file) but when trying to host the normal wcf endpoints I get and InvalidOperationException:
Could not find a base address that matches scheme http for the endpoint with binding WSHttpBinding. Registered base address schemes are [].
So the base address is ignored.
But when I supply full addresses to the endpoints (simply copy the base address in front of the current address) the normal WCF calls work fine, but when trying to access metadata I get the following error:
No protocol binding matches the given address 'http://localhost:8080/Functionality'.
Protocol bindings are configured at the Site level in IIS or WAS configuration.
Here is the web.config serviceModel section, I made a small test web site just for testing this, but it would be to much to post all of it here, if you send me a pm though I will e-mail it to you.
<system.serviceModel>
<services>
<service behaviorConfiguration="metadataSupport" name="MyStuff.TestWithMetadata">
<endpoint address="Functionality" binding="wsHttpBinding" name="FunctionalityBinding"
contract="MyStuff.ITestWithMetadata" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="metadataSupport">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="metadataSupport">
<!--Navigate with browser to httpGetUrl for the wsdl file-->
<serviceMetadata httpGetEnabled="true" httpGetUrl="Metadata" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false">
<serviceActivations>
<add relativeAddress="TestWithMetadata.svc" service="MyStuff.TestWithMetadata" />
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
If anyone has any ideas on how to solve this, please help out.
When you host your service in IIS (which I assume from your requirement "Runs in an existing web site"), then your base address in the config is moot - it will not be used at all.
When hosting in IIS, your service address is determined by:
your server name
possibly a port number
the virtual directory (and possibly subdirectories thereof) where the *.svc file lives
the *.svc file itself (including extension)
So it might be something like:
http://MyServer:7777/ExistingWebApp/TestWithMetadata.svc
or whatever it is that you have in your case.
You seem to be using .NET 4 and WCF 4 (never mentioned that.....) and in that case, you could skip the *.svc file altogether by adapting your config entry:
<serviceHostingEnvironment multipleSiteBindingsEnabled="false">
<serviceActivations>
<add relativeAddress="MyService" service="MyStuff.TestWithMetadata" />
</serviceActivations>
</serviceHostingEnvironment>
In this case, the value of relativeAddress= becomes the service address (within the virtual directory this web.config lives in) - so your service address would be something like:
http://MyServer:7777/ExistingWebApp/MyService
No need for a *.svc file at all in this situation.
Turned out I should use httpGetUrl link to get the metadata, instead of the .svc file, with that the base address can be ignored.
I also moved this test stuff to the actual web site and got tons of problems with zero endpoints being loaded. That was caused by the service reference in serviceActivations not set to the full service name (needs to have namespace included).
I accepted marc's answer because he did help me along and to prevent this question from popping up in unanswered.