(400) Bad Request - when calling a SOAP service with transferMode=Streamed - wcf

I am getting (400) Bad Request returned when I call a WCF service via SOAP where the method takes a single parameter of type Stream and the transferMode=Streamed.
I get this exception only when I publish the service using the RouteTable class:
RouteTable.Routes.Add(new ServiceRoute("ping", new ServiceHostFactory(), typeof(PingService)));
If I create a ServiceHost myself then I can call the service with no problems:
host = new ServiceHost(typeof(PingService));
host.Open();
Here is an example of the Service contract:
[ServiceContract]
public interface IPing
{
[OperationContract]
Stream Ping(Stream stream);
}
Here is the Web.config:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<services>
<service name="SoapStreamedWebServiceTest.PingService" behaviorConfiguration="md">
<endpoint address="" binding="basicHttpBinding" contract="SoapStreamedWebServiceTest.IPing"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="md">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="stm" transferMode="Streamed"/>
</basicHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
This is only a problem if I create a SOAP service using ServiceHostFactory and basicHttpBinding. If I create a REST service using WebServiceFactory and webHttpBinding then it works fine. However I need to publish both a REST and SOAP endpoint for the same service.
This is also only a problem if the transferMode is Streamed or StreamedRequest, it works for Buffered and StreamedResponse. However I need to allow the consumer to pass me data in a streamed fashion.
If the service is published using the RouteTable then it will return (400) Bad Request when called with transferMode=Streamed without hitting any breakpoint I place within the Ping metod. However if I manually create a Service Host it does hit the breakpoint. I have noticed that the Stream.Lenth property raises an exception when called via SOAP but it does not when called via REST. Could this be anything to do with the problem?
Can anyone shed any light as to why I get (400) Bad Request when calling a SOAP service with transferMode=Streamed when it is published via the RouteTable?

Related

WCF/SSL error: Failed to lookup a channel to receive an incoming message

I've been having a difficult time getting a WCF call in Silverlight to work when using SSL. I've gotten it to a point where WCF tracing says the endpoint is listening but when my code tries to call a function on it WCF Tracing shows the error:
Failed to lookup a channel to receive an incoming message. Either the endpoint or the SOAP action was not found.
If I browse to the services URL I properly get the service page, but calling it in code it always fails. Again, this only happens on HTTPS, not before when I was using HTTP. Of course there were a number of config changes to add to use SSL. I should note that the WCF Domain Services functions work fine over SSL, just not the WCF Service. Below are my various config file sections
Web.config
<system.serviceModel>
<domainServices>
<endpoints>
<add name="OData" type="System.ServiceModel.DomainServices.Hosting.ODataEndpointFactory, System.ServiceModel.DomainServices.Hosting.OData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</endpoints>
</domainServices>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior>
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding" maxReceivedMessageSize="20000" maxBufferSize="20000">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
<readerQuotas maxArrayLength="20000" maxStringContentLength="20000" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="PictureService">
<endpoint address="https://MyServer/AdvisorDev/PictureService.svc"
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="PictureService.IPictureService"/>
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
ServiceReferences.ClientConfig:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IPictureService" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://MyServer/AdvisorDev/PictureService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IPictureService"
contract="PictureService.IPictureService" name="BasicHttpBinding_IPictureService" />
</client>
</system.serviceModel>
</configuration>
Create client:
PictureService.PictureServiceClient client = new PictureService.PictureServiceClient();
I am running this on my Dev machine using VS 2012 and using IIS as my web server. IIS is using a self-signed certificate. When my site first loads I do get the "There is a problem with this website's security certificate" error, click continue, and the rest of the application runs fine again including the Domain Service calls which use a dynamically created proxy. I create my proxy for this failing WCF service using "Add Service Reference"
One of my sources for SSL is this:
http://msdn.microsoft.com/en-us/library/hh556232(v=vs.110).aspx
This is the service I implemented:
http://www.silverlightshow.net/items/Uploading-and-downloading-images-from-WCF-in-Silverlight.aspx
I appreciate all advice on this, thank you.
It turns out this error was caused by an incorrect namespace in the Service name and contract attributes in the web.config for this service.
Just in case anyone else is having this issue as well, I was receiving the same error. The fix turned out to be removing inheritance from three of my classes.
My WCF service was returning a List<MyObject> and three classes inherited from the "MyObject" class. This error was thrown when one of the inheriting classes was included in the list.
Ex:
public class MyObject
public class MyObjectTwo : MyObject
...
List<MyObject> returnList;
MyObjectTwo addingThisBreaksTheService = new MyObjectTwo();
returnList.Add(addingThisBreaksTheService);
return returnList; // Exception thrown after this statement

