WCF FaultException error - wcf

I'm new to WCF and I have issues throwing exceptions from my WCF Service to the client. I'm using code examples which I copied from the web. (I'm using VS2010 .NET Framework 4.0)
I created an ErrorHandler where the ProvideFault-method looks like this:
public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message msg)
{
FaultException<Exception> faultException = new FaultException<Exception>(error, error.Message, new FaultCode("Testing."));
MessageFault messageFault = faultException.CreateMessageFault();
msg = Message.CreateMessage(version, messageFault, Constants.FaultAction);
}
The fault contract looks like this:
[FaultContract(typeof(Exception), Action=Constants.FaultAction)]
The client side test code looks like this:
private void button1_Click(object sender, EventArgs e)
{
HistorianAccessServiceClient cli = new HistorianAccessServiceClient();
Tables.Batch bt = new Tables.Batch();
try
{
bt = cli.GetBatch(3241);
}
catch (FaultException<Exception> ex)
{
MessageBox.Show(ex.Message);
}
}
I noticed that if the error parameter to the ProvideFault method contains an inner exception then a System.ServiceModel.CommunicationException is thrown on the client side (!?), the inner exception is System.Net.WebException, the inner exception to that exception is System.IO.IOException and the inner exceptin to that exception is System.Net.Sockets.SocketException (Error Code 10054)?!?!
(Unfortunately I have a swedish operating system installed which means that the messages from the debugger is in swedish.)
The exception message (google translate) looks like this:
An error occurred while receiving the HTTP response to http://localhost:7070/Historian.WebAccess/HistorianAccessService. It may be that the service endpoint binding not using the http protocol. It may also be due to a context for the http request has been interrupted by the server (probably because the service is terminated). You can find more information in server logs.
If I throw an exception without an inner exception, the exception is handled by the client perfectly ok!?!?!
My configuration files looks like this (Service):
<system.serviceModel>
<bindings />
<client />
<services>
<service name="Historian.WebAccess.HistorianAccessService">
<host>
<baseAddresses>
<!--<add baseAddress="http://localhost:8732/Design_Time_Addresses/Historian.WebAccess/HistorianAccessService/"/>-->
<add baseAddress="http://localhost:7070/Historian.WebAccess/"/>
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<!--<endpoint address="HistorianAccessService" binding="wsHttpBinding" contract="Historian.WebAccess.IHistorianAccessService">-->
<endpoint address="HistorianAccessService" binding="wsHttpBinding" contract="Historian.WebAccess.IHistorianAccessService">
<!--
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="false"/>
<serviceThrottling maxConcurrentCalls="16" maxConcurrentInstances="2147483646" maxConcurrentSessions="10"/>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
<!-- 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>
Configuration file (Client):
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IHistorianAccessService" closeTimeout="00:10:00"
openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="104857600" maxReceivedMessageSize="104857600"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="104857600" maxStringContentLength="104857600" maxArrayLength="104857600"
maxBytesPerRead="104857600" maxNameTableCharCount="104857600" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:7070/Historian.WebAccess/HistorianAccessService"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IHistorianAccessService"
contract="HistorianAccessHost.IHistorianAccessService"
name="WSHttpBinding_IHistorianAccessService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Does anyone out there recognize this phenomenon and the solution to it?!
I'd be greatful for all the help I can get!

The solution is to not attempt to pass .NET Exception objects back to the client. This limits you to clients running .NET.
In fact, it limits you to running clients which know about all of the exceptions that you might throw. What if you add a new MyNewException on the server, and throw it back to the client? The client will need to have the assembly containing that exception in order for it to be deserialized at all.

I think you're being too fancy for what you're trying to do. If you're just trying to throw FaultException, just do new FaultException(error). You have to do a bit more work if you're throwing a custom fault type, but none of that message stuff is necessary. Here's a VB example I found:
Public Function DoSomething() As Data()
Try
DoSomething()
Catch ex As Exception
Throw New FaultException(ex.Message)
End Try
End Function
If you're throwing a custom type of fault (like say PermissionDenied or such), you need to create an object for that, which is a bit more work.
You also want to be careful what you're returning here. Sending back a lot of details like stack traces to the client can help an attacker trying to break into the system, and isn't a lot of use to your standard end user. You should log that on the server instead.

