WCF hosted on SharePoint - Need to enable https - wcf

I have a WCF hosted in SharePoint 2013 with two methods GET and SET send JSON data. The WCF worked fine under HTTP servers but now we need to move it to production and run it under SSL where we have a certificate installed on the server.
I made changes to the web.config file but I'm getting error 404 Not Found when I try to call the GET method.
Here is my Web.Config (working on HTTP before the change)
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="WCF.Service" behaviorConfiguration="WCF.ServiceBehavior" >
<endpoint address=""
binding="webHttpBinding"
contract="WCF.IService"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCF.ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior >
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="NoSecurityHttpBinding">
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
Here is what I tried to make the code work:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="WCF.Service" behaviorConfiguration="WCF.ServiceBehavior" >
<endpoint address=""
binding="webHttpBinding"
contract="WCF.IService"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCF.ServiceBehavior">
<serviceMetadata **httpsGetEnabled**="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior >
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="NoSecurityHttpBinding">
<security mode="**Transport**">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
Here is my C# Code on the service interface:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "Get/{Code}")]
Stream Get(string Code);
}
Method code
public class Service : IService
{
public Stream Get(string Code)
{
string strOutPut = "";
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json;charset=utf8";
try
{
/// geting data
return new MemoryStream(Encoding.UTF8.GetBytes(strOutPut));
}
catch (Exception e)
{
// error handler
}
}
}
Any Ideas? What am I missing to enable this method on HTTPS as a SharePoint ISAPI hosted service?

You define security for your binding, but you never assign that binding to your endpoint:
<service name="WCF.Service" behaviorConfiguration="WCF.ServiceBehavior" >
<endpoint address=""
binding="webHttpBinding"
contract="WCF.IService" />
</service>
All your service endpoint says is use webHttpBinding - since you didn't specify a configuration for the binding, the defaults are used, and the default transport for webHttpBinding is None.
Use the bindingConfiguration attribute to tell the endpoint which binding configuration to use:
<endpoint address=""
binding="webHttpBinding"
bindingConfiguration="NoSecurityHttpBinding"
contract="WCF.IService" />
I'd suggest changing the name of your configuration to something other than "NoSecurityHttpBinding" if you're adding security to it.
There may be other issues as well, but you won't even get out of the door until you assign the binding configuration to your endpoint.

Related

How to add Custom Service Behavior To WCF Configuration

I have a service with ComplexType in the Uri Template Parameter, I have Override the CanConvert() and ConvertStringToValue() methods to the class MyQueryStringConverter.
I need to add that behavior to the web.config file.
Here is the Behavior
public class MyWebHttpBehavior : WebHttpBehavior
{
protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
{
return new MyQueryStringConverter();
}
}
Here Is the Configuration File :
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webHttp"
maxReceivedMessageSize="20000000" >
<security mode="None">
<transport clientCredentialType = "None"/>
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="mexBehaviour">
<serviceMetadata httpGetEnabled="true"/>
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="http" port="80" />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="Service.Service1" behaviorConfiguration="mexBehaviour">
<endpoint address="" binding="webHttpBinding" contract="Service.IService1" bindingConfiguration="webHttp" behaviorConfiguration="web"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange">
</endpoint>
</service>
</services>
</system.serviceModel>
Please help how to add that behavior.
First, you must register your behavior, using behaviorExtensions element in your configuration file:
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="MyWebHttpBehavior"
type="FullNameSpace.MyWebHttpBehavior, MyWebHttpBehavior.AssemblyName, Version=1.0.0.0, Culture=neutral" />
</behaviorExtensions>
</extensions>
Where:
"FullNameSpace.MyWebHttpBehavior" is your class with full namespace,
"MyWebHttpBehavior.AssemblyName" is your assembly name with extension
where your class is compiled.
"1.0.0.0" is the version of your assembly
"neutral" is your Culture. Change if any special Culture is required
Secound, declare your behavior:
<behaviors>
<endpointBehaviors>
<behavior name="customMyWebHttpBehavior">
<webHttp/>
<MyWebHttpBehavior/>
</behavior>
</endpointBehaviors>
<behaviors>
Next, add to the binding:
<bindings>
<webHttpBinding>
<binding name="webHttp"
maxReceivedMessageSize="20000000" >
<security mode="None">
<transport clientCredentialType = "None"/>
</security>
</binding>
<MyWebHttpBehavior />
</webHttpBinding>
</bindings>
And finally, set the behavior to your service endpoint:
<endpoint address="" binding="webHttpBinding" contract="Service.IService1" bindingConfiguration="webHttp" behaviorConfiguration="customMyWebHttpBehavior"/>
I've copied this configuration of a service I've developed and changed the names to fit your class/configuration, but check if I did not wrote anything wrong.
I've used this link as base to setup my configuration: Custom Behavior won't register in my web.config
Hope it helps.

RESTful GET on HTTPS returning bad request 400 error