WCF Authentication Service Proxy - CookieContainer not available

I have enabled the ASP.Net authentication service, as recommended by msdn. I am then attempting to use the service via a console app or winforms app (by adding a service reference to my local WCF service). I am doing custom authentication and transport security (so I am handling the AuthenticationService.Authenticating event in my Global.asax which works fine).
The authentication itself works fine, but the proxy created by adding the Service Reference does not include the CookieContainer property. This is obviously a problem when I try to pass the cookie token to subsequent services which require authentication.
Also, in the following client code, the IsLoggedIn() returns false, I'm guessing this is related to no cookie container being present.
ServiceReference1.AuthenticationServiceClient client =
new ServiceReference1.AuthenticationServiceClient();
bool isLoggedIn = client.Login("test", "test", "", true); //returns TRUE
bool check = client.IsLoggedIn(); //returns FALSE
Here is my web.config on the service:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true"
requireSSL = "false"/>
</webServices>
</scripting>
</system.web.extensions>
<system.serviceModel>
<services>
<service name="System.Web.ApplicationServices.AuthenticationService"
behaviorConfiguration="AuthenticationServiceTypeBehaviors">
<endpoint contract="System.Web.ApplicationServices.AuthenticationService"
binding="basicHttpBinding"
bindingConfiguration="userHttps"
bindingNamespace="http://asp.net/ApplicationServices/v200"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="userHttps" allowCookies="true">
<!--<security mode="Transport" />-->
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="AuthenticationServiceTypeBehaviors">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
</configuration>
EDIT: Something else I should add, I did a Fiddler session of the service calling the Login method, and the cookie is being set and sent back to the client. But what am I supposed to do with no CookieContainer?
When this option is enabled the client will make sure all cookies received from a given web
service are stored and properly sent on each subsequent request in a transparent fashion.
But there is a catch: the cookie is only handled in the conversation with one web service.
What if you need to send the same cookies to different web services?
If you need to send the same cookies to multiple services, read this article: http://megakemp.wordpress.com/2009/02/06/managing-shared-cookies-in-wcf/
You need to configure the binding to allow cookies.
<system.ServiceModel>
<bindings>
<basicHttpBinding allowCookies="true">
</bindings>
Apparently, when adding a Service Reference (.Net 3.5+) to a WCF service on a client, the proxy class derives from System.ServiceModel.ClientBase. This class does not have a CookieContainer property (because the ClientBase supports non-HTTP protocols that have no concept of cookies).
http://netpl.blogspot.com/2011/11/managing-cookies-in-wcf-client.html
I could add a Web Reference instead, which would use the .Net 2.0 proxy class (and has CookieContainer property exposed) http://msdn.microsoft.com/en-us/library/bb628649.aspx. But I will most likely revisit my approach entirely and use custom headers and service behaviors to accomplish my goal.
Another option is to access the cookie container for the underlying channel like this:
var cookieManager = client.InnerChannel.GetProperty<IHttpCookieContainerManager>();
cookieManager.CookieContainer.Add(new Cookie(....));
For the above manager to be present, you need to set AllowCookies to true, e.g.:
<system.ServiceModel>
<bindings>
<basicHttpBinding allowCookies="true">
</bindings>

WCF 4 Routing Multicast Configuration Frustration

