How do you pass user credentials from WebClient to a WCF REST service? - wcf

I am trying to expose a WCT REST service and only users with valid username and password would be able to access it. The username and password are stored in a SQL database.
Here is the service contract:
public interface IDataService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
byte[] GetData(double startTime, double endTime);
}
Here is the WCF configuration:
<bindings>
<webHttpBinding>
<binding name="SecureBinding">
<security mode="Transport">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="DataServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType=
"CustomValidator, WCFHost" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="DataServiceBehavior" name="DataService">
<endpoint address="" binding="webHttpBinding"
bindingConfiguration="SecureBinding" contract="IDataService" />
</service>
</services>
I am accessing the service via the WebClient class within a Silverlight application. However, I have not been able to figure out how to pass the user credentials to the service. I tried various values for client.Credentials but none of them seems to trigger the code in my custom validator. I am getting the following error: The underlying connection was closed: An unexpected error occurred on a send.
Here is some sample code I have tried:
WebClient client = new WebClient();
client.Credentials = new NetworkCredential("name", "password", "domain");
client.OpenReadCompleted += new OpenReadCompletedEventHandler(GetData);
client.OpenReadAsync(new Uri(uriString));
If I set the security mode to None, the whole thing works. I also tried other clientCredentialType values and none of them worked. I also self-hosted the WCF service to eliminate the issues related to IIS trying to authenticate a user before the service gets a chance.
Any comment on what the underlying issues may be would be much appreciated. Thanks.
Update: Thanks to Mehmet's excellent suggestions. Here is the tracing configuration I had:
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.IdentityModel" switchValue="Information,
ActivityTracing" propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\Traces.svclog" />
</sharedListeners>
</system.diagnostics>
But I did not see any message coming from my Silverlight client. As for https vs http, I used https as follows:
string baseAddress = "https://localhost:6600/";
_webServiceHost = new WebServiceHost(typeof(DataServices),
new Uri(baseAddress));
_webServiceHost.Open();
However, I did not configure any SSL certificate. Is this the problem?

Since you are using 'Basic' authentication you need to send the username and password in the request header. The example of manually adding the credentials to the header is displayed below:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(#"https://localhost:6600/MyWCFService/GetData");
//Add a header to the request that contains the credentials
//DO NOT HARDCODE IN PRODUCTION!! Pull credentials real-time from database or other store.
string svcCredentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes("userName" + ":" + "password"));
req.Headers.Add("Authorization", "Basic " + svcCredentials);
//Parse the response and do something with it...
using (WebResponse svcResponse = (HttpWebResponse)req.GetResponse())
{
using (StreamReader sr = new StreamReader(svcResponse.GetResponseStream()))
{
//Sample parses json response; your code here may be different
JavaScriptSerializer js = new JavaScriptSerializer();
string jsonTxt = sr.ReadToEnd();
}
}

First you may want to add WCF tracing to your service to get more details. Second, I believe the problem could be that you're sending user credentials in clear text and WCF does not allow the transmission of user credentials in clear text over unsecured transport channel. So either try using https or specify an encryption algorithm to secure user credentials over http.

What atconway suggested above seems correct way but your service has to read base 64 string data from header and convert back to string and then authenticate. But it needs to authenticate on every call.
One more approach is to use secure key. and token
Every client has secure key which he sends on first request ,
probably in header.
You can generate key like key = MD5Hash(username+password);
In response he gets token the , the token is then sent in each
request. Token can be Guid. Every token expired after x mins.
On server side you can maintain a singleton dictionary like Dictionay , to check token expiration when current time > expiration time remove it from dictionary.
To renew sessions put renew session method in your code.
For extream security
Have private/public key pair, client will encrypt entire post data using public key and you will decrypt using private key.

Related

Client Certs for WCF consumer stops working after a while

