Expose webHttpBinding endpoint in a WCF service - c#

I created a WCF service and exposed three endpoints which are basicHttpBinding, wsHttpBinding and webHttpBinding. This is a test service for my experiments with WCF. But, whenever I add service reference using the .svc file, I only get two (basic and ws) endpoints. There doesn't seem to be a third (webHttpBidning) endpoint being exposed for some reason.
To reproduce this issue, create a WCF application project, delete the Service1 service, add new item > WCF service named TestService, and change the config file to the following :
<system.serviceModel>
<services>
<service name="WcfTestService.TestService" behaviorConfiguration="TestServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost/WcfTestService/TestService.svc"/>
</baseAddresses>
</host>
<endpoint address="basic"
binding="basicHttpBinding"
contract="WcfTestService.ITestService" />
<endpoint address="ws"
binding="wsHttpBinding"
contract="WcfTestService.ITestService" />
<endpoint address="web"
binding="webHttpBinding"
contract="WcfTestService.ITestService" />
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TestServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
Here is the code for ITestService.cs:
[ServiceContract]
public interface ITestService
{
[OperationContract]
[WebInvoke]
Boolean ValidateUser(User user);
}
[DataContract]
public class User
{
[DataMember(Name = "Name")]
public String UserName { get; set; }
[DataMember]
public String Password { get; set; }
}
and for TestService.svc
public class TestService : ITestService
{
public bool ValidateUser(User user)
{
if (user.UserName == "User" && user.Password == "123")
{
return true;
}
return false;
}
}
I tried different combination of WebInvoke parameters and WebGet parameters, but failed.
Can anyone tell me why the third endpoint is not showing up in the WSDL file?

#decyclone: I have successfully exposed webHttpBindings without any issue. But I found some interesting thing when it get exposed and when it not!
I can see web binding getting exposed in Wcf Test Client.
Here are my configurations
<services>
<service behaviorConfiguration="TestWeb.Service2Behavior" name="TestWeb.Service2">
<endpoint address="" binding="wsHttpBinding" contract="TestWeb.Service2">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="web" binding="webHttpBinding" contract="TestWeb.Service2">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
Point to note here is, its working fine using VS2008 with Framework 3.5, VS2010 with Framework 3.5, when I use VS2010 and Framework 4.0 then I can't see WebHttpBinding getting exposed in WCF Test Client, however I can use that binidng to do http post in all cases.
I assume that in Framework 4.0 its not visible by default, even I try enable endpointDiscovery but still no luck!
I have covered this behaviour in my post

Your "web" endpoint will be exposed as a JSON endpoint. It is not compatible with WSDL.

WebHttpBinding is in System.ServiceModel.Web. If you are using vs2010, go to properties of your project, check target framework. By default it points to .Net Framework 4 Client Profile. It should point to .Net Framework 4, then you can find the System.ServiceModel.Web when you will go to Add reference

#decyclone: One way that a javascript client can learn the available methods on a webHttpBinding is to download a WCF javascript proxy with HTML script tags pointing to your endpoint followed by "/js": <script src="http://localhost/WcfTestService/TestService.svc/web/js"></script>

Related

Error adding wcf service to WCF Test Client - Service metadata cannot be accessible

I created a WCF Service and would like to test the one method I added using the WCF Test Client. When I originally created the method, it returned a DataTable. When I used the WCF Test Client to add the service, the service was added using the original app.config file. The method returning the DataTable showed an 'X' because I learned that you can't return this data type. So I created a class that contains the DataTable. The DataContract, Subject, is returned by the method. The code is below:
[ServiceContract]
public interface IPaging
{
[OperationContract]
Subject GetSubjectList(string strUserID);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
}
[DataContract]
public class Subject
{
DataTable dtSubjectData = new DataTable();
[DataMember]
public DataTable SubjectTable
{
get;
set;
}
}
The method details:
namespace PagingService
{
public class Paging : IPaging
{
Subject cSubject = new Subject();
public Subject GetSubjectList(string strUserID)
{
....
}
}
}
Now, when I try to add the service to the WCF Test Client, I get the error:
'Service metadata cannot be accessible.'
This is my app.config file:
<system.serviceModel>
<services>
<service name="PagingService.Paging" behaviorConfiguration="SimpleServiceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="PagingService.IPaging">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/PagingService/Service1/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SimpleServiceBehavior">
<serviceMetadata httpGetEnabled="True" />
<!-- 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="False" />
</behavior>
</serviceBehaviors>
It seems to me that it is not with the app.config file because the original entries worked when the method returned a DataTable. But now the return type is now 'Subject', it is not updated somewhere.
When you change the method signature, is there some other place that needs to be changed that I am missing?
Thanks.
Why don't you just serialize the DataTable and send it back as an XML string? On the client end you could create a DataTable on the client end by usinging DataTable.ReadXML.