I have been using stackoverflow.com as a resource as a professional programmer for years now. I would say 8 out of 10 times when I search for something on google, I get pointed to a question and answer here, and I am always relieved when that happens, because I know I am about to find the information I need.
I have been pulling my hair out trying to figure (what I think to be) a simple problem out, concerning setting up a routing service using WCF technology. I have browsed through the questions with similar titles here, and I have consulted a great many resources (both actual books on the subject, as well as websites) trying to figure this out, to no avail.
In a nutshell, I want to setup a system with the following layout:
{client}<-basicHTTP->{portal/router}<-fullWCF-WS*->{end-point-services1..n}
client: gets service reference to portal, able to call functions at end-point service
portal/router: gets requests from client, and sends them on to end-point services in a multi-cast setup
end-point-services1..n: gets request from client, routed through portal, processes request to search for things, and either responds, or logs data in a database to be checked later
I am, 100%, able to get a routing service up and running. The most successful models I have been able to follow, were outlined in the "What's new in WCF4: exercises 8 & 9, content bridging & routing" (msdn.microsoft.com/en-us/gg465212) and "Hello World with the Routing Service" (msdn.microsoft.com/en-us/library/dd795218.aspx) But I have used bits and pieces from all of the sources I have consulted (listed below).
Basically, what is frustrating me, is that I want a client (a 3rd party) to be able to just add a web service reference to the portal service (or, worst case scenario, use the svcutil.exe method), and be done with setup on their part. With that reference, they will have references to all the functions/methods they would want to call in all scenarios. The models I have looked at that do this require 2 references, one to the actual service, and one to the router, and then force the client to specifically call the router in their setup. None of my other attempts to make this particular setup work, have worked.
Your help with this would be greatly appreciated.
Here is a simplified version of my working model that almost is doing what I want:
(note, all services are being hosted in IIS)
PORTAL SERVICE (and IIS Host)
Portal.svc:
<%# ServiceHost Service="System.ServiceModel.Routing.RoutingService, System.ServiceModel.Routing, version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
Web.config:
<configuration>
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<bindings>
...
</bindings>
<client>
<endpoint address="http://searcher1/Searcher.svc/general" binding="basicHttpBinding" contract="*" name="regularSearchServiceEndpoint" />
<endpoint address="http://searcher2/Searcher.svc/general" binding="basicHttpBinding" contract="*" name="regularSearchServiceEndpoint2" />
</client>
<behaviors>
...
</behaviors>
<routing>
<filters>
<filter name="MatchAllFilter" filterType="MatchAll" />
</filters>
<filterTables>
<filterTable name="filterTable1">
<add filterName="MatchAllFilter" endpointName="regularSearchServiceEndpoint" backupList="backupList1" priority="0"/>
</filterTable>
</filterTables>
<backupLists>
<backupList name="backupList1">
<add endpointName="regularSearchServiceEndpoint2"/>
</backupList>
</backupLists>
</routing>
<services>
<service behaviorConfiguration="routingConfiguration" name="System.ServiceModel.Routing.RoutingService">
<endpoint address="general" binding="basicHttpBinding" name="routerEndpoint1" contract="System.ServiceModel.Routing.IRequestReplyRouter" />
</service>
</services>
</system.serviceModel>
</configuration>
SEARCH SERVICE
ISearch.cs:
namespace SearchService
{
[ServiceContract]
public interface ISearch
{
[OperationContract]
string Ping();
[OperationContract]
string searchByInput(string input);
}
}
App.config:
<configuration>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<bindings>
<basicHttpBinding>
...
</basicHttpBinding>
<customBinding>
...
</customBinding>
</bindings>
<client>
...
</client>
<services>
<service name="SearchService.Search">
<endpoint address="general" binding="basicHttpBinding" contract="SearchService.ISearch" name="SearchService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/SearchService/Service1/"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
SEARCH SERVICE HOST
Search.svc:
<%# ServiceHost Service="SearchService.Search" %>
Web.config:
<configuration>
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<!--copied over from SearchService.App.config-->
</basicHttpBinding>
<customBinding>
<!--copied over from SearchService.App.config-->
</customBinding>
</bindings>
<client>
<!--copied over from SearchService.App.config-->
</client>
<services>
...
</services>
<behaviors>
...
</behaviors>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
CLIENT (where it all goes wrong)
Only way I have been able to get it to do what I want, is to add a web service reference to the searcher service (named "remotehost"), and then manually add client endpoints to the app.config file for the router, and force the client code to use that, INSTEAD of the direct link it already has to the searcher
Main.cs:
namespace Client
{
public partial class Main : Form
{
remotehost.SearchClient proxy;
public Main()
{
InitializeComponent();
proxy = new remotehost.SearchClient("RouterService");//("BasicHttpBinding_ISearch")
}
private void button1_Click(object sender,EventArgs e)
{
string response = string.Empty;
//uses method exposed by the SearchService service
response = proxy.Ping();
MessageBox.Show("Response from remote service:\n" + response
"Ping Response",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}
}
App.config:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
...
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://searcher1/Searcher.svc/general" binding="basicHttpBinding" bindingConfiguration="SearchService" contract="remotehost.ISearch" name="SearchService" />
<!--I manually added this-->
<endpoint address="http://portal/Portal.svc/general" binding="basicHttpBinding" contract="remotehost.ISearch" name="RouterService" />
</client>
</system.serviceModel>
</configuration>
I want to emphasize, this all WORKS, but it doesn't work the WAY I want it to. I am fairly certain I can push/pull/cajole this into the elegant setup I am envisioning, but I can't seem to find a resource or guide that will walk me through it for the first time.
Help?
Sources I have consulted, before coming here:
Learning WCF: A Hands-on Guide, by Bustamante, Michele Leroux {978-0-5961-0162-6} (read cover to cover, and did all exercises)
Windows Communication Foundation 4: Step By Step {978-0-7356-4556-1} (focused on chapter 14: Discovering Services and Routing Messages)
msdn.microsoft.com/en-us/library/ms734712.aspx {WCF: Getting Started Tutorial}
msdn.microsoft.com/en-us/gg465212 {what's new in WCF4: exercises 8 & 9, content bridging & routing}
codeproject.com/Articles/146835/How-to-create-scalable-services-with-WCF-4-0-Route {How to create scalable services with WCF 4.0 Router and Discovery services}
msdn.microsoft.com/en-us/library/dd795218.aspx {Hello World with the Routing Service}
msdn.microsoft.com/en-us/library/ee517421.aspx {routing}
msdn.microsoft.com/en-us/library/ee517423.aspx {routing service overview}
msdn.microsoft.com/en-us/library/ee517418.aspx {routine service features}
msdn.microsoft.com/en-us/library/ee517422.aspx {routing intro}
msdn.microsoft.com/en-us/library/ee517420.aspx {routing contracts}
msdn.microsoft.com/en-us/library/bb332338.aspx {wcf routing}
msdn.microsoft.com/en-us/library/ms730158.aspx {more wcf routing}
msdn.microsoft.com/en-us/library/ee354381.aspx {more wcf routing}
dandcohen.wordpress.com/2010/03/02/wcf-4-routing-service-multicast-sample/ {WCF 4 Routing Service Multicast sample}
UPDATE: 2012-04-28:
I figured out a way to do what I wanted. It still isn't as elegant as I wanted, but it get the job done and has allowed me to move forward.
Basically, take the interface from the main service, and implement it in a new service, call it router or portal, or whatever. In the new router/portal service, add a new service reference to the main service.
Now, both services are using the same interface, and have the same signatures for all their methods, so you can then just give the portal/router service wsdl to the 3rd party client, and only allow your portal/router service to communicate with the main service.
Additionally, if you have more than one main service, you can use the portal/router service to decide which of the main services to send requests to, using multiple service references to them, and proxies to send the jobs onward. It works really well.
It is basically a manual front-end routing service, but the beauty is, the detailed work can be done in the main services on a threading model, while the gatekeeping work can be done at the portal/router, so only actual requests are sent to the main services, allowing them to only do work, and the portal services to decide how or if they get that work. The next step I want to add it automatic discovery of new services, but for now, manual configuration is working fine.
I can post the source code for what I came up with, if anyone wants to see it and requests it.
The fundamental problem is that the router knows nothing about the service contract that the service is using - it uses a universal contract (one which uses the Message type). Therefore, there is no way for the router to auto-generate the metadata for the client.
What you will need to do is provide the metadata yourself, maybe as a static WSDL document, with the correct addresses in it and point clients to this

Two endpoints in WCF 3.5 for SOAP and JSON

I dont know what I am doing wrong. I have a WCF (.NET 3.5) service (JsonSoap.svc) that has two endpoints for soap and json content type. Both the endpoints refer to the same service. I am using only one Json endpoint in the client. My aim is to have the service method GetPerson() to return Json or soap depending on the endpoints used to connect to the service (hopefully this is possible in WCF?). I can see wsdl and was able to successfully ad the service reference in to the client side.
I get the following error after I make a call to the GetPerson() -
"An error occurred while receiving the
HTTP response to
http://localhost:80/JsonSoap/json/GetPerson.
This could be due to the service
endpoint binding not using the HTTP
protocol. This could also be due to
an HTTP request context being aborted
by the server (possibly due to the
service shutting down). See server
logs for more details."
WCF service config
<!-- bindings -->
<bindings>
<basicHttpBinding>
<binding name ="soapBinding">
<security mode="None">
</security>
</binding>
</basicHttpBinding>
<webHttpBinding>
<binding name="webBinding">
</binding>
</webHttpBinding>
</bindings>
<!-- JSON behaviors -->
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="defaultBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="TestService.IJsonSoap" behaviorConfiguration="defaultBehavior">
<host>
<baseAddresses>
<!-- note, choose an available port-->
<add baseAddress="http://localhost:80/JsonSoap" />
</baseAddresses>
</host>
<endpoint address="soap" binding="basicHttpBinding"
bindingConfiguration="soapBinding"
contract="TestService.IJsonSoap" />
<endpoint address="json" binding="webHttpBinding"
bindingConfiguration="webBinding"
behaviorConfiguration="jsonBehavior"
contract="TestService.IJsonSoap" />
</service>
WCF code:
[OperationContract]
[WebGet]
Person GetPerson(int ID);
WCF Client config:
<endpoint address="http://localhost:80/JsonSoap/json" binding="webHttpBinding"
bindingConfiguration="webBinding" behaviorConfiguration="jsonBehavior"
contract="MyService.IJsonSoap" />
Client code:
MyService.JsonSoapClient service = new JsonSoapClient();
MyService.Person person = service.GetPerson(10);
This will not work. WSDL servers only for SOAP services and it is the source for Add Service Reference in Visual Studio. You are using client code generated by Visual Studio but you are using it with Json endpoint which doesn't work.
Json endpoint represents REST service. To call WCF REST service in .NET you must either:
Build manully HTTP Request
Share service contract with a client and use ChannelFactory or WebChannelFactory to build a proxy
Use REST Starter KIT CTP2 and its HttpClient class (not recommended because development of REST Starter KIT ended).

WCF Multiple Endpoints Under IIS7

I have a simple WCF service that we are developing... We are hosting in IIS7 on WinServer2k8 (though i cant get it to work in IIS7 on Win7 either)
I want multiple endpoints for the same service contract but have the endpoints behave differently. For example I want one endpoint to return data as XML and another to return data in SOAP messages.
Here is my web.config
<system.serviceModel>
<services>
<service name="MemberService">
<endpoint address="soap" binding="basicHttpBinding" contract="IMemberService" />
<endpoint address="xml" binding="webHttpBinding" contract="IMemberService" behaviorConfiguration="xmlBehavior" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="xmlBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
In my service contract i have a method defined as:
[OperationContract]
[WebGet(UriTemplate = "members/{id}")]
Member GetMember(string id);
When I deploy to IIS (on localhost) and make a request (with fiddler) to http://localhost/MemberService.svc/xml/members/memberid I receive a 404 error, also a 404 with http://localhost/MemberService.svc/soap/
However, http://localhost/MemberService.svc/members/memberid works and serializes the data as expected. We want to add the functionality of JSON in the near future as well, we thought it would be another endpoint with a different behavior. My web.config is modeled after a post i found on here
Following this tutorial....
I was able to quickly deploy the webservices. Then using fiddler I could change the content-type of the request to/from "text/xml" and "text/json" and the service would automatically return the data in the correct format.