I am having really peculiar issue with certs not working after a while for WCF Client App that connect to SOAP 1.1 SAP service. What boggles me is the steps I have to take to make the certs work again. After I installed the certs on couple of load balanced servers, seems like everything works fine. But then after a few days, one of the app/servers throws this error.
The request was aborted: Could not create SSL/TLS secure channel.
When I log on to the server using MMC and open the cert (I do not even have to reinstall it, just open is good enough), the web app works. I am at my wits end as to why this might be happening. Any help will be appreciated.
Below are the architecture/some code samples of how the apps/web services are set up
[MVC WebApp]--[ Load Balancer ]-->(Server 1, Server 2)--> SAP SOAP 1.0 Web Service
Some configuration and code samples..
<system.serviceModel>
<client>
<endpoint address="https://somesapwebservice:8104/XISOAPAdapter/MessageServlet?senderParty=&senderService=BC_PORTAL&receiverParty=&receiverService=&interface=SI_AppFormData_Out_Sync&interfaceNamespace=urn%3Acominc.com%3AOTC%3AI1053%3AppForm" behaviorConfiguration="secureCert" binding="wsHttpBinding" contract="somecontract_Out_Sync" name="HTTPS_Port" />
</client>
<bindings>
<wsHttpBinding>
<binding>
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="secureCert">
<clientCredentials>
<clientCertificate storeName="My" storeLocation="CurrentUser" x509FindType="FindBySubjectDistinguishedName" findValue="CN=CNN, OU=Windows, OU=SAP, OU=Service Accounts, OU=Admin, OU=CORP, DC=myinc, DC=ds" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
..
<appSettings>
<add key="ProtocolExceptionMessage" value="The content type text/xml; charset=utf-8 of the response message does not match the content type of the binding (application/soap+xml; charset=utf-8)" />
C# Code
public ActionResult FormSubmit(SubmitViewModel model)
try
{
this.SubmitToSAPService(model);
return this.RedirectToAction("Index", "Complete");
}
catch (ProtocolException pe)
{
// Current SAP only support SOAP 1.1 and WCF with .NET 4.6 runs on SOAP 1.2 - Catching the known exception
// Creating custom WCF binding to handle this is another possibility but that config could get convoluted
var messageSnippet = ConfigurationManager.AppSettings["ProtocolExceptionMessage"];
if (pe.Message.Contains(messageSnippet))
{
return this.RedirectToAction("Index", "Complete");
}
throw pe;
}
One thing I am doing little off here is that I was told is that SAP is currently running SAOP 1.1 and .NET we are running is SOAP 1.2. So I was always getting Protocol Exception. To get around that I check for the text and if the exception message matches exactly as expected, I bypass it.
public string SubmitToSAPService(SubmitViewModel model)
{
var dtFormDataRecords = new DT_FormData();
dtFormDataRecords.Records = new DT_FormDataRecords();
dtFormDataRecords.Records.Name = model.name
....
var client = new SI_AppFormData_Out_SyncClient();
try
{
client.SI_AppFormData_Out_Sync(dtFormDataRecords);
}
finally
{
client.Close();
}
...
After trying to run intellitrace on the app, that let to clue me in the app-pool settings Load User Profile was set to False. That had cause the issue I was getting. After I set the it to True, my issue was resolved.

REST WCF service returns XML response but not JSON response

I am new to WCF so I think this is pretty basic. I have a simple method that a single "order" object is returned. It works just fine when using the default XML, however, when I apply the
ResponseFormat = WebMessageFormat.Json
attribute, it fails to return JSON. The code successfully executes and hits the return line but then the method is immediately called again and then finally a third time before the browser returns an error stating the connection to localhost has been interrupted.
When I remove the ResponseFormat = WebMessageFormat.Json, the method is called and XML is returned just fine. Not sure I am missing for the JSON.
IProductSales.cs
namespace ProductsSalesService
{
[ServiceContract(Name = "ProductsSales")]
public interface IProductsSales
{
[OperationContract]
[WebGet(UriTemplate = "Orders/{orderID}", ResponseFormat = WebMessageFormat.Json)]
[Description("Returns the details of an order")]
SalesOrderHeader GetOrder(string orderID);
}
}
ProductSales
public SalesOrderHeader GetOrder(string orderID)
{
SalesOrderHeader header = null;
try
{
int id = Convert.ToInt32(orderID);
AdventureWorksEntities database = new AdventureWorksEntities();
header = (from order in database.SalesOrderHeaders
where order.SalesOrderID == id
select order).FirstOrDefault();
}
catch
{
throw new WebFaultException(HttpStatusCode.BadRequest);
}
return header;
}
I am working through an sample in a WCF book so they had me build a small console application to be the host, so this is the app.config file I have for the host client.
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="AdventureWorksEntities" connectionString="metadata=res://*/ProductsSalesModel.csdl|res://*/ProductsSalesModel.ssdl|res://*/ProductsSalesModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=BINGBONG;Initial Catalog=AdventureWorks;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
</connectionStrings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup><system.serviceModel>
<services>
<service name="ProductsSalesService.ProductsSales">
<endpoint address="http://localhost:8000/Sales" binding="webHttpBinding"
bindingConfiguration="" name="ProductsSalesService.ProductsSales"
contract="ProductsSalesService.IProductsSales" />
</service>
</services>
</system.serviceModel>
</configuration>
Finally, this is just the host client code.
public class Program
{
static void Main(string[] args)
{
WebServiceHost host = new WebServiceHost(typeof(ProductsSalesService.ProductsSales));
host.Open();
Console.WriteLine("Service running");
Console.WriteLine("Press ENTER to stop the service");
Console.ReadLine();
host.Close();
}
}
So when I go to http://localhost:8000/Sales/Orders/43659 to pull up my order it hits three times and the page cancels in Chrome with the following error:
This webpage is not available The connection to localhost was
interrupted. Here are some suggestions: Reload this webpage later.
Check your Internet connection. Restart any router, modem, or other
network devices you may be using. Add Google Chrome as a permitted
program in your firewall's or antivirus software's settings. If it is
already a permitted program, try deleting it from the list of
permitted programs and adding it again. If you use a proxy server,
check your proxy settings or contact your network administrator to
make sure the proxy server is working. If you don't believe you should
be using a proxy server, adjust your proxy settings: Go to the wrench
menu > Settings > Show advanced settings... > Change proxy settings...
LAN Settings and deselect the "Use a proxy server for your LAN" checkbox. Error 101 (net::ERR_CONNECTION_RESET): The connection was
reset.
If I remove the WebMessageFormat.Json everything works fine!
Thanks for any assistance!
For starters try WCF tracing/logging to see if it sheds any light on things.
Put this in your server's config file (somewhere within the <configuration> element):-
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Error" propagateActivity="true">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="C:\Temp\server.svclog"/>
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="messages"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="C:\Temp\server_messages.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
And put this inside the <system.serviceModel> element:-
<diagnostics>
<messageLogging
logEntireMessage="true"
logMalformedMessages="false"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="false"
maxMessagesToLog="3000"
maxSizeOfMessageToLog="2000"/>
</diagnostics>
Try hitting your service again and examine the .svclog files that this (hopefully) generates for clues. The files will open in a "Service Trace Viewer" tool - if not it can be downloaded from MS (part of the Win SDK I think).
Although my fault is actually unrelated, this is the first article I found when looking into my problem which is that my service was failing and I was seeing an error connection has been interrupted.
My fault was to do with the fact that the class I was outputting from my WebGet method had properties that had DataContract attributes but I had not added a Set accessor to each one (because I considered them to be output-only I didn't see the point).
Adding the tracing into my configuration file quickly revealed that the fault was that there were no Set accessors, so I added private set accessors to each DataContract property and all is now working as expected.
I have added this here in case anyone else follows the same search path and has the same issue.
This line of code will construct Service Host without taking configuration into account so you will have Service but it will listen different URL.
WebServiceHost host = new WebServiceHost(typeof(ProductsSalesService.ProductsSales));
Add base address new WebServiceHost plus code below:
WebChannelFactory<ProductsSalesService.IProductsSales> cf =
new WebChannelFactory<ProductsSalesService.IProductsSales>("ProductsSalesService.ProductsSales");
ProductsSalesService.IProductsSales channel = cf.CreateChannel();
See full code here - http://msdn.microsoft.com/en-us/library/bb919583

WCF HTTP 504 Error

I have the following problem. I am using Entity Framework to connect to a SQL Azure and that works(I tested it in a Test Project).
But when i try to get it through WCF RESTful service it throws Error 504.
My Operation Contract:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet(UriTemplate = "/Artikli", ResponseFormat = WebMessageFormat.Json)]
IEnumerable<Artikal> GetArtikli();
}
Implementation of [ServiceContract] :
public class Service : IService
{
public IEnumerable<Artikal> GetArtikli()
{
using (var context = new CijenolomciEntities())
{
var result = context.Artikals.ToList();
result.ForEach(a => context.Detach(a));
return result;
}
}
}
The whole thing is hosted on local IIS. I use Fiddler, an what it says when i try to reach
http://localhost:17916/Service.svc/Artikli
is
[Fiddler] ReadResponse() failed: The server did not return a response for this request.
The WCF App.Config looks like:
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="CijenolomciEntities" connectionString="My_Connection_String" providerName="System.Data.EntityClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding" />
</protocolMapping>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<!-- 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>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
EDIT:
When i try to access URL through browser i get the following:
Request Error
The server encountered an error processing the request. See server logs for more details.
Try to enable Tracing and see if your request is exceeding the default values due to which you are getting a timeout error.
Inspect the trace log for detailed error on why it is failing and then appropriately perform the needed steps to increase either the timeout values or the default size limits
If your network environment is set to make all HTTP traffic go through a proxy server then it's likely the account the IIS app pool is running under isn't allow to send HTTP traffic. As a test, change the app pool account to your login account and see if the WCF service connects successfully. The 504 message is usually a proxy or network issue.
I don't think it is the network error. The issue is in the service. Might be you receive 504 not from IIS, but from Fiddler. Read this. Might be you have to increase maxItemsInObjectGraph

