I have a current project that runs fine with a self-hosted net.tcp binding if I use the following
host.AddServiceEndpoint(typeof(IMonitorService), new NetTcpBinding() {PortSharingEnabled = false }, "");
host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
However, if I amend to the below it fails to run with the message that there is already an endpoint on the port, can anyone explain why adding the extra properties causes it to fail?
host.AddServiceEndpoint(typeof(IMonitorService), new NetTcpBinding() {PortSharingEnabled = false,ListenBacklog=1000,ReceiveTimeout=new TimeSpan(0,3,0) }, "");
host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
Edit:
Testing confirms that the ReceiveTimeout property works Ok, as soon as I add the MaxConnections or ListenBacklog the service fails to start
Edit 2:
This link seems to imply I need port sharing if I want to modify these properties, not sure I am understanding it.
Related
I'm kind of new to the whole WCF and SOAP topic so please be kind.
I'm using a generated SOAP Client with .net6. In another project we successfully worked with the same Web Service using the old .net Framework 2.0 Web References and the same credentials.
Strange enough everything seemed to work fine at first. Until I realized, that it does not use the given credentials to authenticate. Instead it authenticates with my own domain user.
I also tried to get it to work with explicitly setting the binding with a BasicHttpBinding but I only could get the same broken logic to work or I got various authentication/protocol/security errors.
So it seems the authentication is basically working. It just doesn't use the provided credentials. So my question is: How can I configure it to work with the provided identity?
I also found out that it might have anything to do with a cached Windows token. But how can I get rid of it. How to prevent caching in the first place?
EDIT:
Specified the variable types explicitly.
string url = "http://someServer/AdministrationService.asmx";
AdministrationServiceSoapClient client = new AdministrationServiceSoapClient(
AdministrationServiceSoapClient.EndpointConfiguration.AdministrationServiceSoap,
url);
WindowsClientCredential credential = client.ClientCredentials.Windows;
credential.ClientCredential.UserName = "username";
credential.ClientCredential.Password = "password";
credential.ClientCredential.Domain = "DOMAIN";
GetServerInfoRequest getServerInfoRequest = new GetServerInfoRequest
{
// some stuff set here
};
GetServerInfoRequest getServerInfoReply = await client.GetServerInfoAsync(getServerInfoRequest);
As far as I know, BasicHttpBinding has security disabled by default, but can be added setting the BasicHttpSecurityMode to a value other than None in the constructor. It can be configured according to the instructions in BasicHttpBinding and BasicHttpBinding Constructors.
By default, setting up client credentials involves two steps: determining the type of client credential required by the service and specifying an actual client credential, as described in this document.
After waiting a day it is working. It seems that the cached credentials became invalid somehow.
Strange enough the simple service creation from above is not working anymore. Instead I have to use the following.
var client = new AdministrationServiceSoapClient(
new BasicHttpBinding()
{
Security = new BasicHttpSecurity()
{
Mode = BasicHttpSecurityMode.TransportCredentialOnly,
Message = new BasicHttpMessageSecurity()
{
ClientCredentialType = BasicHttpMessageCredentialType.UserName,
},
Transport = new HttpTransportSecurity()
{
ClientCredentialType = HttpClientCredentialType.Windows,
ProxyCredentialType = HttpProxyCredentialType.Windows,
}
},
},
new EndpointAddress(url));
My situation:
I have one WCF service on address http://0.0.0.0:10004/Service.svc. Using Interface_1, Service_1_Class, ServiceHost_1_Class.
Now I need second version of this service with authorisation. Choosing address https://0.0.0.0:10004/Service2.svc, using Interface_1, Service_1_Class, ServiceHost_2_Class.
Got the error
HTTP could not register URL https://+:10004/Service2.svc/. Another application has already registered this URL with HTTP.SYS.
If copy-paste and use Interface_2, Service_2_Class, ServiceHost_2_Class (same classes with different name) everything works.
Not the big problem, but want to know: how to bind same service class on two addresses? So which step may I miss? I.e. binding one to one works, binding one to two - not, where is difference? If there should not be differences (i.e. problem in code), I'll close this question.
PS: sorry, cant post code: too big, too complicated, not clear. Question not about code, but conception
As suggested, you need to setup multiple service endpoints each with a different binding. One binding with no security enabled and the other binding with security enabled.
Here is a working example of how to host the same service at two different endpoints. One endpoint has no security at all and the other endpoint provides HTTP-based client authentication.
var baseUri = new Uri("http://localhost:10004/");
var serviceHost = new ServiceHost(typeof(HelloWorldService), baseUri);
try
{
var unsecureServiceEndpoint = serviceHost.AddServiceEndpoint(typeof(IHelloWorldService), new WebHttpBinding(), "Service.svc");
unsecureServiceEndpoint.Behaviors.Add(new WebHttpBehavior());
unsecureServiceEndpoint.Name = "UnsecureEndpoint";
var secureBinding = new WebHttpBinding(WebHttpSecurityMode.TransportCredentialOnly);
secureBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var secureServiceEndpoint = serviceHost.AddServiceEndpoint(typeof(IHelloWorldService), secureBinding, "Service2.svc");
secureServiceEndpoint.Behaviors.Add(new WebHttpBehavior());
secureServiceEndpoint.Name = "SecureEndpoint";
serviceHost.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
serviceHost.Open();
Console.WriteLine("Hosting - {0} # {1}", unsecureServiceEndpoint.Name, unsecureServiceEndpoint.Address);
Console.WriteLine("Hosting - {0} # {1}", secureServiceEndpoint.Name, secureServiceEndpoint.Address);
Console.WriteLine("Press <Enter> to stop the services.");
Console.ReadLine();
serviceHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("An exception occurred: {0}", ce.Message);
serviceHost.Abort();
}
I'm trying to disable SoapProcessing for an endpoint (yes, it needs to be done, don't ask why, and message inspectors will not work):
MSDN docs for soapProcessing
However, all of the documentation I've found seems to rely on setting this value in the app's config file. I am developing a plugin for an application that does not allow me to include a separate config file, so I have to set up the endpoint and bindings and all that via code:
// Create transport binding
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
// Create client
MySyncPortClient _service = new MySyncPortClient(binding, new EndpointAddress("https://path/to/service"));
_service.ClientCredentials.UserName.UserName = "foo";
_service.ClientCredentials.UserName.Password = "bar";
// Set custom bindings
BindingElementCollection elements = _service.Endpoint.Binding.CreateBindingElements();
elements.Find<SecurityBindingElement>().IncludeTimestamp = false;
_service.Endpoint.Binding = new CustomBinding(elements);
// Perform a request
_service.DoSomething();
If anyone can point me in the right direction, I'd appreciate it. And not to be rude, but please do not suggest using a config file. It -NEEDS- to be done via code. If you want a full explanation, I can provide one separately.
Closing this out - apparently it can't be done.
I'll set the scene.
We have a set of WCF Service Hosts (S1, S2...Sn) that operate in a chain to process a received message, the first service does some processing and then hands the message to the next service which does some more processing and so on. A final WCF Service (U) receives the output of Sn and validates it.
The services S1, S2,...Sn are started via .exe files separately from the service U. Sevice U is started from Visual Studio 2010 from a Unit Test and once its started a message is fired into service s1 for processing. The problem we're seeing is that once service Sn attempts to pass the message to service U for validation we are presented with an error:
There was no endpoint listening at http://localhost:9005/ValidationService.svc
The strange thing is this error only occurs on the first run of the Unit Test. If we were to re-run the test after the initial failure the test would pass without issue (Sn successfully passing the message to U). However closing services S1, S2,...Sn restarting and re-running the unit test causes the "no endpoint listening at..." to be thrown again on the first run of the test.
My thoughts are that service U might still be completing its opening processes while service Sn tries to send a message to it, however I'm unconvinced, if this was the case how can we be sure service U is open and listening before firing a message into S1?
The service U is started by the following code:
public void TestChain()
{
var binding = new BasicHttpBinding();
// Construct service U
var serviceHostU = new ServiceHost(typeof(ChainContract), "http://localhost:9005");
serviceHostU.AddServiceEndpoint(typeof(ChainContractImplementation), binding, "ValidationService.svc");
serviceHostU.Open();
//fire message into service s1
var ep = new EndpointAddress("http://localhost:8777/InputService.svc");
var inputFactory = new ChannelFactory<ChainContract>(binding, ep);
var channel = inputFactory.CreateChannel();
//fire a message into service s1.
channel.ReceiveMessage(new TestMessage());
serviceHostU.Close();
}
Any help would be greatly appreciated.
I think your supposition that the first ServiceHost is initialising while the second one makes the call is probably correct.
To handle this, you could hook a delegate to the Opened event of your ServiceHost and run your second service from there.
When I am adding the "Web Reference" we are giving the address to the asmx page to visual studio.
How Can I set this at run time?
I would have upvoted one of the other answers - they're almost correct.
using (YourService service = new YourService())
{
service.Url = "http://some.other.url/";
// Now you're ready to call your service method
service.SomeUsefulMethod();
}
If a using block is not used, and an exception is thrown, then resources like network connections can be leaked.
Just set the Url property of the object before you call any of the service methods:
YourService service = new YourService();
service.Url = "http://some.other.url/";
// Now you're ready to call your service method
service.SomeUsefulMethod();
YourWebService service = new YourWebService();
service.Url = "http://www.example.com/YourWebService.asmx";
service.CallMethod();