I have a simple WCF host and client which run fine in Windows but suffer extremely bad performance on Mono 2.10.8/9.
The WCF host is running in a self-hosted console app.
WCF client is also a simple console app.
They're using netTcpBinding without any security.
Here's the host app.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MetadataBehavior">
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MetadataBehavior" name="EmployeeServiceLib.EmployeeService">
<clear />
<endpoint address="net.tcp://localhost:8888/EmployeeService/tcp"
binding="netTcpBinding" bindingConfiguration="ultra" name="EmployeeService"
contract="EmployeeServiceLib.IEmployeeService" listenUriMode="Explicit" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="ultra" transactionFlow="false" transferMode="Streamed">
<reliableSession enabled="false" />
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
client app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="EmployeeService" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false"
transferMode="Streamed" transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard" listenBacklog="10"
maxBufferPoolSize="65536" maxBufferSize="65536" maxConnections="10"
maxReceivedMessageSize="1048576">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:8888/EmployeeService/tcp"
binding="netTcpBinding" bindingConfiguration="EmployeeService"
contract="EmployeeService.IEmployeeService" name="EmployeeService" />
</client>
</system.serviceModel>
</configuration>
WCF Service class:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single,
AddressFilterMode = AddressFilterMode.Any)]
public class EmployeeService : IEmployeeService
{
private readonly List<Employee> m_Employees = new List<Employee>();
#region IEmployeeService Members
public void AddEmployee(Employee employee)
{
m_Employees.Add(employee);
}
// ... snipped ...
}
What the client does is calling an OperationContract 100 times and benchmark the calls.
var employee = new Employee { ... };
var client = new EmployeeServiceClient("EmployeeService", "net.tcp://localhost:8888/EmployeeService/tcp");
client.Open();
Console.Write("Adding 100 employees...");
var startTime = Environment.TickCount;
for (int i = 0; i < 100; i++)
{
client.AddEmployee(employee);
}
var timeTaken = Environment.TickCount - startTime;
Console.WriteLine(" Done.");
Benchmark result:
.NET 4.0 = 62 ms
Mono 2.11.1 = 1672 ms
Mono 2.10.9 in Debian 6 running in VM = 9632 ms (CPU usage hovering around 1%)
What can I do to speed up the performance of WCF on Mono esp in Debian?
Related
I have a WCF service with net.tcp endpoints using custom usernamePassswordValidator, custom authorization and TransportWithMessageCredential with credential type "Username" (see below).
Server and client work fine - unless the time skew between server and client machine are more than 5 minutes.
Now I try to set the max skew time in code. I tried to adapt code snippets intended for WSHttpBindings from MSDN and used the custom binding on server and client:
binding = GetSecuredBindingFromServerOrClient();
CustomBinding myCustomBinding = new CustomBinding(binding);
var security = myCustomBinding.Elements.Find<TransportSecurityBindingElement>(); // TransportSecurityBindingElement or SecurityBindingElement
security.LocalClientSettings.MaxClockSkew = timeSkew;
security.LocalServiceSettings.MaxClockSkew = timeSkew;
security.LocalServiceSettings.DetectReplays = false;
security.IncludeTimestamp = false;
// on client: use this custom binding in channel factory
var channelFactory = new ChannelFactory<ICheckerService>(customBinding, someAddress);
// on server: Update binding with customBinding
endpoint.Binding = myCustomBinding;
Still the connection fails with a MessageSecurityException when there is a time skew for more than 5 minutes (default value). I set also IncludeTimestamp to false or true but neither of them improved the situation.
The server behavior is:
<behavior name="customUserNamePasswordSecurityBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MySecurity.BasicAuthenticationValidator, MySecurity.Services"/>
</serviceCredentials>
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="Security.CustomAuthorizationPolicy, MySecurity.Services"/>
</authorizationPolicies>
</serviceAuthorization>
</behavior>
Then endpoint bindings are:
<binding name="tcpUserNameAuthentication">
<reliableSession enabled="true"/>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
Did anybody get the time skew working based on the above configuration with TransportWithMessageCredential and net.tcp? Or is there a basic misunderstanding?
On my side, MaxClockSkew works well if I use NetTcp protocol, which requires a certificate on the server-side (need to add the management permission of the private key to the account running the service) and username/password on the client-side.
At first, I transform the Nettcpbinding to Custombinding.
<customBinding>
<binding name="mybinding">
<security authenticationMode="SecureConversation">
<localClientSettings maxClockSkew="00:07:00" />
<localServiceSettings maxClockSkew="00:07:00" />
<secureConversationBootstrap authenticationMode="UserNameForCertificate">
<localClientSettings maxClockSkew="00:30:00" />
<localServiceSettings maxClockSkew="00:30:00" />
</secureConversationBootstrap>
</security>
<binaryMessageEncoding></binaryMessageEncoding>
<tcpTransport />
</binding>
</customBinding>
Then I invocate the service with the client proxy class when I change the time on the client-side, it works well when the client time varies within 7minutes on the server-side. if I didn't set up the MaxClockSkew on the server-side. it only works within 5minutes the server-side time.
Please refer to the below example, wish it is useful to you.
Server-side(console application)
class Program
{
static void Main(string[] args)
{
using (ServiceHost sh=new ServiceHost(typeof(MyService)))
{
sh.Open();
Console.WriteLine("Service is ready....");
Console.ReadLine();
sh.Close();
}
}
}
[ServiceContract]
interface IService
{
[OperationContract]
string GetData();
}
public class MyService : IService
{
public string GetData()
{
return DateTime.Now.ToString();
}
}
public class MyValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (userName != "jack" || password != "123456")
{
throw new Exception("My Error");
}
}
}
App.config
<system.serviceModel>
<services>
<service name="Server1.MyService" behaviorConfiguration="mybehavior">
<endpoint address="" binding="customBinding" contract="Server1.IService" bindingConfiguration="mybinding"></endpoint>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"></endpoint>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:800"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<customBinding>
<binding name="mybinding">
<security authenticationMode="SecureConversation">
<localClientSettings maxClockSkew="00:07:00" />
<localServiceSettings maxClockSkew="00:07:00" />
<secureConversationBootstrap authenticationMode="UserNameForCertificate">
<localClientSettings maxClockSkew="00:30:00" />
<localServiceSettings maxClockSkew="00:30:00" />
</secureConversationBootstrap>
</security>
<binaryMessageEncoding></binaryMessageEncoding>
<tcpTransport />
</binding>
</customBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="mybehavior">
<serviceMetadata />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="5ba5022f527e32ac02548fc5afc558de1d314cb6" x509FindType="FindByThumbprint" storeLocation="LocalMachine" storeName="My"/>
<userNameAuthentication customUserNamePasswordValidatorType="Server1.MyValidator,Server1" userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Client-side.
ServiceReference1.ServiceClient client = new ServiceClient();
client.ClientCredentials.UserName.UserName = "jack";
client.ClientCredentials.UserName.Password = "123456";
try
{
var result = client.GetData();
Console.WriteLine(result);
}
catch (Exception)
{
throw;
}
App.config(auto-generated)
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_IService">
<security defaultAlgorithmSuite="Default" authenticationMode="SecureConversation"
requireDerivedKeys="true" includeTimestamp="true" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireSignatureConfirmation="false" canRenewSecurityContextToken="true">
<secureConversationBootstrap defaultAlgorithmSuite="Default"
authenticationMode="UserNameForCertificate" requireDerivedKeys="true"
includeTimestamp="true" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireSignatureConfirmation="false">
<localClientSettings detectReplays="true" />
<localServiceSettings detectReplays="true" />
</secureConversationBootstrap>
<localClientSettings detectReplays="true" />
<localServiceSettings detectReplays="true" />
</security>
<binaryMessageEncoding />
<tcpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="net.tcp://10.157.13.69:800/" binding="customBinding"
bindingConfiguration="CustomBinding_IService" contract="ServiceReference1.IService"
name="CustomBinding_IService">
<identity>
<certificate encodedValue="blablabla" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Feel free to let me know if there is anything I can help with.
I have a Restful service that has this OperationContract
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "json")]
Response JSONData(Request request);
and is configured in this way
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService" closeTimeout="01:01:00"
openTimeout="01:01:00" receiveTimeout="01:10:00" sendTimeout="01:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" transferMode="Streamed"
useDefaultWebProxy="true">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
<webHttpBinding>
<binding name="WebHttpBinding_IService" closeTimeout="01:01:00" openTimeout="01:01:00"
receiveTimeout="01:10:00" sendTimeout="01:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
transferMode="Streamed" useDefaultWebProxy="true">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None" />
</binding>
<binding name="webHttpBindingXML"/>
<binding name="webHttpBindingJSON"/>
</webHttpBinding>
</bindings>
<services>
<service name="SearchService.SearchService" behaviorConfiguration="ServiceBehaviour">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address ="" binding="webHttpBinding" bindingConfiguration="WebHttpBinding_IService" contract="SearchService.ISearchService" behaviorConfiguration="web">
<!--
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.
-->
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<!-- 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>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint
automaticFormatSelectionEnabled="true"
helpEnabled="true" />
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
The request object is formed in this way
[DataContract]
public class Query
{
[DataMember]
public string name { get; set; }
[DataMember]
public string birthDate { get; set; }
}
[DataContract]
public class Input
{
[DataMember]
public Query query { get; set; }
[DataMember]
public string login_username { get; set; }
[DataMember]
public string login_password { get; set; }
}
[DataContract]
public class Request
{
[DataMember]
public Input input { get; set; }
}
I created a small client to test this query and I've also tested it using WCFTestClient and works fine. If I try to access this through fiddler though I get a 415 Unsupported Media Type error.
I tried this in the following manner
POST, http://localhost:8080/HostDevServer/SearchService.svc/json, HTTP/1.1
User-Agent: Fiddler
Content-Type: application/json;charset=UTF-8
Host: localhost:8080
Content-Length: 368
{ "input": { "login_password": "pass", "login_username": "login name", "query": { "birthDate": "", "name": "robert" } } }
I also tried deploying this service and see if fiddler would be able to access it then, but things got even more confusing because now instead of getting a 415 I was getting a 400 complaining about 'Reference to an object not set to an instance of the object.' and the small command line client I created would complain about There was no endpoint listening at the location of my service.
My question is, is there something wrong with my configuration file, or did I compose the fiddler request in the wrong way? If yes how can I fix this so I can access my service normally?
I can see that you are using BodyStyle = WebMessageBodyStyle.Wrapped
This means that you need to wrap the actual data with the name of the variable expected by your OperationContract. In short this should work
{ "response": { "input": { "login_password": "pass", "login_username": "login name", "query": { "birthDate": "", "name": "robert" } } } }
If you want to keep the body content as is then I suggest you use Bare instead of Wrapped for the body style.
I converted my WCF Services today to use WSHttpBinding instead of BasicHttpBinding. It is still in the development stage and thus I am using self signed certificates. The example that I followed is located Here
After finally getting the code to work like the example illustrates (follow the examples of the configs in the code that one can download), I decided to proceed to use Channel Factories like I did before.
Now when I make a call to a WCF method, I can clearly see that the object that I am sending is populated with the expected values, but if I step into the WCF side, the values are their defaults. For example Guid's will be Empty Guid's and int's will be 0. Always.
Any idea what might be causing this? here is some of my code:
In the web.config:
<add key="ClientCertificate" value="WcfClient" />
<add key="ServerCertificate" value="WcfServer" />
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="CustomBehavior">
<clientCredentials>
<clientCertificate findValue="WcfClient"
x509FindType="FindBySubjectName"
storeLocation="CurrentUser"
storeName="My" />
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IDocumentsService" closeTimeout="00:10:00"
openTimeout="00:10:00" sendTimeout="00:10:00" maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647" messageEncoding="Mtom" allowCookies="true">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:58790/DocumentsService.svc"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IDocumentsService"
contract="DocumentsService.IDocumentsService"
name="WSHttpBinding_IDocumentsService"
behaviorConfiguration="CustomBehavior">
<identity>
<dns value="WcfServer" />
</identity>
</endpoint>
</client>
</system.serviceModel>
This is my channel factory
public static class ServiceObjects
{
public static IDocumentsService DocumentsSVC { get { return GetDocServiceClient(); } }
#region Private Members
private static WSHttpBinding _DMBinding = new WSHttpBinding("WSHttpBinding_IDocumentsService");
private static EndpointIdentity _DMIdentity = EndpointIdentity.CreateDnsIdentity(ConfigurationManager.AppSettings.Get("ServerCertificate"));
private static EndpointAddress _DMEndpoint = new EndpointAddress(new Uri(ConfigurationManager.AppSettings.Get("DocumentsService")), _DMIdentity);
private static IDocumentsService GetDocServiceClient()
{
ChannelFactory<IDocumentsService> _docSvcFactory = new ChannelFactory<IDocumentsService>(_DMBinding, _DMEndpoint);
_docSvcFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;
_docSvcFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, ConfigurationManager.AppSettings.Get("ClientCertificate"));
_docSvcFactory.Credentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, ConfigurationManager.AppSettings.Get("ServerCertificate"));
return _docSvcFactory.CreateChannel();
}
#endregion
}
When I call the service, on the Client side for example:
private static Guid _UserID = (HttpContext.Current.User as Titan.Web.Classes.Identity.CustomPrincipal).UserId;
ServiceObjects.DocumentsSVC.GetDocumentsByFolderID(new DocumentRequest { CurrentUserID = _UserID })
I can see _UserID is populated, but on the server side it's not.
This is in my service's config
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding" closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00" allowCookies="true" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Mtom">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="Titan.WCF.Documents.DocumentsService" behaviorConfiguration="DocumentsServiceBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="Titan.WCF.Documents.IDocumentsService">
<!--
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>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DocumentsServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
<serviceCredentials>
<clientCertificate>
<!-- Remove the NoCheck in production, this is only for when we use a self signed cert -->
<authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck" />
</clientCertificate>
<serviceCertificate findValue="WCfServer"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Of course, since you've changed your configuration in the service you need to update the service reference so that the client too can update its configuration on its side. Unless you do that the client will keep calling the service with old configuration which it reads from its config file while the service runs with the new configuration settings.
It may be tiring, but it's the way it is.
It seems the issue lies in the way you make a call to the service using the following code:
ServiceObjects.DocumentsSVC.GetDocumentsByFolderID(new DocumentRequest { CurrentUserID = _UserID });
Here you are trying to invoke the service function without creating a proxy object of the service. And that is because you have written a static class in the service.
In a WCF service you can't use static classes. You need to create an instance of the class (service proxy object) and then invoke the service function.
I am not sure why this would make a difference, but it did.
I needed to update my service references.
A rookie mistake I guess, but why would that make a difference if the only thing I did was to change the bindings, endpoints etc?
How can I get my console app to connect with an IIS hosted WCF service when basic and/or windows authentication is switched on and anonymous authentication turned off?
The site is internal and stringent security is not required. There is no domain controller. However, I need to turn off anonymous access.
I have searched for days and have tried many methods including using a self hosted certificate and overriding the certification validation, overriding the UserNameValidator and using client.ClientCredentials.Windows.ClientCredentials.UserName or client.ClientCredentials.UserName.UserName. None of these have worked.
I am at a point where it would be nice if someone would be so kind as to look and run the code and help me get the sample running with authentication.
I have taken the liberty of uploading a sandbox solution containing, HostWebSite, ClientConsole and API projects.
I have hosted the zip file on my Windows Live SkyDrive: WCF_Authentication.zip
Some small setup steps.
I added to the hosts file 127.0.0.1 hostwebsite.local
I added a website to IIS
-- location: HostWebSite project root,
-- binding: hostwebsite.local
-- app pool: Classic 4.0 app pool.
Applied security Everyone read access to the HostWebSite project directory.
Verify can see service http://hostwebsite.local/services/EchoService.svc
Verify the console echoes back hello world.
Then turn off anonymous via IIS / Authentication and turn on either basic and/or windows authentication.
thank you
For the benefit of readers, I have included code snippets here
Project: API
namespace API.Contract
{
[ServiceContract]
public interface IEcho
{
[OperationContract]
string SendEcho(string message);
}
}
namespace API.Proxy
{
public class EchoProxy : IEcho
{
public string SendEcho(string message)
{
return string.Concat("You said: ", message);
}
}
}
namespace API.Service
{
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public class EchoService : System.ServiceModel.ClientBase<IEcho>, IEcho
{
public EchoService()
{
}
public EchoService(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}
public EchoService(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public EchoService(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public EchoService(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
public string SendEcho(string message)
{
return base.Channel.SendEcho(message);
}
}
}
Project: ClientConsole
static void Main(string[] args)
{
EchoService client = new EchoService("WSHttpBinding_IEcho");
try
{
Console.WriteLine(client.SendEcho("Hello World"));
client.Close(); // i tried putting this in the finally block but the client would close in an errored state it said.
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
Client Config
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IEcho" 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"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<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://hostwebsite.local/Services/EchoService.svc/services/EchoService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IEcho"
contract="API.Contract.IEcho" name="WSHttpBinding_IEcho">
<identity>
<servicePrincipalName value="host/mikev-ws" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Project: HostWebSite
<system.serviceModel>
<!-- SERVER -->
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="API.Proxy.EchoProxy" behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address="/services/EchoService.svc" binding="wsHttpBinding" contract="API.Contract.IEcho" />
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex"/>
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
Are you really looking at message level security? From your description, it appears that you want a transport level security (from IIS). For that you have to get your client configuration file correct. For example,
<binding ...
...
<security mode="TransportCredentialOnly">
<transport clientCredentialType="windows" proxyCredentialType="None" realm="" />
...
This will ensure integrated windows authentication - will use current windows user running the client for authentication. For NTLM/BASIC authentication, you need to provide user name/password from code - for example,
<binding ...
...
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="None" realm="" />
And in code,
EchoService client = new EchoService("WSHttpBinding_IEcho");
client.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential(userName, pwd);
EDIT:
For basic authentication to work with http protocol, you have to do configuration on server side as well as. For example,
<system.serviceModel>
<!-- SERVER -->
<bindings>
<basicHttpBinding>
<binding name="NewBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
</bindings>
...
<services>
<service name="API.Proxy.EchoProxy" ...
<endpoint binding="basicHttpBinding" bindingConfiguration="NewBinding" contract="API.Contract.IEcho" />
...
See this article for more info. BTW, you may want to consider HTTPS scheme because basic auth transmits password in plain text.
I am learning WCF and right now I am getting one exception while running the application:
Exception:
Could not find default endpoint
element that references contract
'IService1' in the ServiceModel client
configuration section. This might be
because no configuration file was
found for your application, or because
no endpoint element matching this
contract could be found in the client
element.
Service Code:
namespace StockService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
public string GetCompositedata()
{
CompositeType ct = new CompositeType();
return ct.StringValue;
}
}
}
web.config:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<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>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
now using svcutil I have generated proxyclass(generatedProxy.cs) and config file (serviceapp.config) and added it to a console application(client)
Client:
Service1Client sc = new Service1Client();
Console.WriteLine(sc.GetCompositedata());
Console.ReadKey();
config:
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1" 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="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:2614/Service1.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1" contract="IService1"
name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
</configuration>
I am not able to figure out why I am getting this exception.
Please help
Is that config you display for the client part of the client app's app.config or web.config, if it's a web site / web application??
You need to include those parts in your application's config - it's not enough to have those config's in a separate file created by svcutil.exe - it needs to be part of your application's configuration.
The svcutil-generated configuration needs to go into your main app.config, not be included as-is.
You need to add an app.config to your project then merge the contents of the svcutil config into the configuration section.