WCF custom security over netTcp

I'm new to WCF and I'm making server/client application in which I need to have some user/password schema to maintain some customization settings for each client and to log who access the service, but "security" in the traffic going through the net is not really needed, since information is not sensitive.
So taking this into account I was searching for a SIMPLE way of accomplishing this but I couldn't find it.
I have a few constraints and conditions:
Windows security is not an option.
I'm using clickonce deployment, so everything should be contained
within the installation packet. I don't know the actual list of users
that are downloading it, so I don't have a way to distribute some
certificate to all users.
Also the client will be accesed within the LAN and through several
WANs. Another requirement has to be met is that the service should
have very good performance since a lot of data is flowing with each
response, so the questions is:
Does message security hurts performance notoriously?
The "manual" way would be to pass the username as a parameter for each method I'm exposing, but it seems like a very dirty solution.
It seems to me a lot of constrains to design this, so that's why I'm asking about this.
Which would be the simplest solution to accomplish this?
First of all we have to assume that all users consuming the service are in some way "registered" to use the service. Because if it is out in the open, anonymous, then there is simply no tracking. So my assumption is as follows:
The service is hosted in Windows Service/WinForms to support TCP
Endpoint. - With new versions of IIS(>6) this is not a required assumption anymore
There is a combination like "UserName/Password" to authenticate. This
is not in the active directory (not opting windows authentication)
but may be xml/database.
We are not willing to have methods like public int Add(string
User, string Password, int A, int B)
I have a service with a TCP endpoint which does something like this. I will share that. I don't claim it is the best practice.
Application name is MYAPP
I have provided
customUserNamePasswordValidatorType="MYAPPHost.Authenticate, MYAPPHost"
in
serviceCredentials > userNameAuthentication
section of web.config.
MYAPPHost is name of my windows service. Authenticate is the class which does the authentication from Database.
message clientCredentialType="UserName" is set for TCPBinding.
App.Config of my windows service:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Off" propagateActivity="true" >
<listeners>
<add name="SERVICE_MONITOR" type="System.Diagnostics.XmlWriterTraceListener"
initializeData="MYAPP_MONITOR.svclog" />
</listeners>
</source>
<source name="MYAPP_TRACE" switchValue="All" >
<listeners>
<add name="MYAPP_TRACE_LISTENER" type="System.Diagnostics.XmlWriterTraceListener"
initializeData="MYAPP_TRACE.svclog" />
</listeners>
</source>
</sources>
<trace autoflush="true" />
</system.diagnostics>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="OverAllServiceBehavior">
<serviceSecurityAudit
auditLogLocation="Application"
serviceAuthorizationAuditLevel="Failure"
messageAuthenticationAuditLevel="Failure"
suppressAuditFailure="true" />
<serviceDebug includeExceptionDetailInFaults="True" />
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
<serviceThrottling maxConcurrentCalls="10000" maxConcurrentSessions="10000">
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="MYAPPHost.Authenticate, MYAPPHost"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="OverAllEndPointBehavior" />
</endpointBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="ServiceTCPEndPointBinding" maxBufferSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxNameTableCharCount="2147483647" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" algorithmSuite="TripleDes"/>
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="OverAllServiceBehavior"
name="MiddleWare.ServiceClasses.ServiceClass">
<host>
<baseAddresses>
<add baseAddress="net.tcp://127.0.0.1:15010/ServiceTCPEndPointMEX"/>
</baseAddresses>
</host>
<endpoint address="net.tcp://127.0.0.1:15020/ServiceTCPEndPoint" contract="MiddleWare.ServiceContracts.IServiceContract" />
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
Authenticate Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IdentityModel.Selectors;
namespace MYAPPHost
{
public class Authenticate : UserNamePasswordValidator
{
public override void Validate(string UserName, string Password)
{
if (!CheckFromDB(UserName,Password))
throw new Exception("UNAUTHORIZED ACCESS!!!");
}
}
}
In Client Side,after adding reference to the WCF (SR)
SR.ServiceContractClient obj = new SR.ServiceContractClient("ServiceTCPEndPoint");
obj.ClientCredentials.UserName.UserName = "User1";
obj.ClientCredentials.UserName.Password = "Password1";
int I = obj.Add(1, 2);
If credentials are not provided, message security token error is thrown. For wrong credentials UNAUTHORIZED ACCESS occurs.