Related

WCF This could be due to the service endpoint binding not using the HTTP protocol

Default.aspx.cs
WCFService.Service1Client client = new WCFService.Service1Client();
string stream = client.JsonSerializeFromDatabase();
client.Close();
WCFService.Service1Client client2 = new WCFService.Service1Client();
foreach (WCFService.Person in client2.JsonDeserializeFromDatabase(stream))
Service1.svc.cs
public IList<Person> JsonDeserializeFromDatabase(string value)
{
MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(value));
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<Person>));
IList<Person> tableData = (IList<Person>)ser.ReadObject(ms);
ms.Close();
ms.Dispose();
return tableData;
}
IService1.cs
[OperationContract]
IList<Person> JsonDeserializeFromDatabase(string value);
Server Web.config
<httpRuntime maxRequestLength="8192"/>
</system.web>
...
<system.serviceModel>
<services>
<service name="TestWCF.Service1" behaviorConfiguration="TestWCF.Service1Behavior">
<endpoint address="" binding="wsHttpBinding" contract="TestWCF.IService1">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TestWCF.Service1Behavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</serviceBehaviors>
Client Web.config
<httpRuntime maxRequestLength="8192"/>
</system.web>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="debuggingBehaviour">
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1" closeTimeout="00:50:00" openTimeout="00:50:00" receiveTimeout="00:50:00" sendTimeout="00:50:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="64" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<reliableSession ordered="true" inactivityTimeout="00:50:00" enabled="false"/>
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="~~~~~/Service1.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1" contract="WCFService.IService1" name="WSHttpBinding_IService1" behaviorConfiguration="debuggingBehaviour">
Exception Information
- Type: System.ServiceModel.CommunicationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- Message: An error occurred while receiving the HTTP response to ~~~~~/Service1.svc. 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.
I got this exception information from Server trace viewer, so please do not advise me to put <-system.diagnostics-> tag.
As you can see, I increased all the size thing.
Like.. i don't know why I am getting an error when I call JsonDeserializeFromDatabase(stream).
"An error occurred while receiving the HTTP response to ~~~~~/Service1.svc. 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."
I too have experienced this error message when returning records from a database in a WCF service. As well as increasing maxReceivedMessageSize in the binding in the client configuration (App.config), a separate problem seems to be that WCF has problems serializing Entity Framework objects if they have relationships that lead to circularity in their object graphs.
I solved this by returning buddy class objects (which are copies of the raw database records, but without any relationship links) rather than the raw database classes themselves.
Hope this helps -
And WHY doesn't Microsoft produce better error messages?? Here, as in many other cases, the error message gives no clue to the real problem (the serialization of the return value from the WCF call)!
re: WCF & problems serializing Entity Framework objects if they have relationships that lead to circularity in their object graphs. I was getting the same error and the answer provided by user1956642 and it did point me in the right direction, but later realized I could serialize these entities by configuring the DbContext
context.Configuration.ProxyCreationEnabled = false;
Lazy loading is still enabled, but I believe the dynamic proxies are used for change tracking and lazy loading. So yea ... just my 5c

Using wsHttpBinding

