I am trying to get my webservice to reply with a particular form of XML, which I thought I could do with just putting the data in a string and returning this to the webpage.
I am trying to return:
<tradeHistory><trade TradeId="1933" ExtId="1933" instrument="EUA" quantity="1500" setType="Escrow" TradeDate="12/02/2010" DeliveryDt="13/02/2010" PaymentDt="12/02/2010" type="BUY" pricePerUnit="6.81" GrossConsid="10320" currency="EUR"/></tradeHistory>
But when I return the string I'm getting:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"><tradeHistory><trade tradeid="1933" ExtId="1933" Instrument="EUA" quantity"1500" setType="Escrow" TradeDate="24/05/2011" DeliveryDt="25/05/2011" PaymentDt="25/05/2011" type"BUY" pricePerUnit="6.81" GrossConsid="10320" currency="EUR" /><tradeHistory></string>
Any ideas on how I can achieve this goal? It would be nice not to have the tag but I can live with that but the issue I have is that its not formatting the string correctly its reading the opening and closing tags as special characters
My Service is:
<ServiceContract(Namespace:="")>
Public Interface ITradePortal
<WebGet(UriTemplate:="Reporting/GetClientTrades/{ClientID}")>
<OperationContract()>
Function GetClientTrades(ByVal ClientID As String) As String
End Interface
My implementation is:
<ServiceBehavior(ConcurrencyMode:=System.ServiceModel.ConcurrencyMode.Multiple, InstanceContextMode:=InstanceContextMode.Single, _
Namespace:="")>
<XmlSerializerFormat()>
and my config file:
<services>
<service behaviorConfiguration="Default" name="CFP_Web_Lib.TradePortal">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8686/TradePortal"/>
</baseAddresses>
</host>
<endpoint address="" binding="webHttpBinding"
contract="CFP_Web_Lib.ITradePortal"
behaviorConfiguration="web"
/>
<endpoint address="Operations/" binding="wsDualHttpBinding"
contract="CFP_Web_Lib.ITradeOperations"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_IPubSubService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsDualHttpBinding>
<mexHttpBinding>
<binding name="NewBinding0" />
</mexHttpBinding>
</bindings>
The default return format is XML, so when your operation returns String, it will be formatted as XML - with the string content inside the element. The easiest way to return anything would be to use the raw programming model. Your operation would look something like this:
<WebGet(UriTemplate:="Reporting/GetClientTrades/{ClientID}")> _
<OperationContract()> _
Function GetClientTrades(ByVal ClientID As String) As Stream
And the implementation:
Function GetClientTraces(ByVal ClientID As String) As Stream Implements ITradePortal.GetClientTraces
Dim result as String = "<tradeHistory>...</tradeHistory>"
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml" ' or anything you need
return new MemoryStream(Encoding.UTF8.GetBytes(result))
End Function
Another option, if you don't want to deal with Streams, is to change the return type to XmlElement (or XElement). That is written out "as is", so you can return arbitrary XML.
Yet another option is to create classes to hold that data. The TradeHistory class would hold a reference to a "Trade" instance, and the Trade class would have many fields declared with the attribute. The operation would then have a return type of TradeHistory.
Related
I am using a CustomUserNamePasswordValidator for my WCF web service. However, i am trying to add a IsAlive operation, which should be able to be called from clients, even when not authenticated.
For example, i want to be able to do a check, if a service is online and accessible on startup, so i can notify the user on missing inet connection or a not available service (due to maintenance).
I have code for all this already in place. What i am missing is how i can access the operation without passing a username and password.
I could probably just add a second service which allows anon access, but i'd really prefer to use the existing service.
The Validator is implemented like this (i ommited the actual checking code):
public sealed class MyCredentialValidator : UserNamePasswordValidator
{
public MyCredentialValidator ()
{
}
public override void Validate(string userName, string password)
{
Debug.WriteLine("MyCredentialValidator : Validate called.");
// do some checks
var isValid = CheckCredentials(userName, password)
if(!isValid)
{
throw new FaultException(...);
}
}
}
It is registered in the web.config like so:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyCredentialValidator,..."/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
<bindings>
<wsHttpBinding>
<binding name="SecureBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxStringContentLength="2147483647"/>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="my service" behaviorConfiguration="SecureBehavior">
<endpoint address="" binding="wsHttpBinding" contract="my contract" bindingConfiguration="SecureBinding">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
client side configuration:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="SecureBinding"
closeTimeout="00:10:00"
openTimeout="00:10:00"
receiveTimeout="00:10:00"
sendTimeout="00:10:00"
maxReceivedMessageSize="2147483647">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
<readerQuotas maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxStringContentLength="2147483647"/>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://my service url"
contract="my contract"
binding="wsHttpBinding"
bindingConfiguration="SecureBinding"
name="secure" />
</client>
</system.serviceModel>
client side wcf call code:
var cf = new ChannelFactory<my contract>("secure");
using (IClientChannel channel = (IClientChannel)cf.CreateChannel())
{
channel.OperationTimeout = TimeSpan.FromSeconds(3);
bool success = false;
try
{
channel.Open();
result = ((my contract)channel).IsAlive();
channel.Close();
success = true;
}
finally
{
if (!success)
{
channel.Abort();
}
}
}
I have done something like this before,
depending on how you have integrated your custom validator in the wcf pipleline,
you could simply before you do the actual validation, which I guess returns something like true or false, you could check the incoming url or address and see if it is going to be going to your IsAlive operation, if that is the case, you could simply do a early return true.
Wcf has a few ways with which you can check what operation the client has called.
to be more accurate, I would need to know how you wrote your custom validator and where in the pipeline it integrates.
I am trying to integrate with the DocuSign Connect service. I've setup a WCF service to handle this, but so far have had no luck receiving the DocuSignEnvelopeInformation object properly.
I believe it is related to the issue that Mark Bailey posted about back in December: Why is my WCF web service presenting this object in a different namespace with different field names?. However as you will see in my code, I have already marked the DocuSignConnectUpdate method with [XmlSerializerFormat] in the interface. Is there something else I'm missing?
My Interface:
<ServiceContract(Namespace:="http://www.docusign.net/API/3.0")>
Public Interface IDSConnectService
<OperationContract()>
<XmlSerializerFormat()>
Function DocuSignConnectUpdate(ByVal DocuSignEnvelopeInformation As DocuSignEnvelopeInformation)As String
End Interface
My Class:
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)>
<ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any, Namespace:="http://www.docusign.net/API/3.0")>
Public Class DSConnectService
Implements IDSConnectService
Public Function DocuSignConnectUpdate(ByVal DocuSignEnvelopeInformation As DocuSignEnvelopeInformation) As String Implements IDSConnectService.DocuSignConnectUpdate
If Not DocuSignEnvelopeInformation Is Nothing Then
...........
Return DocuSignEnvelopeInformation.EnvelopeStatus.EnvelopeID
Else
Return "No Envelope Information Received"
End If
End Function
The DocuSignConnectUpdate always returns "No Envelope Information Received" when publishing EnvelopeInformation through the DocuSign Connect Service (but works fine for my local test client).
My web.config settings:
......
<system.serviceModel>
<services>
<service name="MyService.DSConnectService" behaviorConfiguration="MyBehavior" >
<endpoint address=""
binding="basicHttpBinding"
contract="MyService.IDSConnectService"/>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="xmlEndpointBehavior">
<webHttp helpEnabled="true" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"
textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true"
messageEncoding="Text">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
EDIT:
Here is an example of the XML that is being sent by DocuSign and my test client (I copied the xml from the Connect logs and used it in my client request).
<?xml version="1.0" encoding="UTF-8"?>
<DocuSignEnvelopeInformation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.docusign.net/API/3.0">
<EnvelopeStatus>
<RecipientStatuses>
<RecipientStatus>
<Type>Signer</Type>
<Email>role99#email.com</Email>
<UserName>Producer Name</UserName>
<RoutingOrder>1</RoutingOrder>
<Sent>2014-09-04T09:51:52.107</Sent>
<Delivered>2014-09-04T09:55:26.62</Delivered>
<Signed>2014-09-04T09:55:26.62</Signed>
<DeclineReason xsi:nil="true"/>
<Status>Completed</Status>
<RecipientIPAddress>255.255.255.255</RecipientIPAddress>
<ClientUserId>99</ClientUserId>
<CustomFields/>
<AccountStatus>Active</AccountStatus>
<RecipientId>276567ad-763a-45e5-a5b2-38572dfa6bb8</RecipientId>
</RecipientStatus>
</RecipientStatuses>
<TimeGenerated>2014-09-04T09:55:46.5725646</TimeGenerated>
<EnvelopeID>01f83c1a-135f-438f-87cc-57ce74aba050</EnvelopeID>
<Subject>Russell Test Signing your Application</Subject>
<UserName>Russell Test</UserName>
<Email>my#email.com</Email>
<Status>Completed</Status>
<Created>2014-09-04T09:51:51.793</Created>
<Sent>2014-09-04T09:51:52.153</Sent>
<Delivered>2014-09-04T09:55:26.683</Delivered>
<Signed>2014-09-04T09:55:26.683</Signed>
<Completed>2014-09-04T09:55:26.683</Completed>
<ACStatus>Original</ACStatus>
<ACStatusDate>2014-09-04T09:51:51.793</ACStatusDate>
<ACHolder>Russell Test</ACHolder>
<ACHolderEmail>my#email.com</ACHolderEmail>
<ACHolderLocation>DocuSign</ACHolderLocation>
<SigningLocation>Online</SigningLocation>
<SenderIPAddress>255.255.255.255 </SenderIPAddress>
<EnvelopePDFHash/>
<CustomFields>
</CustomFields>
<AutoNavigation>true</AutoNavigation>
<EnvelopeIdStamping>true</EnvelopeIdStamping>
<AuthoritativeCopy>false</AuthoritativeCopy>
<DocumentStatuses>
<DocumentStatus>
<ID>1</ID>
<Name>TestForm1</Name>
<TemplateName/>
<Sequence>1</Sequence>
</DocumentStatus>
<DocumentStatus>
<ID>2</ID>
<Name>TestForm2</Name>
<TemplateName/>
<Sequence>2</Sequence>
</DocumentStatus>
<DocumentStatus>
<ID>3</ID>
<Name>TestForm3</Name>
<TemplateName/>
<Sequence>3</Sequence>
</DocumentStatus>
<DocumentStatus>
<ID>4</ID>
<Name>Signed-on-Paper_276567ad-763a-45e5-a5b2-38572dfa6bb8</Name>
<TemplateName/>
<Sequence>4</Sequence>
</DocumentStatus>
</DocumentStatuses>
</EnvelopeStatus>
</DocuSignEnvelopeInformation>
Any suggestions?
Try the following decorators, where your_descriptor can be something generic for all your services or more specific.
http://your_domain/your_descriptor")>
Public Interface IDSConnectService
[OperationContract(Action = "http://your_domain/your_descriptor/DocuSignConnectUpdate",
ReplyAction = "http://your_domain/your_descriptor/DocuSignConnectUpdateResponse"
)]
Function DocuSignConnectUpdate(ByVal DocuSignEnvelopeInformation As DocuSignEnvelopeInformation)As String
(no decorators or use the namespace above)
Public Class DSConnectService
Implements IDSConnectService
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
Trying to configure an SSL endpoint for a self-hosted WCF service on Windows XP. My configuration works fine on Windows 7; but Windows XP, using the same certificate, doesn't respond. I get a server not found error.
When I run netstat -an, I can see that the service is listening on port 443. There are no conflicting applications listening on the port and the firewall is off.
Has anyone seen this before? Any ideas on how to resolve?
Running httpcfg query ssl yields the following:
C:\Documents and Settings\Kane>httpcfg query ssl
IP : 0.0.0.0:443
Hash : 4857fcdc71a69b8df67bb7cb7c6fb1073a08f23
Guid : {00000000-0000-0000-0000-000000000000}
CertStoreName : (null)
CertCheckMode : 0
RevocationFreshnessTime : 0
UrlRetrievalTimeout : 0
SslCtlIdentifier : (null)
SslCtlStoreName : (null)
Flags : 0
------------------------------------------------------------------------------
IP : 0.0.0.0:8443
Hash : 4857fcdc71a69b8df67bb7cb7c6fb1073a08f23
Guid : {00000000-0000-0000-0000-000000000000}
CertStoreName : (null)
CertCheckMode : 0
RevocationFreshnessTime : 0
UrlRetrievalTimeout : 0
SslCtlIdentifier : (null)
SslCtlStoreName : (null)
Flags : 0
------------------------------------------------------------------------------
Below is my config file:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
</system.web>
<system.serviceModel>
<protocolMapping>
<add binding="webHttpBinding" scheme="http"/>
</protocolMapping>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="false"/>
<services>
<service name="SomeWindowsService.SomeService" behaviorConfiguration="webServiceBehaviorConfig">
<host>
<baseAddresses>
<add baseAddress="http://*:8080/"/>
<add baseAddress="https://*/ssl/"/>
</baseAddresses>
</host>
<!-- this endpoint is exposed at the base address provided by host: http://localhost:8080/someservice -->
<endpoint address="" binding="webHttpBinding" behaviorConfiguration="WebHttpEndPointBehaviour" contract="SomeWindowsService.IFileAccessService"/>
<endpoint name="someservice" address="someservice" binding="basicHttpBinding" bindingConfiguration="soapBindingConfig" contract="someservice"/>
<endpoint name="someserviceSSL" address="ssl/someservice" binding="basicHttpBinding" bindingConfiguration="sslBindingConfig" contract="someservice"/>
<endpoint address="mex" binding="mexHttpBinding" name="MetadataBinding" contract="IMetadataExchange"/>
</service>
</services>
<!--Bindings-->
<bindings>
<basicHttpBinding>
<binding name="soapBindingConfig" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="None"/>
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647" />
</binding>
<binding name="sslBindingConfig" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="Transport"/>
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<!--Behaviors-->
<behaviors>
<serviceBehaviors>
<behavior name="webServiceBehaviorConfig">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true" httpGetUrl="mex" httpsGetEnabled="true" httpsGetUrl="mex" />
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="WebHttpEndPointBehaviour">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/><AutoStartTerminals>false</AutoStartTerminals></startup></configuration>
Ok, so to understand what was causing this problem I had to first turn on schannel error logging (http://support.microsoft.com/kb/260729).
Under: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL, I added a new reg DWORD: EventLogging with value 7. Then restart the machine.
Then looking at the logs, I saw error:
Event Type: Error
Event Source: Schannel
Event Category: None
Event ID: 36870
Date: 8/29/2013
Time: 8:03:07 PM
User: N/A
Computer: DEVELOPMENT
Description:
A fatal error occurred when attempting to access the SSL server credential private key. The error code returned from the cryptographic module is 0x80090016.
For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
This error led me to the following article: http://support.microsoft.com/kb/939616 after searching google for: "a fatal error 0x80090016"
I re-imported the certificate and the problem was resolved.
The key was getting logging out of Windows. It was the logging that alerted me to the certificate issue.
Server:
<system.serviceModel>
<services>
<service name="Service" behaviorConfiguration="md">
<!-- Service Endpoints -->
<endpoint address="SslService" binding="basicHttpBinding" bindingConfiguration="security" contract="IService"/>
<host>
<baseAddresses>
<add baseAddress="https://pc:8080/Service.svc"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="security">
<security mode="Transport">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="md">
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="ClassLibrary1.CustomUserNameValidator, ClassLibrary1" />
</serviceCredentials>
<serviceMetadata httpsGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
ClassLibrary1.CustomUserNameValidato:
public class CustomUserNameValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (userName != "111" || password != "111")
{
throw new System.ServiceModel.FaultException("Unknown username or incorrect password");
}
}
}
Client:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType="Basic" realm="">
<extendedProtectionPolicy policyEnforcement="Never" />
</transport>
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://pc:8080/Service.svc/SslService" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService" contract="ServiceReference1.IService"
name="BasicHttpBinding_IService" />
</client>
</system.serviceModel>
ServiceReference1.ServiceClient s = new WindowsFormsApplication1.ServiceReference1.ServiceClient();
s.ClientCredentials.UserName.UserName = "111";
s.ClientCredentials.UserName.UserName = "111";
MessageBox.Show(s.GetData(3)); // <---- ERROR
The HTTP request is unauthorized with client authentication scheme 'Basic'. The authentication header received from the server was 'Basic realm="pc"'.
I had created a client like this:
using (var client = new Client())
{
client.ClientCredentials.UserName.UserName = <username>;
client.ClientCredentials.UserName.Password = **<WRONG_PASSWORD>**;
...
}
The security section of my binding looked like this:
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType="Basic" realm="" />
</security>
And I saw this error come back. Once I corrected the password, everything worked.
I'm assuming you are hosting your servicehost on the IIS. Then the problem is that the IIS intercepts the https request and performs IIS-level authentication before the WCF framework and your custom validator has a chance to kick in.
In your example, the IIS will actually look for a local user '111' with password '111' on the server running the IIS. Try creating this user on the server, and you will probably get a different result.
One solution is to host your WCF servicehost somewhere else, for example in a Windows Service. Another solution is to change your security scheme to TransportWithMessageCredential. Finally, you could check this OSS http module out: Custom Basic Authentication for IIS - seems to do the trick we need.
Try to send username and password not in http with basic authentication (this can embarrass IIS), but only in soap-message headers with following scheme:
<binding name="...">
<security mode="TransportWithMessageCredential" >
<message clientCredentialType="UserName" />
</security>
</binding>
How to: Use Transport Security and Message Credentials
Maybe you also need to additionally specify <transport clientCredentialType="None">
I posted an answer here: Can not call web service with basic authentication using WCF
transport clientcredentialType is TransportCredentialOnly
Looks like you set the user name twice instead of the user name and password.
When you have basic authentication and you do not send the username and password with the request you get a challenge response back.
I applied all the things which are above mentioned but my problem is not solved.
In my case this is happening because of proxy server. Then I removed all the proxy and run my web service. Then it is working fine.
Hope this will you!!!!!!