WCF Project library

I want to migrate my WCF serivce from WebSite App_Code folder to project library.
As far as I know, WCF library is able to read web config about service model, so the only action I did was following:
1 - Create new project library and put all code about wcf from app_code to it.
2 - Modify web config in order to point at service class with full qualified name (namespace + class name)
3 - Modify svc file in order to point at service class instance with full qualifide name.
However, my service is not running anymore. I'm using ws-httpbinding with custom validator, but it seems my service expect a basic http binding.
The error I'm struggling with appears like this:
the request of message must be protected, such as required by a contract operation ('IMyService','http://tempuri.org/'). The protection must be implemented by ('BasicHttpBinding','http://tempuri.org/') binding.
##EDIT:
My Web.Config:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyWcfNamespaceOfMyDLL.MyCustomValidator" />
<serviceCertificate findValue="localhost" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="MyBinding" maxBufferPoolSize="1000000000" maxReceivedMessageSize="1000000000" messageEncoding="Mtom">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="MyBehavior" name="MyServiceName">
<endpoint address="" binding="wsHttpBinding" contract="MyWcfNamespaceOfMyDLL.IMyServiceName" bindingConfiguration="MyBinding">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>
This is my svc file inside web site root:
<%# ServiceHost Language="C#" Debug="true" Service="MyWcfNamespaceOfMyDLL.MyServiceName" %>
Finally, service contrat inside my dll appears like this:
[ServiceContract]
public interface IMyService
{
[OperationContract(ProtectionLevel=System.Net.Security.ProtectionLevel.EncryptAndSign)]
string DoSomething();
}
public class MyServiceName : IMyService
{
public string DoSomething();
}
public class MyValidator : UserNamePasswordValidator
{
// simple validation
}
Any idea?
I've solved.
The problem was about dll name missing on web config.
I had to change my config as following:
First:
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="="MyWcfNamespaceOfMyDLL.MyCustomValidator", MyDllName" />
Second:
<services>
<service behaviorConfiguration="MyBehavior"
name="MyWcfNamespaceOfMyDLL.MyServiceName">
<endpoint address="" binding="wsHttpBinding"
contract="IMyServiceName" bindingConfiguration="MyBinding">
<identity>
I think everyone could begin crazy..!!
Well, as you can see, I had to:
Specify DLL name on userNameAuthentication tag.
Specify namespace name on attribute name of service tag.
Remove specification about namespace name on contract attribute of endpoint tag.
Ok I 've solved, but I'm a bit worried for the next future ..!!
Are you sure that the problem comes from the service and not from the client ?
Can you show us how do you call this service ?
the request of message must be protected, such as required by a contract operation ('IMyService','http://tempuri.org/'). The
protection must be implemented by
('BasicHttpBinding','http://tempuri.org/') binding.
As said here,
If the binding does not support security (such as BasicHttpBinding),
the effective System.Net.Security.ProtectionLevel is
ProtectionLevel.None for the whole contract. The result is that
depending upon the endpoint binding, clients can require different
message or transport level security protection even when the contract
specifies ProtectionLevel.None.
This error message suggests you are calling the service with a basicHttpBinding with no ProtectionLevel.
Also, the contract in your Web.config IMyServiceName is not the same that in your code 'IMyService' or in the error message.

Service can't find endpoint of other service in WCF