After reading more about it and trying to implement wshttpbinding, it just won't happen. No matter what I try, I keep getting the below error message (with security mode commented out). I understand why because of the different SOAP versions between bindings.
"(415) Cannot process the message because the content type 'application/soap+xml; charset=utf-8' was not the expected type 'text/xml; charset=utf-8'"
I read more about the TransportWithMessageCredentials at the following link:
http://msdn.microsoft.com/en-us/library/ms789011.aspx
but still could not get it to work.
I can use basicHttpBinding just fine for internal apps and works great (if I don't include any transactions), but my application in the WCF layer still needs to support transactions (see below), from which I understand that basicHttpBinding doesn't support, because it doesn't contain the transactionflow attribute.
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required))
When I try and run the below with the security mode included, the svc config editor doesn't even start up and throws the following error: "System.InvalidOperationException: Could not find a base address that matches scheme https for the endpoint with binding WSHttpBinding. Registered base address schemes are [http]."
I know it's expecting some kind of SSL/https security, but my website (as you can see below is http) . That would be fine for the public facing websites, but for internal sites, for now, all I want to do is have support for transactions.
Here is my server side setup for wsHttpBinding:
<bindings>
<wsHttpBinding>
<binding name="WsHttpBinding_IYeagerTechWcfService" closeTimeout="00:02:00" openTimeout="00:02:00" receiveTimeout="24.20:31:23.6470000" sendTimeout="00:10:00" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" transactionFlow="true">
<security mode="Transport" >
<transport clientCredentialType = "Windows" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<?xml version="1.0"?>
<services>
<clear />
<service name="YeagerTechWcfService.YeagerTechWcfService">
<endpoint address="" binding="wsHttpBinding" contract="YeagerTechWcfService.IYeagerTechWcfService" >
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://abc.com/yeagerte/YeagerTechWcfService.YeagerTechWcfService.svc" />
</baseAddresses>
</host>
</service>
</services>
Here is my client side setup:
<?xml version="1.0"?>
<client>
<endpoint address="http://abc.com/yeagerte/YeagerTechWcfService.YeagerTechWcfService.svc"
binding="wsHttpBinding" contract="YeagerTechWcfService.IYeagerTechWcfService"
name="WsHttpBinding_IYeagerTechWcfService" />
</client>
Could somebody please provide the following:
Is there another way to support transactions in WCF for basicHttpBinding or any other way for that matter?
If so, how do I implement it?
If not, what are my options?
For the above question, I may have figured out an answer but want to run it by somebody more experienced in this matter.
Instead of having the WCF layer handle the transactions (like mentioned above), I propose I use basicHttpBinding and the following code in my Controller when it passes the data to the WCF layer:
// method here
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required))
{
db.EditCategory(cat);
// the above code would execute the EditCategory method below in the WCF layer and keep the transaction alive ts.Complete();
ts.Dispose();
}
return Json(new GridModel(db.GetCategories()));
// end method
WCF layer:
public void EditCategory(Category cat)
{
try
{
using (YeagerTechEntities DbContext = new YeagerTechEntities())
{
Category category = new Category();
category.CategoryID = cat.CategoryID;
category.Description = cat.Description;
// do another db update here or in another method...
DbContext.Entry(category).State = EntityState.Modified;
DbContext.SaveChanges();
}
}
catch (Exception ex)
{
throw ex;
}
}
For public facing websites using SSL, how do I properly implement wsHttpBinding?
I encountered the same problem when using WCF Transactions
I used Message security with Windows authentication and did not have to setup any certificates.
<wsHttpBinding>
<binding name="WSHttpBinding_Transactional"
transactionFlow="true">
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None" />
</security>
</binding>
</wsHttpBinding>

Hosted WCF Service Hangs after the weekend

