Reputation: 4906
I have a WCF service with custom binding, hosted in IIS (IIS Express in development) with following service contract:
[ServiceContract]
public interface IServer
{
[OperationContract]
StreamCollection GetStreams(Guid poolKey);
[OperationContract]
PoolCollection GetPools();
[OperationContract]
StreamEntity GetStream(Guid poolKey, string localIndex);
}
It works OK (from client and also I can see it's metadata discovered ok in WCFTestClient).
I have to expose its functionality as REST, so I created a new contract as below
[ServiceContract]
public interface IRestServer
{
[OperationContract(Name="GetStreamsREST")]
[WebGet(UriTemplate = "pool/{poolKey}/streams")]
StreamCollection GetStreams(string poolKey);
[OperationContract(Name = "GetPoolsREST")]
[WebGet(UriTemplate = "pools")]
PoolCollection GetPools();
[OperationContract(Name = "GetStreamREST")]
[WebGet(UriTemplate = "pool/{poolKey}/stream/{localIndex}")]
StreamEntity GetStream(string poolKey, string localIndex);
}
I have both interfaces implemented in the same service class. The web.config file is
<behaviors>
<endpointBehaviors>
<behavior name="webHttp">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="CustomBinding">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="655360" />
</binding>
</customBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="MyServ.Server.Server">
<endpoint address="" binding="customBinding" bindingConfiguration="CustomBinding" contract="MyServ.Server.IServer" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<endpoint address="rest" behaviorConfiguration="webHttp" binding="webHttpBinding" contract="MyServ.Server.IRestServer" />
</service>
</services>
However, when I browse to access the service using rest, witha url like
http://localhost:<myport>/Service.svc/pools
http://localhost:<myport>/Service.svc/pool/somekey/streams
http://localhost:<myport>/Service.svc/pool/somekey/streams
I get error 404.
I put a break-point in some methods and attached debugger to IIS process, but it seems nothing gets called.
If I check the service metadata with WCFTestClient, it just sees IService, but not IRestService. Is this normal? EDIT: Yes, it seems it is (check this)
Thanks for any suggestion.
Upvotes: 1
Views: 2327
Reputation: 4906
Thanks all for all suggestions. However, I solved the issue finally.
The problem is I don't know still what was the problem, but I decided to take a different and more "clean" way.
So what I did was to create a different service SVC file, RestServer, where I implemented the REST methods
And I modified the settings in web config to have two different services, one for original one (pure WCF) and one for REST one, as below
<service name="MyServ.Server.RestServer" >
<endpoint address="" name="RESTEndpoint" behaviorConfiguration="webHttp" binding="webHttpBinding" contract="MyServ.Server.IRestServer" />
</service>
And this did the trick.
Actually, I should use this approach from the very beginning, to comply with single responsability principle ...
Upvotes: 1
Reputation: 3054
Are you able to post your code on how you are calling the WCF service? I had a similar problem the other day where the client app was calling the page with a HTTP POST instead of a HTTP GET, and thus getting a 404 error.
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json, UriTemplate = "/GuessWhat")]
vs
[WebGet(UriTemplate = "/GuessWhat/{variable}", ResponseFormat = WebMessageFormat.Json)]
Im not sure if your service has this or not but make sure the service that is implementing your Service Contract has this attribute.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
Upvotes: 1
Reputation: 87308
REST endpoints do not expose metadata in a way which can be consumed by the WCFTestClient, which explains why you can't access it. And the address you're browsing is incorrect, since you specified the endpoint address for the REST endpoint as "rest", you need to access them in something like
http://localhost:port/Service.svc/rest/pool/myPoolKey/streams
http://localhost:port/Service.svc/rest/pools
http://localhost:port/Service.svc/rest/myPoolKey/stream/1
Another thing: the Name
attribute in the [OperationContract]
attribute doesn't matter for REST endpoints, so you can drop it (it doesn't hurt having it there, though). Also, if you're using .NET 4.0, you don't even need the [OperationContract]
attribute at all, given that you already have [WebGet]
, so your interface can be defined as
[ServiceContract]
public interface IRestServer
{
[WebGet(UriTemplate = "pool/{poolKey}/streams")]
StreamCollection GetStreams(string poolKey);
[WebGet(UriTemplate = "pools")]
PoolCollection GetPools();
[WebGet(UriTemplate = "pool/{poolKey}/stream/{localIndex}")]
StreamEntity GetStream(string poolKey, string localIndex);
}
Upvotes: 2