I recently needed to change my REST WCF service to use SSL.
It is hosted in IIS 6 and was working fine prior to the SSL requirement.
I am unable to figure out why I'm getting the 400 bad request error.
I have diagnostic logging and it says the
<Message>The body of the message cannot be read because it is empty.</Message>
The web.config looks like:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<webServices>
<protocols>
<add name="HttpGet"/>
</protocols>
</webServices>
<identity impersonate="true"/>
<customErrors mode="Off"/>
</system.web>
<startup>
<supportedRuntime version="v4.0.30319"/>
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IMessageService">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
<webHttpBinding>
<binding name ="webBinding">
</binding>
</webHttpBinding>
<basicHttpBinding>
<binding name="httpBinding">
<security mode="Transport">
<transport clientCredentialType = "None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="metadataBehavior"
name="XXXDataService.XXXDataService">
<endpoint address=""
binding="wsHttpBinding"
bindingNamespace="http://blah.blah.blah.com/XXXDataService/"
bindingConfiguration="WSHttpBinding_IMessageService"
contract="ZZZDataService.IZZZDataServices">
</endpoint>
<endpoint address="mex"
binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name=""
helpEnabled="true"
automaticFormatSelectionEnabled="true" />
</webHttpEndpoint>
</standardEndpoints>
<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="True"
httpHelpPageEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I only removed the diagnostics part and needed to protect the names by replacing with XXX and ZZZ.
Any help or suggestions would be greatly appreciated.
service implementation:
[ServiceBehavior(Namespace="blah.blah.blah.com", Name="XXXDataService")]
public class YYYDataService : IYYYDataService
{
public string GetUser(string id)
{
string result = string.Empty;
using (YYYAdmintTree tree = new YYYAdmintTree()) // used for accessing DB
{
result = tree.GetUserById(id, 1);
}
return result;
}
}
contract:
[ServiceContract(Namespace="https://blah.blah.blah.com", Name="XXXDataService")]
public interface IYYYDataService
{
[OperationContract]
[WebGet(UriTemplate="/GetUser/{id}", ResponseFormat=WebMessageFormat.Json)]
string GetUserById(string id);
}
Error 400 comes when you pass wrong parameter as Input. If you are passing XML or JSON as an input check once again. If server was unable to locate it it would have given you error 404. But 400 indicates surely there is something wrong with input provided.

WCF Multiple Endpoints is not working

I am trying to let my WCF service to have operations that can be called through a proxy client and through REST call, i am using the following configurations:
<services>
<service behaviorConfiguration="SecureBehavior" name="Payment">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="secureWS" contract="IPayment"/>
<endpoint address="rest" binding="webHttpBinding" behaviorConfiguration="webBehavior" contract="IPayment"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<bindings>
<mexHttpBinding>
<binding name="userMex"/>
</mexHttpBinding>
<wsHttpBinding>
<binding name="secureWS">
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
</security>
</binding>
<binding name="publicWS">
<security mode="None"/>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="false"/>
</serviceCredentials>
</behavior>
<behavior name="PublicBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="true"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</services>
and here is my code:
[ServiceContract]
public interface IPayment
{
[OperationContract]
PaymentResult Finalize(string TransactionID, string CertificatePath);
[OperationContract]
[WebGet(UriTemplate = "rest")]
System.IO.Stream GetPayment();
}
Now whenever i run my service i receive this error:
Operation 'Finalize' of contract 'IPayment' specifies multiple request body parameters to be serialized without any wrapper elements. At most one body parameter can be serialized without wrapper elements. Either remove the extra body parameters or set the BodyStyle property on the WebGetAttribute/WebInvokeAttribute to Wrapped.
Where here i would like to keep Finalize operation to be only called via .NET client and the GetPayment operation to be called through any browser.
If you do not want your Finalize method to be called from a client connecting via the webhttp endpoint and you don't want GetPayments to be called from a client connecting via wshttp you can simply split your contract in two.
Assuming you are hosting in IIS you might need to do a little trick to make sure that it works. Let me give you an example using the details from the question...
First of all here is the code for the two services...
[ServiceContract]
public interface IPayment
{
[OperationContract]
[WebGet(UriTemplate = "rest")]
System.IO.Stream GetPayment();
}
[DataContract]
public class PaymentResult
{
}
[ServiceContract]
public interface IMakePayment
{
[OperationContract]
PaymentResult Finalize(string TransactionID, string CertificatePath);
}
// Maybe you really should have the two services separate but if you do
// want to implement them both in a single class you can do this
public abstract class PaymentBase : IMakePayment, IPayment
{
// ... Implement both interfaces here
public PaymentResult Finalize(string TransactionID, string CertificatePath)
{
return null;
}
public System.IO.Stream GetPayment()
{
return null;
}
}
public class MakePayment : PaymentBase
{
// Empty
}
public class Payment : PaymentBase
{
// Empty
}
Now create two .svc files like so:
MakePayment.svc
<%# ServiceHost Language="C#" Debug="true" Service="WebApplication1.MakePayment" %>
Payment.svc
<%# ServiceHost Language="C#" Debug="true" Service="WebApplication1.Payment" %>
And finally here is the system.servicemodel configuration:
<system.serviceModel>
<services>
<service behaviorConfiguration="SecureBehavior" name="WebApplication1.MakePayment">
<endpoint binding="wsHttpBinding" bindingConfiguration="secureWS" contract="WebApplication1.IMakePayment"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" bindingConfiguration="userMex"/>
</service>
<service behaviorConfiguration="PublicBehavior" name="WebApplication1.Payment">
<endpoint binding="webHttpBinding" behaviorConfiguration="webBehavior" bindingConfiguration="publicWS" contract="WebApplication1.IPayment"/>
</service>
</services>
<bindings>
<mexHttpBinding>
<binding name="userMex"/>
</mexHttpBinding>
<wsHttpBinding>
<binding name="secureWS">
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
<webHttpBinding>
<binding name="publicWS">
<security mode="None"/>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="false"/>
</serviceCredentials>
</behavior>
<behavior name="PublicBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<windowsAuthentication allowAnonymousLogons="true"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
There you go - if you connect to /MakePayment.svc you will connect via WSHTTP and be able to call FinalizePayment and if you go to /Payments.svc/rest it will call the GetPayment method where you are returning a stream.