We have a WCF service hosted in a windows service which hangs after long periods of inactivity: ie after the weekend.
This behavior happens at different locations.
The service uses WSHttpBinding which is set to use transport security a Custom serviceAuthorization authorizationPolicy which uses windows authentication.
The Spring framework is used. Spring.ServiceModel.Activation.ServiceHostFactory creates the Service hosts.
Service throttle is set to 200 sessions, instances and calls. There are at most 15 users of the system.
Tracing is enabled and set to Warning which should let me know about throttle issues.
There are no messages in the service trace log.
There are no messages in the Event log which look relevant.
There are no relevant logs in HTTPPerf logs.
We log considerably in the server side application but there is no activity being recorded when the system hangs.
It is a total black box when the system hangs.
The client fails with the following message.
08:13:32.014 [1] ERROR App - System.TimeoutException: Client is unable to finish the security negotiation within the configured timeout (00:00:59.9941374). The current negotiation leg is 1 (00:00:59.9863206). ---> System.TimeoutException: The request channel timed out while waiting for a reply after 00:00:59.9628702. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout. ---> System.TimeoutException: The HTTP request to 'http://localhost:8080/OrderManagementService.svc' has exceeded the allotted timeout of 00:00:59.9690000. The time allotted to this operation may have been a portion of a longer timeout. ---> System.Net.WebException: The operation has timed out
at System.Net.HttpWebRequest.GetResponse()
I have spent many hours searching for relevant information on this.
I do not think this is related to inactivity timeout as this should be recorded in the trace log.
Only thing that I can think of is related to Active Directory credential caching or something of that nature or that it is related to the use of the Spring framework.
Any help would be greatly, greatly appreciated.
Am thinking of moving away from WSHttpBinding or WCF altogether as this is an unacceptable situation.
Service side configuration is as follows.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false" maxBufferPoolSize="2147483646" maxReceivedMessageSize="2147483646">
<readerQuotas maxDepth="2147483646" maxStringContentLength="2147483646" maxArrayLength="2147483646" maxBytesPerRead="2147483646" maxNameTableCharCount="2147483646" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
<security>
<transport></transport>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="Kodi.Kodiak.Security.AuthorizationPolicy, Kodi.Kodiak.Security" />
</authorizationPolicies>
</serviceAuthorization>
<serviceCredentials>
<windowsAuthentication includeWindowsGroups="true" allowAnonymousLogons="false" />
</serviceCredentials>
<serviceThrottling maxConcurrentCalls="200" maxConcurrentSessions="200" maxConcurrentInstances="200" />
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="rest">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ServiceBehavior" name="OrderManagementService">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding" contract="Kodi.Kodiak.Services.ServiceContracts.IOrderManagementService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
SPRING CONFIG
<object id="OrderManagementService"
singleton="false"
type="Kodi.Kodiak.Services.OrderManagementService, Kodi.Kodiak.Services"
scope="session">
</object>
How the clients are calling the service? If they are calling the service through the SvcUtil generated proxy; are they closing the proxy connection properly? I think the clients are not closing the connections or simply the connections are not getting closed properly.
One important thing is, you should avoid using using statement while creating proxies.
A better approach would be something like this,
ServiceClient client = null;
try
{
client = new ServiceClient();
client.CallMethod();
}
finally
{
client.CloseConnection(); // extension method
}
public static void CloseConnection(this ICommunicationObject client)
{
if (client.State != CommunicationState.Opened)
{
return;
}
try
{
client.Close();
}
catch (CommunicationException)
{
client.Abort();
throw;
}
catch (TimeoutException)
{
client.Abort();
throw;
}
catch (Exception)
{
client.Abort();
throw;
}
}
I think this can be done by maintaining the client and server Binding End Points and Behavior same, the timeout values specified in the Client and Server Configs Should be Same.

Wcf Basic authentication