WCF 4.0, can't invoke the service

In a solution, I added a "WCF Service Library". No problem with the default method. I added one :
In the interface :
[ServiceContract]
public interface ISecurityAccessService
{
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
[OperationContract]
CompositeUser ListUser();
}
[DataContract]
public class CompositeUser
{
List<User> _listUser = new List<User>();
[DataMember]
public List<User> ListUser
{
get { return _listUser; }
set { _listUser = value; }
}
}
The interface implementation, the dataaccess iw working, I tested the DataService and no problem.
public class SecurityAccessService : ISecurityAccessService
{
public CompositeUser ListUser()
{
DataAccess.DataService service = new DataAccess.DataService();
CompositeUser compositeUser = new CompositeUser();
compositeUser.ListUser = service.ListUser();
return compositeUser;
}
}
When I execute and try to invoke, I receive this error message :
*An error occurred while receiving the HTTP response to http://localhost:8732/Design_Time_Addresses/WcfServiceLibrary/ISecurityAccessService/. 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.*
The App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<!-- 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>
<services>
<service name="WcfServiceLibrary.SecurityAccessService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8732/Design_Time_Addresses/WcfServiceLibrary/ISecurityAccessService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address ="" binding="wsHttpBinding" contract="WcfServiceLibrary.ISecurityAccessService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 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>
</behaviors>
</system.serviceModel>
</configuration>
Update 1
I made a working sample with database access. I just don't understand something in the "PersonService" class, why I have to make this loop. Solution is welcome.
Download 40ko .rar full example
your User class needs to be marked with the DataContract attribute and its methods with the DataMember attribute. It may also need to be marked as a KnownType in the CompositeUser class so that it is included in the types for the service. You can do that like so:
[DataContract]
[KnownType(typeof(User))]
public class CompositeUser
{
...
}
you'll be able to tell what the issue is from the logs. Either you'll get a 'cannot be serialized' message, in which case you need to add the [DataContract] attribute or it will be 'type was not expected' in which case you'll also need to add the [KnownType] attribute
If you enable tracing in your service you'll be able to get more details of what the problem was. Add something like this in the config file:
<configuration>
<system.diagnostics>
<trace autoflush="true"/>
<sources>
<source name="System.ServiceModel" switchValue="Verbose">
<listeners>
<add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData="D:\wcfLog.svcLog"/>
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
also setting <serviceDebug includeExceptionDetailInFaults="True" />
will allow more detail about the error to be returned in the service exception which might also help.
EDIT
From the comments below it seems the User class is a Linq to SQL generated class. I don't think you should be sending this class across the wire. WCF deals with messages not in serializing types with behaviour, so you should create a DTO which represents the data in your User class that will be needed on the client and send this DTO out from the service contract. Even if you do send the User class as it is, when it gets to the client it won't have the context to still be connected to the DB.
I faced this problem again today. A long time ago I had the same problem, but I had forgotten the cause and it took me some time to sort it out toady.
In my case, it was a looping serialization problem. One table has a column which is a foreign key to another column in the same table. So all I had to do was to click the work surface of the dbml file and change the Serialization Mode to Unidirectional.
If yours is a Linq to Sql situation, and the error message is the one shown above, you might want to check whether it is the same cause as mine.