I'm a newbie at WCF. I'm trying to edit existing code to use a net.tcp binding instead of a http binding. I have done this easily in test projects using the config files, but for various reasons, in the real project it is done programatically.
I made the necessary changes, and the service host seems to start correctly:
Uri baseAdress= new Uri("net.tcp://localhost:7005/MyService/");
host = new ServiceHost(typeof(MyServiceImpl), baseAdress);
host.AddServiceEndpoint(
typeof(MyService),
new NetTcpBinding(),
"");
ServiceMetadataBehavior metadataBehavior;
metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metadataBehavior == null)
{
metadataBehavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(metadataBehavior);
}
BindingElement bindingElement = new TcpTransportBindingElement();
CustomBinding binding = new CustomBinding(bindingElement);
host.AddServiceEndpoint(typeof(IMetadataExchange), binding, "mex");
host.Open();
So far so good. I edited the connection string client side:
string serverUri = string.Format("net.tcp://{0}:{1}/MyService", serverName, port);
MyService server = new MyServiceClient("MYS", serverUri);
But when i try to call functions from my service, i get this error:
The provided URI scheme 'net.tcp' is invalid; expected 'http'
Not quite sure what i am missing... Any hints?
Related
I coded a WCF Service using HttpTransportBindingElement in conjunction with IIS on port 80.
The code works fine as long as no proxy is used. But if a customer has a http-proxy the communication between WCF-Client and Server does not work in this case by occuring following error:
'There was no endpoint listening at ... that could accept the message. This is often caused by an incorrect address or SOAP action.'
It is essential to use settings by code ONLY!
here is my code approach for that issue but i stuck on it:
bool SendClientRequest(Action<ICustomerService> channel)
{
string proxy ="my.proxy.domain:8080";
string user = "user1";
string password="secret";
// maybe i do not need this 3 lines!
WebProxy webproxy = new WebProxy(proxy, true);
webproxy.Credentials = new NetworkCredential(user, password);
WebRequest.DefaultWebProxy = webproxy;
CustomBinding customBinding = new CustomBinding();
customBinding.Elements.Add(new HttpTransportBindingElement()
{
AuthenticationSchemes.None : AuthenticationSchemes.Basic,
ProxyAddress = string.IsNullOrEmpty(proxy) ? null : new Uri(proxy),
UseDefaultWebProxy = false,
BypassProxyOnLocal = true,
TransferMode = TransferMode.Streamed,
MaxReceivedMessageSize = 84087406592,
MaxBufferPoolSize = 0x1000000,
MaxBufferSize = 0x1000000
});
using (ChannelFactory<ICustomerService> factory = new
ChannelFactory<ICustomerService>(customBinding ))
{
IClientChannel contextChannel = null;
string url = "http://my.domain.de/Distribution/eService.svc",
EndpointAddress ep = new EndpointAddress(url);
ICustomerService clientChannel = factory.CreateChannel(ep);
contextChannel = clientChannel as IClientChannel;
contextChannel.OperationTimeout = TimeSpan.FromMinutes(rcvTimeout );
channel(clientChannel); // <- here i get the exception!
return true;
}
}
I tried several solution approaches but nothing seems to be specific like mine.
I think you have a few options, some of which I'll detail below.
First you could set UseDefaultWebProxy to true. This would then mean that proxy information is retrieved automatically from system proxy settings, configurable in Internet Explorer (Internet Options > Connections > LAN settings > Proxy server). This may be appropriate if you don't need to specify credentials for proxy use.
Another approach that's worked for me is to use the ProxyAuthenticationScheme property within your HttpTransportBindingElement() object. This property is only available on the CustomBinding class and allows an authentication scheme to be specified that will be used to authenticate against a proxy. In conjunction with this, the proxy server must be set against property ProxyAddress. Last but not least, the credentials to use against the proxy should be set according to the authentication scheme used, so for example, using AuthenticationSchemes.Ntlm would mean setting the UserName and Password properties on ChannelFactory.ClientCredentials.Windows.ClientCredential or perhaps ChannelFactory.ClientCredentials.HttpDigest.ClientCredential
With the second approach, be sure to note the difference between holding credentials in the ChannelFactory for use with the remote service versus credentials used for the proxy server. I've highlighted these in the code example below for clarity:
// Example service call using a CustomBinding that is configured for client
// authentication based on a user name and password sent as part of the message.
var binding = new CustomBinding();
TransportSecurityBindingElement securityBindingElement = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
var secureTransport = new HttpsTransportBindingElement();
secureTransport.UseDefaultWebProxy = false;
secureTransport.ProxyAddress = new Uri("http://some-proxy");
secureTransport.ProxyAuthenticationScheme = AuthenticationSchemes.Ntlm;
binding.Elements.Add(securityBindingElement);
binding.Elements.Add(secureTransport);
var endpointAddress = new EndpointAddress("https://some-service");
var factory = new ChannelFactory<IService>(binding, endpointAddress);
// Credentials for authentication against the remote service
factory.Credentials.UserName.UserName = "serviceUser";
factory.Credentials.UserName.Password = "abc";
// Credentials for authentication against the proxy server
factory.Credentials.Windows.ClientCredential.UserName = "domain\user";
factory.Credentials.Windows.ClientCredential.Password = "xyz";
var client = factory.CreateChannel();
client.CallMethod();
I'm defining a Service Reference in code using the following:
EndpointAddress NewEndPoint =
new EndpointAddress("http://example.com/someservice.asmx");
sr_SomeService.SomeServiceSoapClient _SomeService =
new sr_SomeService.SomeServiceSoapClient(
new System.ServiceModel.BasicHttpBinding(), NewEndPoint);
When I use an EndPoint with HTTP the above code works however when I try an HTTPS address I get the following error:
The provided URI scheme 'https' is invalid; expected 'http'.
Parameter name: via
How do I use an HHTPS EndPoint?
Here's the code for the answer :)
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
EndpointAddress NewEndPoint =
new EndpointAddress("https://example.com/someservice.asmx");
sr_SomeService.SomeServiceSoapClient _SomeService =
new sr_SomeService.SomeServiceSoapClient(binding, NewEndPoint);
Thanks for the pointers.
Ok so I am hosting a WCF service within a console application.
all bindings are created programatically, so no config settings.
I have a working service as long as I use HttpTransportBindingElement however as soon as I use HttpsTransportBindingElement then nothing works, the service does not display within the browser and the client application returns a 405 (Method Not Allowed) CommunicationException
I have tried setting a SecurityBindingElement to my CustomBinding but I am not sure which option I should be using.
SecurityBindingElement.CreateCertificateOverTransportBindingElement()
SecurityBindingElement.CreateAnonymousForCertificateBindingElement()
etc.
The code for the creation of the host is below
baseAddress = new Uri(string.Format("{0}://{1}", strConnectionType, ConfigurationManager.AppSettings["baseAddress"]));
ServiceHost host = new ServiceHost(typeof(IMyService), baseAddress);
host.AddServiceEndpoint(typeof(MyService), binding, String.Empty);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpsGetEnabled = certificate != null;
smb.HttpGetEnabled = certificate == null;
host.Description.Behaviors.Add(smb);
ServiceDebugBehavior sdb = host.Description.Behaviors.Find<ServiceDebugBehavior>();
if (sdb == null)
{
host.Description.Behaviors.Add(new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
}
else
{
if (!sdb.IncludeExceptionDetailInFaults)
{
sdb.IncludeExceptionDetailInFaults = true;
}
}
if (certificate != null)
{
host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, certificate.Thumbprint);
}
I followed this blog http://blogs.msdn.com/b/james_osbornes_blog/archive/2010/12/10/selfhosting-a-wcf-service-over-https.aspx which highlighted that in order for HTTPS to work you need to bind the port to the certificate you are using.
Process bindPortToCertificate = new Process();
bindPortToCertificate.StartInfo.FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.SystemX86), "netsh.exe");
bindPortToCertificate.StartInfo.Arguments = string.Format("http add sslcert ipport=0.0.0.0:{0} certhash={1} appid={{{2}}}", port, certificate.Thumbprint, Guid.NewGuid());
bindPortToCertificate.Start();
bindPortToCertificate.WaitForExit();
once this was done it all worked.
contact me if any requires my example code of setting up and configuring a self-hosted WCF server with bindings programatically set. :)
i want to secure a Silverlight App with SSL.
So I try to wrote a proof of concept, where I host two BasicHttpBindings. One with BasicHttpSecurityMode.None and the other with BasicHttpSecurityMode.Transport.
But I not able to get the second one running, The WCFTestClient from VS Tools display this error message
// Error: Cannot obtain Metadata from https://localhost:8081/ If this is
// a Windows (R) Communication Foundation service to which you have
// access, please check that you have enabled metadata publishing at the
// specified address. For help enabling metadata publishing, please
// refer to the MSDN documentation at
// http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange
// Error URI: https://localhost:8081/ Metadata contains a reference
// that cannot be resolved: 'https://localhost:8081/'. An error
// occurred while making the HTTP request to https://localhost:8081/.
// This could be due to the fact that the server certificate is not
// configured properly with HTTP.SYS in the HTTPS case. This could also
// be caused by a mismatch of the security binding between the client and
// the server. The underlying connection was closed: An unexpected
// error occurred on a send. Unable to read data from the transport
// connection: An existing connection was forcibly closed by the remote
// host. An existing connection was forcibly closed by the remote
// hostHTTP GET Error URI: https://localhost:8081/ There was an
// error downloading 'https://localhost:8081/'. The underlying
// connection was closed: An unexpected error occurred on a send.
// Unable to read data from the transport connection: An existing
// connection was forcibly closed by the remote host. An existing
// connection was forcibly closed by the remote host
I would be great if some could view over my code, I stuck for two days with this. It need to be done all programmatically.
Thanks a lot.
Almost the whole programm: http://pastebin.com/9j9K43tS
The Endpoints
private static readonly Uri UriBase = new Uri("http://localhost:8080/");
private static readonly Uri UriBaseService = new Uri("http://localhost:8080/Basic");
private static readonly Uri UriSecure = new Uri("https://localhost:8081/");
private static readonly Uri UriSecureService = new Uri("https://localhost:8081/Secure");
This Works
private static void BasicHTTPServer()
{
var binding = new BasicHttpBinding();
binding.Name = "binding1";
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.Security.Mode = BasicHttpSecurityMode.None;
// Create a ServiceHost for the CalculatorService type and provide the base address.
_serviceHost = new ServiceHost(typeof (ServiceBasic), UriBase);
_serviceHost.AddServiceEndpoint(typeof (IServiceBasic), binding, UriBaseService);
_serviceHost.AddServiceEndpoint(typeof (IPolicyRetriever), new WebHttpBinding(), "")
.Behaviors.Add(new WebHttpBehavior());
var smb = new ServiceMetadataBehavior {HttpGetEnabled = true, HttpGetUrl = UriBase};
_serviceHost.Description.Behaviors.Add(smb);
// Open the ServiceHostBase to create listeners and start listening for messages.
_serviceHost.Open();
Logger.Log(Server.Basic, string.Format("Open at {0} Service: {1}", UriBase, UriBaseService));
}
This doesn't Works
private static void SecureHTTPServer()
{
var binding = new BasicHttpBinding();
// it doesnt matter if I use BasicHttpsBinding or BasicHttpBinding
binding.Name = "binding2";
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
// Create a ServiceHost for the CalculatorService type and provide the base address.
_serviceHostSecure = new ServiceHost(typeof (ServiceBasic), UriSecure);
_serviceHostSecure.Credentials.ServiceCertificate.Certificate = GetCertificate();
//load a certificate from file
_serviceHostSecure.Credentials.ClientCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.None;
_serviceHostSecure.AddServiceEndpoint(typeof (IServiceBasic), binding, UriSecureService);
var webHttpBinding = new WebHttpBinding(WebHttpSecurityMode.Transport);
webHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
_serviceHostSecure.AddServiceEndpoint(typeof (IPolicyRetriever), webHttpBinding, "")
.Behaviors.Add(new WebHttpBehavior());
var smb = new ServiceMetadataBehavior {HttpsGetEnabled = true, HttpsGetUrl = UriSecure};
_serviceHostSecure.Description.Behaviors.Add(smb);
// Open the ServiceHostBase to create listeners and start listening for messages.
_serviceHostSecure.Open();
Logger.Log(Server.Basic, string.Format("Open at {0} Service: {1}", UriSecure, UriSecureService));
}
I'm loading an host with a service called Service which implement the contract IService.
The binding is WSDualHttpBinding.
var host = new ServiceHost(typeof(Service));
host.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
host.AddServiceEndpoint(typeof(IService),new WSDualHttpBinding()
,endPointAddress);
In the client side i am trying to discover the endpoint.
EndpointAddress address = new EndpointAddress(new Uri(string.Format("http://{0}:{1}/Service/Client/Discovery", Environment.MachineName, "1111")));Environment.MachineName, 1111);
DiscoveryClient client =
new DiscoveryClient(new DiscoveryEndpoint(new WSDualHttpBinding(), address));
FindResponse find = client.Find(new FindCriteria(typeof(IService))
{ Duration = TimeSpan.FromSeconds(3) });
It is not working... I get a timeout exception after a minute without any reason.
i am running the host and the client on the same machine.
does anyone can detect what the problem is?
thanks