I am trying to create two WCF services which should be able to access each other. However I am getting this error message:
The server encountered an error processing the request. The exception message is 'Could not find default endpoint element that references contract 'AddonWCFService.IService1' 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 contract could be found in the client element.'.
I call the Test() Method from this service
namespace CustomersService
{
[ServiceContract]
public interface ICustomers
{
[OperationContract]
[WebGet]
string Test();
}
public class Customers : ICustomers
{
private int m_i = 0;
public int GetCounter()
{
return m_i;
}
public void Test()
{
AddonWCFService.Service1Client foo = new AddonWCFService.Service1Client();
}
}
}
The other service
namespace AddonWCFWebservice
{
[ServiceContract]
public interface IService1
{
[OperationContract]
void Init();
}
public class Service1 : IService1
{
public void Init()
{
}
}
}
My webconfig:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="MyserviceBehavior" name="CustomersService.Customers">
<endpoint name="ws" address="ws" binding="wsHttpBinding" contract="CustomersService.ICustomers"/>
<endpoint name=""
address=""
binding="webHttpBinding"
contract="CustomersService.ICustomers"
behaviorConfiguration="WebBehavior"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<service name="AddonWCFWebservice.Service1" behaviorConfiguration="MyserviceBehavior">
<endpoint address="" binding="wsHttpBinding" contract="AddonWCFWebservice.IService1"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyserviceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
<customErrors mode="Off"/>
</system.web>
</configuration>
Both services reside in the same active directory of IIS . I added the service reference to the VS C# projects using the web URL i.e. http://www.foobar.baz/Test/Service1.svc and http://www.foobar.baz/Test/Customers.svc
It's probably something obvious but I'm fairly new to the whole WCF business. Thanks!
Update: The solution was to add a client section to my webconfig. Also I used basicHttpBinding over wsHttpBinding because my security will be incorparated elsewhere because it is a public service. I had to match the binding of the client to the binding of the service section: both basicHttpBinding
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<client>
<endpoint
name=""
address="http://demo.mydomain.baz/TestService/Service1.svc"
binding="basicHttpBinding"
contract="AddonWCFService.IService1" />
</client>
<services>
<service behaviorConfiguration="MyserviceBehavior" name="CustomersService.Customers">
<endpoint name="ws" address="ws" binding="wsHttpBinding" contract="CustomersService.ICustomers"/>
<endpoint name=""
address=""
binding="webHttpBinding"
contract="CustomersService.ICustomers"
behaviorConfiguration="WebBehavior"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<service name="AddonWCFWebservice.Service1" behaviorConfiguration="MyserviceBehavior">
<endpoint address="" binding="basicHttpBinding" contract="AddonWCFWebservice.IService1"/>
<!--
<endpoint address=""
binding="webHttpBinding"
contract="AddonWCFWebservice.IService1"
behaviorConfiguration="WebBehavior"/>
-->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyserviceBehavior">
<!-- 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>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
<customErrors mode="Off"/>
</system.web>
</configuration>
The problem with your config is that you have no client configurations. You have only server parts. You need to have client element with endpoints. Take a look here: http://msdn.microsoft.com/en-us/library/ms731745.aspx
If you are not so sure about you config skills I would advise you to open your config with SvcConfigEditor.exe. You will immediately see what's configured.
You can find it here: C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SvcConfigEditor.exe.
If you will do it - you will see that there are no clients configured
I think you specified the wrong service contract in your config file.
This line here:
<endpoint address="" binding="wsHttpBinding" contract="AddonWCFWebservice.IService1"/>
specifies the contract as "AddonWCFWebservice.IService1" when it should be something like "AddonService.IService1" (without the "WCF").

After creating a wcf service how do I tell whether its restful or soap from the wsdl?