Having some trouble using basic authentication with a simple test Wcf service. I am getting an exception:
The requested service, 'http://qld-tgower/test/Service.svc' could not be activated. See the > server's diagnostic trace logs for more information.
And in the trace log it shows:
The authentication schemes configured on the host ('Basic') do not allow those configured on the binding 'BasicHttpBinding' ('Anonymous'). Please ensure that the SecurityMode is set to Transport or TransportCredentialOnly. Additionally, this may be resolved by changing the authentication schemes for this application through the IIS management tool, through the ServiceHost.Authentication.AuthenticationSchemes property, in the application configuration file at the <serviceAuthenticationManager> element, by updating the ClientCredentialType property on the binding, or by adjusting the AuthenticationScheme property on the HttpTransportBindingElement.
But what I don understand it when I us the incorrect username and password it says it IS using basic authentication?
The HTTP request is unauthorized with client authentication scheme 'Basic'. The authentication header received from the server was 'Basic realm="qld-tgower"'.
This is my web.config details
<system.serviceModel>
<services>
<service name="WcfService"
behaviorConfiguration="Behavior">
<endpoint address="http://QLD-TGOWER/test/Service.svc"
binding="basicHttpBinding"
bindingConfiguration="httpBinding"
contract="IService" />
</service>
</services>
<diagnostics>
<endToEndTracing activityTracing="false" messageFlowTracing="true" propagateActivity="true"></endToEndTracing>
</diagnostics>
<bindings>
<basicHttpBinding>
<binding name="httpBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" proxyCredentialType="Basic">
</transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<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="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
and this is my App.config
<system.serviceModel>
<diagnostics>
<endToEndTracing activityTracing="true" />
<messageLogging logMessagesAtTransportLevel="true" />
</diagnostics>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService" >
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" proxyCredentialType="Basic"></transport>
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://QLD-TGOWER/test/Service.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference1.IService"
name="BasicHttpBinding_IService" />
</client>
</system.serviceModel>
my test application
private static void Main(string[] args)
{
var proxy = new ServiceClient("BasicHttpBinding_IService");
var clientCredentials = proxy.ClientCredentials;
clientCredentials.UserName.UserName = "username";
clientCredentials.UserName.Password = "password";
var res = proxy.GetData(1);
Console.WriteLine(res);
Console.WriteLine("Done");
Console.ReadKey(true);
}
And my service
public class Service : IService
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
Is there something that I am missing here?
Change the name and contract of the service to include the namespace.
Also, remove the endpoint address (set it to "") and don't include proxyCredentialType in the transport tag.
End result of the web.config should look something like this
<system.serviceModel>
<services>
<service name="MyNameSpace.MyService" behaviorConfiguration="asdf">
<endpoint address="" binding="basicHttpBinding"
bindingConfiguration="httpBinding" contract="MyNameSpace.IMyService" />
</service>
</services>
<diagnostics>
<endToEndTracing activityTracing="true" messageFlowTracing="true"
propagateActivity="true">
</endToEndTracing>
</diagnostics>
<bindings>
<basicHttpBinding>
<binding name="httpBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="asdf">
<!-- 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>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false"/>
</system.serviceModel>
Try for both client and server configs
<basicHttpBinding>
<binding name="BasicHttpBinding_IService">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
Install/Enable basic authentication
You may also need to install and apply basic authentication in IIS.
Goto "Programs and Features" / "Turn windows features on/off ".
Enable "basic authentication" somewhere under IIS and security.
I closed and opened the IIS console and was able to enable it under authentication settings.
This of course if for a development testing and it warns you about not having an SSL certificate.
You're not allowed to use username authentication over an unsecured connection
You can secure the message by using a secure transport (e.g. SSL) or message encryption (using certificates)
I have used ClearUsernameBinding in the past to great success, but I don't recommend it in production. I used it so that I could keep all my authentication code the same without requiring SSL in dev/test environments, but having it work with SSL by changing the configuration only.
Note: that custom binding isn't perfect, and I had to change it a bit to enable certain configuration changes.
This is what solved the issue for me:
<bindings>
<basicHttpBinding>
<binding>
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
For reference see:
https://msdn.microsoft.com/en-gb/library/ff648505.aspx

WCF: Cannot find my custom validator specified in web.config - customUserNamePasswordValidatorType - - Could not load file or assembly ... - help?

