I successfully integrated the Caste WCF Facility with my services. Now I try to configure an HTTPS communication based on BasicHttpBinding.
According the following blog post, this should not be a big deal: http://blog.adnanmasood.com/2008/07/16/https-with-basichttpbinding-note-to-self/
Here's my setup. On client-side, I configure the Windsor container using the following code:
BasicHttpBinding clientBinding = new BasicHttpBinding();
// These two lines are the only thing I changed here to allow HTTPS
clientBinding.Security.Mode = BasicHttpSecurityMode.Transport;
clientBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
// Everything else worked well with HTTP
clientBinding.MaxReceivedMessageSize = 163840;
clientBinding.MaxBufferSize = (int)clientBinding.MaxReceivedMessageSize;
container = new WindsorContainer();
container.AddFacility<WcfFacility>();
container.Register(
Component.For<IClientService>()
.AsWcfClient(new DefaultClientModel {
Endpoint = WcfEndpoint.BoundTo(clientBinding)
.At(configuration.Get(CFGKEY_SERVICE_CLIENT))
})
);
Besides that, I don't have any configuration on client-side. This worked well using HTTP communication.
The server side got the following configuration within Web.config:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
When I'm trying to connect through https://, I get the following exception:
System.ServiceModel.EndpointNotFoundException: There was no endpoint listening at https://myuri.com/Services/Client.svc that could accept the message.
Any ideas what's missing?
Thank you in advance.
Fixed it by myself, the above code is correct, the problem has been located inside my Windsor service installer on server-side. The following snippet for each service point will do the job.
As you can see, I've put the absolute service URI as well as transport mode (either http or https) into the app settings section of the Web.config file. Of course it would be nice to use the default WCF configuration model but this did not work.
.Register(
Component
.For<MyNamespace.ContractInterface>()
.ImplementedBy<MyNamespace.ImplementationClass>()
.Named("ServiceName").LifestylePerWcfOperation()
.AsWcfService(
new DefaultServiceModel().Hosted().AddEndpoints(
WcfEndpoint.BoundTo(new BasicHttpBinding {
Security = new BasicHttpSecurity {
Mode = (WebConfigurationManager.AppSettings["Service.WCFFacility.TransportMode"] == "http") ? BasicHttpSecurityMode.None : BasicHttpSecurityMode.Transport,
Transport = new HttpTransportSecurity {
ClientCredentialType = HttpClientCredentialType.None
}
}
}).At(WebConfigurationManager.AppSettings["Service.WCFFacility.Endpoint"])
)
)
);
The server configuration remains as shown above, except the app setting keys.
Hope this might help someone experiencing similar problems.
Related
I build 2 services for the project I'm currently working on.
1) a simple client-server request service using basicHttpBinding
2) a callback dataservice using WSDualHttpBinding
with some twiddling I was able to host both in IIS and I can visit both :/Service.svc in my browser locally as well as on another machine that shall interact with both services as well.
here is the app-config section for the callback dataservice
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="myBehavior">
<clientVia />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_IDataService">
<security mode="None">
<message negotiateServiceCredential="false" clientCredentialType="None" />
</security>
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://<address>:50111/Service.svc/service"
binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_IDataService" behaviorConfiguration="myBehavior"
contract="CallbackService.IDataService" name="WSDualHttpBinding_IDataService">
</endpoint>
</client>
</system.serviceModel>
the basicHttpBinding looks quite similar - only to another port
I set IIS to anonymous authentication .. User IUSR, no password ..
Originally it worked locally - but from the remote computer I received authentication errors .. so I tweaked some more - and now I get a timeout even locally .. though Visual Studio interacts with the service reference to both services just fine.
How do I get the service "to cooperate" again
And I'm at my wits end - any help greatly appreciated!?
Edit: first problem solved - local communication restored
public ClientCallbacks myCallbacks=new ClientCallbacks();
public DuplexChannelFactory<IDataService> channelFactory { get; set; }
public IDataService channel;
public int connect() {
WSDualHttpBinding binding = new WSDualHttpBinding()
{ Name = "WSDualHttpBinding_IDataService" };
this.channelFactory = new DuplexChannelFactory<IDataService>(
mainForm.dbCommunication.myCallbacks,
binding,
new EndpointAddress("http://<address>:50111/Service.svc/service"));
this.channel = this.channelFactory.CreateChannel();
...
...
channel.AddListener(int-parameter); // announce new callback-partner
...
...
this.newListe = this.myCallbacks.receivedTaskList; //get Tasklist over callback
This works locally - but calling it remotely I get a "new" error
System.ServiceModel.Security.SecurityNegotiationException:
The caller was not authenticated by the service. --->
System.ServiceModel.FaultException: The request for security token could not be satisfied
because authentication failed.
at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault
(Message message, EndpointAddress target)
at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody
(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)
--- End of inner exception stack trace ---
And again I struggle to find a clue / solution .. I set IIS authentication to anonymous ... but it seems the communication is blocked before that point is reached .. What do I have to do to reach the service from a remote machine?
It seems that we should provide the credentials to have the client authenticated by the server-side. which sort of credentials should be supplied relies on the binding configuration of the server-side.
By default. The security mode of the WsDualhttpbinding is configured with Message security mode, and the client credential type is Windows.
These below code snippets are equivalent.
WSDualHttpBinding binding = new WSDualHttpBinding();
WSDualHttpBinding binding = new WSDualHttpBinding();
binding.Security.Mode = WSDualHttpSecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
From your code snippet, I didn’t see your configuration of the server-side. If Windows credential is required, please consider the below code segments.
//ChannelFactory<IService> channelFactory = new ChannelFactory(...);
channelFactory.Credentials.Windows.ClientCredential.UserName = "administrator";
channelFactory.Credentials.Windows.ClientCredential.Password = "123456";
IService svc = channelFactory.CreateChannel();
Feel free to let me know if the problem still exists.
March 27, 2020 UPDATE
It has been 4 days and I have padded my office walls now. :)
BIG QUESTION
This will only work locally if I change the following settings
Anonymous Authentication = Enabled
Does anybody know how to get around this issue with
- IIS Express
- Visual Studio 2017
I stepped out of the work code and created a test locally and I am only stuck on one issue now.
Authentication is now my BLOCKER
I will need to use the settings for deployment as I do not have any control on the DEV | SIT | UAT | PROD --- IAAS or PAAS - I can only code CI and CD.
I removed all the ---- Configuration
This was not in the original source code
I do have to comment out the code in the
MultipleBindingServiceHost.cs file
The localhost is complaining about the 2 URLs (I will revisit once I get all the security holes in the code fixed.
string rawUrl = ConfigurationManager.AppSettings["tsRawUrl"];
ServiceEndpoint endpoint = AddServiceEndpoint(typeof(ITicketService), httpBinding, baseAddress, new Uri(rawUrl));
endpoint.Behaviors.Add(new WebHttpBehavior());
#if (!DEBUG)
string vanityUrl = ConfigurationManager.AppSettings["tsVanityUrl"];
ServiceEndpoint endpoint2 = AddServiceEndpoint(typeof(ITicketService), httpBinding, baseAddress, new Uri(vanityUrl));
endpoint2.Behaviors.Add(new WebHttpBehavior());
#endif
March 23, 2020
I have been trying to figure out WCF and Local Machine development for the past week and now I am coming to stackoverflow for the communities assistance.
I have been tasked with supporting an application that has two WCF Services
Web.config appSettings Settings as follows:
<appSettings>
<add key="tsVanityUrl" value="http://localhost:1574/TicketService.svc" />
<add key="tsRawUrl" value="http://localhost:1574/TicketService.svc" />
<add key="fsVanityUrl" value="http://localhost:1574/FileService.svc" />
<add key="fsRawUrl" value="http://localhost:1574/FileService.svc" />
</appSettings>
Web.config system.serviceModel
<system.serviceModel>
<!-- START RBD Additions for Local Development -->
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<behaviors>
<serviceBehaviors>
<behavior name="TicketBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
<behavior name="FileBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="TicketSystem.TicketService" behaviorConfiguration="TicketBehavior">
<endpoint address="/TicketService.svc"
binding="basicHttpBinding"
contract="TicketSystem.ITicketService"
/>
</service>
<service name="TicketSystem.FileService" behaviorConfiguration="FileBehavior">
<endpoint address="/FileService.svc"
binding="basicHttpBinding"
contract="TicketSystem.IFileService"
/>
</service>
</services>
<!-- END RBD Additions for Local Development -->
</system.serviceModel>
I keep getting the following error:
The value could not be added to the collection, as the collection already contains an item of the same type: 'System.ServiceModel.Description.ServiceMetadataBehavior'. This collection only supports one instance of each type.
Parameter name: item
This points me to the MultipleBindingServiceHost.cs file
protected override void ApplyConfiguration()
{
base.ApplyConfiguration();
ServiceMetadataBehavior mexBehavior = new ServiceMetadataBehavior();
Description.Behaviors.Add(mexBehavior);
WebHttpBinding httpBinding = new WebHttpBinding();
foreach (Uri baseAddress in BaseAddresses)
{
if (baseAddress.Scheme == Uri.UriSchemeHttp)
{
httpBinding.Security.Mode = WebHttpSecurityMode.None;
mexBehavior.HttpGetEnabled = true;
}
else if (baseAddress.Scheme == Uri.UriSchemeHttps)
{
httpBinding.Security.Mode = WebHttpSecurityMode.Transport;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
mexBehavior.HttpsGetEnabled = true;
}
//ServiceEndpoint endpoint = AddServiceEndpoint(typeof(TicketSystem.ITicketService),
// httpBinding,
// baseAddress);
//endpoint.Behaviors.Add(new WebHttpBehavior());
//Fix for 404 Vanity URL Issue
string rawUrl = ConfigurationManager.AppSettings["tsRawUrl"];
ServiceEndpoint endpoint = AddServiceEndpoint(typeof(ITicketService), httpBinding, baseAddress, new Uri(rawUrl));
endpoint.Behaviors.Add(new WebHttpBehavior());
string vanityUrl = ConfigurationManager.AppSettings["tsVanityUrl"];
ServiceEndpoint endpoint2 = AddServiceEndpoint(typeof(ITicketService), httpBinding, baseAddress, new Uri(vanityUrl));
endpoint2.Behaviors.Add(new WebHttpBehavior());
break;
}
}
}
I know I am very close and probably missing something very simple, but after spending multiple days on this I have to post on stackoverflow to get the services running on my local maching.
WCF service application project doesn’t support multiple service contracts in one service host. One service project has one service host, we need to specify the service implemented class during starting the host. Consequently, it is impossible to host multiple service contracts in one host. We could create multiple hosts in a console/Windows NT service application so as to support multiple service contracts.
using (ServiceHost sh = new ServiceHost(typeof(TestService)), sh2 = new ServiceHost(typeof(MyService1)))
{
sh.Opened += delegate
{
Console.WriteLine("service is ready");
};
sh.Closed += delegate
{
Console.WriteLine("service is closed");
};
sh2.Opened += delegate
{
Console.WriteLine("service2 is ready...");
};
sh2.Closed += delegate
{
Console.WriteLine("Service is closed...");
};
sh.Open();
sh2.Open();
Console.ReadLine();
sh.Close();
sh2.Close();
}
Feel free to let me know if there is anything I can help with.
I have a server&client solution that are using WCF. The client will ask a service about the URL to an active server at runtime and to be able to set this I use ChannelFactory. I however still needs to use all other WCF settings from the config file. This is how I do it :
var clientSection = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;
var address = string.Empty;
for(int i = 0; i < clientSection.Endpoints.Count; i++)
{
if(clientSection.Endpoints[i].Name == endpointConfigurationName)
{
var endpointAddress = new EndpointAddress(clientSection.Endpoints[i].Address.ToString());
var netHttpBinding = new NetHttpBinding(clientSection.Endpoints[i].BindingConfiguration);
var serviceEndpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(T)), netHttpBinding, endpointAddress);
var channelFactory = new ChannelFactory<T>(serviceEndpoint);
break;
}
}
The problem is that I got 2 BehaviorExtensions that are used by some of the endpoints like this.
<services>
<endpoint binding="netHttpBinding" behaviorConfiguration="protoEndpointBehavior" address="BinaryHttpProto" bindingNamespace="http://MyApp.ServiceContracts/2007/11" contract="MyApp.ServiceContracts.IMyAppClientService" />
</services>
<behaviors>
<endpointBehaviors>
<behavior name="protoEndpointBehavior">
<protobuf />
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="protobuf" type="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net, Version=2.0.0.668, Culture=neutral, PublicKeyToken=257b51d87d2e4d67" />
</behaviorExtensions>
</extensions>
The question is how I read this from the clientSection.Endpoints? and sets it on the channelFactory? I know that I could create then manually like this :
serviceEndpoint.EndpointBehaviors.Add(new ProtoEndpointBehavior());
serviceEndpoint.EndpointBehaviors.Add(new CustomMessageInspectorBehavior());
But then this will be a hard coded static and it will apply to all endpoints, I need to be able to change it from the config.
You don't need to create the ChannelFactory by yourself. Just create a ClientService class that inherits from ClientBase<T>. The constructor of the ClientBase<T> accepts a EndpointName and adds automatically the behavior that is associated with this Endpoint. The ClientBase<T> also give you the possibility to access the ChannelFactory<T> and you can open as much channel as you want. the only thing that you need further to do, is to add a name for each EndPoint in the config that you want to use.
<endpoint binding="..." name="MyEndPoint" ... />
I hade to create everything in code, a mixed solution was no good, not in my case where I use alot of custom stuff.
I am testing out the no configuration features of WCF 4.
I have built a simple service and deployed it to IIS. The service is deployed as a svc file
The client config is empty:
<configuration>
<system.serviceModel>
<bindings />
<client />
</system.serviceModel>
</configuration>
The config on the web server is:
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
This code works fine:
BasicHttpBinding myBinding = new BasicHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress("http://localhost/Service1.svc");
ChannelFactory<IService1> myChannelFactory = new ChannelFactory<IService1>(myBinding, myEndpoint);
IService1 wcfClient1 = myChannelFactory.CreateChannel();
int z = wcfClient1.Multiply(composite);
This code does not:
NetTcpBinding myBinding = new NetTcpBinding();
EndpointAddress myEndpoint = new EndpointAddress("net.tcp://localhost:808/Service1.svc");
ChannelFactory<IService1> myChannelFactory = new ChannelFactory<IService1>(myBinding, myEndpoint);
IService1 wcfClient1 = myChannelFactory.CreateChannel();
int z = wcfClient1.Multiply(composite);
The error that I get is:
Could not connect to
net.tcp://localhost/Service1.svc. The
connection attempt lasted for a time
span of 00:00:02.1041204. TCP error
code 10061: No connection could be
made because the target machine
actively refused it 127.0.0.1:808.
The net.tcp binding is set on the default web site.
I have a feeling that there is something simple that I am missing. Anyone have any ideas?
I get the feeling that your Net.Tcp Port Sharing Service is not enabled.
Found the problem. Although net.tcp looked like it was installed for the Default web site it needed to be activated using this command:
appcmd.exe set app "Default Web Site/" /enabledProtocols:http,net.tcp
I've written a simple Java Console Application in Eclipse that references a WCF web service written in C#. Hosting the WCF service locally on my PC, I'm unable to connect to the service using the java client.
The steps I've taken to create the WCF Service are as follows
Create a 'Service1.svc' with the following endpoint:
string IService1.Hello(string sName)
{
return "Hello " + sName + "!" ;
}
The web config for the service is as follows:
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding" />
</basicHttpBinding>
</bindings>
<client>
<endpoint binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding"
contract="WcfService1.IService1" name="BasicHttpEndpoint" />
</client>
<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"/>
I modified the properties so the service will always use port 8888.
I've tested the service using a C# console application.
To Create the Java client, I did the following:
Download and install Glassfish 3.0.1 (Application server) which come bundled with Metro (Web Server)
Use the 'wsimport' tool in the 'bin'directory of my jdk to generate the service reference code for the java client app. The .bat file that I ran to create the service reference
Copy the code from step 2. above into a new Java Application in Eclipse.
Create a new Java class in my console app which calls the web service as follows
`
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import org.tempuri.Service1;
import org.tempuri.IService1;
public class Main {
/**
* #param args
*/
public static void main(String[] args) {
try {
Service1 service = new Service1(new URL("http://localhost:8888/Service1.svc?wsdl"), new QName("http://tempuri.org", "Service1"));
IService1 port = service.getBasicHttpBindingIService1();
((BindingProvider)port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://localhost:8888/Service1.svc");
String sFileName = port.hello("Cal");
System.out.println(sFileName);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
e.printStackTrace();
}
}
}
`
The error I'm getting when I attempt to run my application is as follows:
Exception in thread "main" javax.xml.ws.WebServiceException: {http://tempuri.org}Service1 is not a valid service. Valid services are: {http://tempuri.org/}Service1
at com.sun.xml.ws.client.WSServiceDelegate.(WSServiceDelegate.java:237)
at com.sun.xml.ws.client.WSServiceDelegate.(WSServiceDelegate.java:182)
at com.sun.xml.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:106)
at javax.xml.ws.Service.(Unknown Source)
at org.tempuri.Service1.(Service1.java:42)
at Main.main(Main.java:17)
Any assistance with this is appreciated. Thanks.
change:
new QName("http://tempuri.org", "Service1")
to:
new QName("http://tempuri.org/", "Service1")
notice the extra "/" after org.