I created a service and I'm presented with a page saying:
You have created a service.
To test this service, you will need to
create a client and use it to call the
service. You can do this using the
svcutil.exe tool from the command line
with the following syntax:
But how do I tell if its a SOAP or a REST service from that? How would I tell from the wsdl etc?
Service config:
<services>
<service name="VLSContentService"
behaviorConfiguration="VLSContentServiceBehaviour" >
<endpoint name="rest"
address=""
behaviorConfiguration="VLSContentServiceEndpointBehaviour"
binding="webHttpBinding"
contract="IVLSContentServiceREST" />
<endpoint name="soap"
address="soap"
binding="basicHttpBinding"
contract="IVLSContentServiceREST"/>
</service>
</services>
UPDATE:
Hi Mark,
My config is:
<services>
<service behaviorConfiguration="VLSContentServiceBehaviour" name="VLSContentService">
<endpoint name="rest" address="" behaviorConfiguration="VLSContentServiceEndpointBehaviour" binding="webHttpBinding" contract="IVLSContentServiceREST" />
<endpoint name="soap" address="soap" binding="basicHttpBinding" contract="IVLSContentServiceREST"/>
</service>
</services>
So basically I browse to the .svc file and I see a link for a wsdl. But how do I know if thats for the SOAP or REST endpoint. Have I even configured it correctly?
Thanks
UPDATE: 17:49 (UK TIME)
<system.serviceModel>
<!---Add the service-->
<services>
<service behaviorConfiguration="VLSContentServiceBehaviour" name="VLSContentService">
<endpoint name="rest"
address=""
behaviorConfiguration="VLSContentServiceEndpointBehaviour"
binding="webHttpBinding"
contract="IVLSContentServiceREST" />
</service>
</services>
<!---Add the behaviours-->
<behaviors>
<serviceBehaviors>
<behavior name="VLSContentServiceBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="VLSContentServiceEndpointBehaviour">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
</system.serviceModel>
marc_s UPDATE: 18:22 (UK TIME)
Pete, try this - no metadata publishing, nothing - just webHttpBinding - you should not see any WSDL anymore...
<system.serviceModel>
<services>
<service name="VLSContentService">
<endpoint name="rest"
address=""
binding="webHttpBinding"
contract="IVLSContentServiceREST" />
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
</system.serviceModel>
The service can be both REST and SOAP, in a way that a WCF service can have multiple endpoints, including a mix of both SOAP and REST. On the WSDL, the SOAP endpoints will show up in the wsdl:definitions/wsdl:service/wsdl:port element; the REST endpoints will not. So if you only have one endpoint in the service, if there is a wsdl:port entry in the WSDL, then it's a SOAP endpoint; otherwise it's REST.
You can run the code below and look at the wsdl to see that it only shows up one wsdl:port element, for the SOAP endpoint.
public class StackOverflow_6414181
{
[ServiceContract]
public interface ITest
{
[OperationContract]
[WebGet]
string Echo(string text);
}
public class Service : ITest
{
public string Echo(string text)
{
return text;
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "soap");
host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "rest").Behaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Host opened");
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
If you have a WSDL - it's a SOAP service.
REST doesn't have WSDL.
REST has a similar concept called WADL - Web Application Description Language (WADL specification as PDF) - but that's not nearly as well established and widely used as WSDL for SOAP.

getting error message related to basicHttpBinding even though I'm using wsHttpBinding

I am trying to expose a WCF service at a wsHttpBinding endpoint and it gives me the following error message :
Contract requires Session, but Binding
'BasicHttpBinding' doesn't support it
or isn't configured properly to
support it.
Here is the interface :
[ServiceContract(Namespace="http://server.com/orderservices/",SessionMode=SessionMode.Required)]
public interface IOrderService
{
[OperationContract(IsInitiating=true,IsTerminating=false)]
string GetOrderNumber();
[OperationContract(IsInitiating = false, IsTerminating = true)]
void CreateOrder(string orderXML);
}
Here is my web.config file (the service is hosted in IIS 7 ) :
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="longTimeoutBinding"
receiveTimeout="00:10:00" sendTimeout="00:10:00">
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="eMidWare.OrderService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<endpoint
address=""
binding="wsHttpBinding" bindingConfiguration="longTimeoutBinding"
contract="eMidWare.IPricingDataService">
</endpoint>
<endpoint
address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Hmmm.... check your service contract - it's a IOrderService
[ServiceContract(Namespace="http://server.com/orderservices/",SessionMode=SessionMode.Required)]
public interface IOrderService
{
}
but in your config, you're setting up an endpoint for eMidWare.IPricingDataService
<endpoint
address=""
binding="wsHttpBinding" bindingConfiguration="longTimeoutBinding"
contract="eMidWare.IPricingDataService">
Therefore, I believe, .NET / WCF 4 will kick in a default endpoint, which is of basicHttpBinding for the http:// scheme by default....
If you had posted your service interface I could have said with certainty but I believe you have something like this on your service interface:
[ServiceContract(SessionMode = SessionMode.Required)]
This would require session and BasicHttpBinding does not support it. You need to use wsHttpBinding if you need to have sessions.

Categories

Resources