So I've basically got everything up and running with wsHttpBindings and my WCF service using custom authentication over HTTPS.
The issue I'm having is with the customUserNamePasswordValidatorType:
<serviceCredentials>
<!-- Use our own custom validation -->
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/>
</serviceCredentials>
Following directions found here I've created my custom class as well:
namespace CustomValidator
{
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!AuthenticateUser(userName, password))
throw new SecurityTokenValidationException("Invalid Credentials");
The error is "Could not load file or assembly 'CustomValidator' or one of its dependencies. The system cannot find the file specified.", and refers to the tail end of customUserNamePasswordValidatorType - "..., CustomValidator".
I didn't think it was a problem having my custom validator in its own namespace and class, but I can't see what else to do to make this work.
I've tried with/without the namespace at the beginning, swapping, etc - nothing.
Hoping another pair of eyes can pick this out.
Thanks.
EDIT
system.serviceModel
<system.serviceModel>
<bindings>
<!-- wsHttpBinding -->
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
<!-- webHttpBinding -->
<webHttpBinding>
<binding name="wsHttps" >
<security mode="Transport"/>
</binding>
</webHttpBinding>
<!-- Basic binding -->
<basicHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<message clientCredentialType="UserName"/>
<!-- transport clientCredentialType="None"/-->
</security>
</binding>
</basicHttpBinding>
<!-- customBinding>
<binding name="WebHttpBinding_IService">
textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap12" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpsTransport manualAddressing="false"/>
</binding>
</customBinding -->
<!-- Another custom binding -->
<customBinding>
<binding name="CustomMapper">
<webMessageEncoding webContentTypeMapperType=
"IndexingService.CustomContentTypeMapper, IndexingService" />
<httpTransport manualAddressing="true" />
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
<services>
<service behaviorConfiguration="ServiceBehavior" name="Service">
<!-- Service Endpoints -->
<!-- since we're hosting in IIS, baseAddress is not required
<host>
<baseAddresses>
<add baseAddress="https://mysslserver.com/Service.svc"/>
</baseAddresses>
</host>
-->
<endpoint address="https://mysslserver.com/Service.svc"
binding="wsHttpBinding"
bindingConfiguration="wsHttpEndpointBinding"
contract="IService"
name="wsHttpEndpoint">
<!--
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="https://mysslserver.com"/>
</identity-->
</endpoint>
<!-- endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/ -->
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<!-- Setup Security/Error Auditing -->
<serviceSecurityAudit auditLogLocation="Application"
suppressAuditFailure="false"
serviceAuthorizationAuditLevel="Failure"
messageAuthenticationAuditLevel="Failure" />
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"
httpsGetUrl="https://mysslserver.com/Service.svc"/>
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<!-- Use our own custom validation -->
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<!-- serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpsGetEnabled="true"
httpsGetUrl="https://mysslserver.com/Service.svc" />
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-->
</behaviors>
</system.serviceModel>
I decided to give it another stab, and didn't like having my custom validator in another lib.
So I created a new class in App_Code, and went at it...
The following is what actually fixed it,
="CustomValidator.CustomUserNameValidator, App_Code"
When you refer to the custom validator with the values
="CustomValidator.CustomUserNameValidator, CustomValidator"
The first value is the type name and the second is the name of the assembly
in which to find the type. So I would suggest that in your first instance
your service is actually in some other assembly such as MyService
In that case you really needed your config file to say
="CustomValidator.CustomUserNameValidator, MyService"
I suspect that when you have created your new class library for your
validator, you have called your project CustomValidator (which will
output an assembly called CustomValidator.dll), and hence now your
config will work (i.e. it has nothing to do with being in a separate
class library - it just happens that the naming of your assembly
reference in the web.config is now valid)
Seems a bit strange, but the solution was to create a separate class library and make reference to its DLL in my WCF service.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.ServiceModel;
/// <summary>
/// Summary description for CustomUsernamePasswordValidator
/// </summary>
namespace CustomValidator
{
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (!AuthenticateUser(userName, password))
throw new SecurityTokenValidationException("Invalid Credentials");
else
{
// do nothing - they're good
}
}
public bool AuthenticateUser(string userName, string password)
{
if (userName != "userbill" || password != "passwordbill")
{
return false;
}
else
{
return true;
}
}
}
}
I then made added a reference to System.IdentityModel and System.ServiceModel.
The serviceCredentials section for the WCF service is now changed to this:
<serviceCredentials>
<!-- Use our own custom validation -->
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="CustomValidator.CustomUserNameValidator, CustomValidator"/>
</serviceCredentials>
Hope that helps someone.
I tried this with invalid credentials, and was expecting to see my "Invalid Credentials" message. Instead I'm getting "At least one security token in the message could not be validated."
Other than that this thing is finally up and running!
Just reading this as it was helpful for a POC I had to get going quickly. In response to ELHaix above...this should work to ensure your descriptive custom error is returned back to the client:
using System.ServiceModel
...
throw new FaultException("Invalid Credentials - Custom Error");