Contract requires Session, but Binding ‘WSHttpBinding’ doesn’t support it or isn’t configured properly to support it

I have specified the service contract to require the session.
[ServiceContract(SessionMode = SessionMode.Required)]
public interface ITicketSales
{
}
The service decorated like this:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
public class TicketSalesService : ITicketSales
{
}
Here is my App.config file:
<system.serviceModel>
<services>
<service name="InternetRailwayTicketSales.TicketSalesImplementations.TicketSalesService" behaviorConfiguration="defaultBehavior">
<host>
<baseAddresses>
<add baseAddress = "https://localhost/TicketSales/"></add>
</baseAddresses>
</host>
<endpoint address="MainService" binding="wsHttpBinding" bindingConfiguration="wsSecureConfiguration"
contract="InternetRailwayTicketSales.TicketSalesInterface.ITicketSales" />
<endpoint address="mex" binding="mexHttpsBinding"
contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="wsSecureConfiguration">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="defaultBehavior">
<serviceThrottling maxConcurrentInstances="5000" maxConcurrentSessions="5000"/>
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
When I press F5 I receive the error message "Contract requires Session, but Binding ‘WSHttpBinding’ doesn’t support it or isn’t configured properly to support it."
I really need the channel which supports SSL and requires session.
You can support sessions by enabling message security:
<binding name="wsHttpSecureSession">
<security>
<message establishSecurityContext="true"/>
</security>
</binding>
If you need to go with transport security you may need to specify a client credential type

How to use SSL with a WCF web service?

I have a web service in asp.net running and everything works fine. Now I need to access some methods in that web-service using SSL. It works perfect when I contact the web-service using http:// but with https:// I get "There was no endpoint listening at https://...".
Can you please help me on how to set up my web.config to support both http and https access to my web service. I have tried to follow guidelines but I can't get it working.
Some code:
My TestService.svc:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class TestService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public bool validUser(string email) {
return true;
}
}
My Web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior name="ServiceAspNetAjaxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ServiceBehavior" name="TestService">
<endpoint address="" behaviorConfiguration="ServiceAspNetAjaxBehavior"
binding="webHttpBinding" bindingConfiguration="ServiceBinding"
contract="TestService" />
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="ServiceBinding" maxBufferPoolSize="1000000" maxReceivedMessageSize="1000000">
<readerQuotas maxDepth="1000000" maxStringContentLength="1000000" maxArrayLength="1000000" maxBytesPerRead="1000000" maxNameTableCharCount="1000000"/>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
Instead of using the webHttpBinding, try creating a customBinding instead:
<customBinding>
<binding name="poxBindingHttps" closeTimeout="00:00:20">
<textMessageEncoding writeEncoding="utf-8" />
<httpsTransport manualAddressing="true"/>
</binding>
<binding name="poxBindingHttp" closeTimeout="00:00:20">
<textMessageEncoding writeEncoding="utf-8" />
<httpTransport manualAddressing="true"/>
</binding>
</customBinding>
You'll also need to setup the webHttpBehavior like so:
<behaviors>
<endpointBehaviors>
<behavior name="ajaxBehavior">
<enableWebScript/>
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
And finally, your service & endpoint:
<services>
<service name="TestService">
<endpoint name="sslDefault" address="" binding="customBinding" bindingConfiguration="poxBindingHttps" behaviorConfiguration="ajaxBehavior" contract="TestService"/>
<endpoint name="noSslDefault" address="" binding="customBinding" bindingConfiguration="poxBindingHttp" behaviorConfiguration="ajaxBehavior" contract="TestService"/>
</service>
</services>
Hopefully that works out for you in creating an SSL endpoint
It sounds like there is more an issue with IIS no listening on port 443 (The port used for HTTPS). Check IIS that there is a certificate installed and that it is listening on the secure port.