Assumption:
I'm working with a WCF application called DemoWCF, in which I have a simple wcf service called Calculator.
The purpose of the application is obviously a demo, the WCF service has to take two numbers as parameters and make the sum of them.
Service Class:
public class Calculator : ICalculator
{
public int Sum(int firstValue, int secondValue)
{
return firstValue + secondValue;
}
}
Service Contract :
[ServiceContract(Namespace="http://ROCKET/Calculator")]
public interface ICalculator
{
[OperationContract]
int Sum(int firstValue, int secondValue);
}
Web.config, service model configuration:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpsBinding">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="DemoWCF.Services.ServiceClasses.Calculator">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpsBinding" contract="DemoWCF.Services.ServiceContracts.ICalculator" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
When I deploy the WCF application on my IIS and I try to consume the WCF service in SOAP UI or in an ASP.NET MVC application, everything works fine.
Goal:
When I consume the WCF service in SOAP UI, I note that from the wsdl of the web service is automatically generated the binding "WSHttpBinding_ICalculator".
When I consume the WCF service in an ASP.NET MVC application, I note that the from the wsdl of the web service is automatically generated the service model, precisely:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ICalculator">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://rocket/ServiceClasses/Calculator.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICalculator" contract="Calculator.ICalculator" name="WSHttpBinding_ICalculator" />
</client>
</system.serviceModel>
What I want to do, is to rename the Service Name and the Binding Name of the WCF Service.
It's possibile to omit this WCF behavior of generating binding's name with the format : "BindingType_IServiceInterface" ?
What I have to do, if I want to rename my service name and binding name in "Calculator" ?
Related
I have self hosting WCF service that contains it's own app.Config to expose endpoints required for the service contracts. If the service is started in the programs.cs main method it all works just fine and the metadata is exposed via the browser. However, I created a HostService class based on the ServiceBase class which in the same host library and is instantiated within the program.cs file. The HostService class starts the service and has a timer method to ping other client web services for information.
My question is, when I created the HostService : ServiceBase class and instantiate it from the main(), I have to put a duplicate app.Config file in the Service Library in order for the endpoints to properly exposed and return the metadata/wsdl. I don't want to maintain 2 duplicate app.config files if possible. Currently the host library and service library both require one. Is there a way to only have just one w/ the host that could be used for both? Sorry for the dumb question, but I'm new to WCF =)
Program.cs
static void Main(string[] args){
var service = new HostService();
service.StartHostService(args);
}
HostService.cs
public partial class HostService : ServiceBase
{
internal void StartHostService(string[] args)
{
this.OnStart(args);
Console.ReadLine();
this.OnStop();
}
....
}
Short answer is no. There must be two configs, one for the client that consumes the WCF and one for the server that exposes that communication methods with the WCF.
In order for your client to work, your config must be set with Client Configuration
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<client>
<endpoint
name="endpoint1"
address="http://localhost/ServiceModelSamples/service.svc"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IHello"
behaviorConfiguration="IHello_Behavior"
contract="IHello" >
<metadata>
<wsdlImporters>
<extension
type="Microsoft.ServiceModel.Samples.WsdlDocumentationImporter, WsdlDocumentation"/>
</wsdlImporters>
</metadata>
<identity>
<servicePrincipalName value="host/localhost" />
</identity>
</endpoint>
// Add another endpoint by adding another <endpoint> element.
<endpoint
name="endpoint2">
//Configure another endpoint here.
</endpoint>
</client>
//The bindings section references by the bindingConfiguration endpoint attribute.
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IHello"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard">
<readerQuotas maxDepth="32"/>
<reliableSession ordered="true"
enabled="false" />
<security mode="Message">
//Security settings go here.
</security>
</binding>
<binding name="Another Binding"
//Configure this binding here.
</binding>
</wsHttpBinding>
</bindings>
//The behavior section references by the behaviorConfiguration endpoint attribute.
<behaviors>
<endpointBehaviors>
<behavior name=" IHello_Behavior ">
<clientVia />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
notice the <client> tag specifying how the client must call the WCF.
and with Server Config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="myBindingConfiguration1" closeTimeout="00:01:00" />
<binding name="myBindingConfiguration2" closeTimeout="00:02:00" />
<binding closeTimeout="00:03:00" /> <!—- Default binding for basicHttpBinding -->
</basicHttpBinding>
</bindings>
<services>
<service name="MyNamespace.myServiceType">
<endpoint
address="myAddress" binding="basicHttpBinding"
bindingConfiguration="myBindingConfiguration1"
contract="MyContract" />
<endpoint
address="myAddress2" binding="basicHttpBinding"
bindingConfiguration="myBindingConfiguration2"
contract="MyContract" />
<endpoint
address="myAddress3" binding="basicHttpBinding"
contract="MyContract" />
</service>
</services>
</system.serviceModel>
</configuration>
Notice there is no <client> tag here.
To put into context, I have a client application that will attempt to call a webservice that will be deployed on multiple web servers. The URI list will be obtained from the Settings.settings file of the client and a foreach loop will cycle through the URIs until the available service responds.
Let's say I have a service with the following contract:
[ServiceContract]
public interface ICMMSManagerService
{
[OperationContract]
ServerInfo GetServerInfo(string systemNumber);
}
In the web.config of the service's project, I have defined CMMSManager service with the the endpoint name: BasicHttpBinding_IWorkloadMngrService
<system.serviceModel>
<services>
<service name="WorkloadMngr">
<endpoint binding="basicHttpBinding" contract="IMetadataExchange" />
</service>
<service name="CMMSManager">
<endpoint binding="basicHttpBinding" contract="IMetadataExchange" name="BasicHttpBinding_IWorkloadMngrService" />
</service>
</services>
<client>
<remove contract="IMetadataExchange" name="sb" />
</client>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding>
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
On the client side, I have the following code executed when the application starts:
private void QueryWebServiceUrls()
{
var webServiceUrls = Properties.Settings.Default.WebServiceUrls;
foreach (var webServiceUrl in webServiceUrls)
{
try
{
var client = new CMMSManagerServiceClient("BasicHttpBinding_IWorkloadManagerService");
client.Endpoint.Address = new EndpointAddress(new Uri(webServiceUrl),
client.Endpoint.Address.Identity, client.Endpoint.Address.Headers);
client.Open();
var result = client.GetServerInfo("test");
}
catch (EndpointNotFoundException e)
{
continue;
}
catch (InvalidOperationException e)
{
break;
}
}
}
But the application crashes with an InvalidOperationException when the CMMSManagerServiceClient class is instanciated.
Could not find endpoint element with name
'BasicHttpBinding_IWorkloadMngrService' and contract
'ComClientService.ICMMSManagerService' 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 name could be found in the client element.
I have the following configuration in the app.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ICMMSManagerService">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/WorkloadMngr/CMMSManagerService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICMMSManagerService"
contract="ComClientService.ICMMSManagerService" name="BasicHttpBinding_ICMMSManagerService" />
</client>
</system.serviceModel>
I thought everything was valid by passing the BasicHttpBinding_ICMMSManagerService parameter to the CMMSManagerServiceClient class. I have no clue what am I missing at the moment... Any ideas?
The error is telling you exactly what's wrong: there is no endpoint with the name BasicHttpBinding_IWorkloadMngrService. The app.config says the endpoint is called BasicHttpBinding_ICMMSManagerService so your code should be:
var client = new CMMSManagerServiceClient("BasicHttpBinding_ICMMSManagerService");
Hope this helps.
I am trying to add a reference to a WCF service from my C# Desktop app.
I can add the service reference OK but as soon as I try to open the form within this desktop app I get this error:
NB. I have a UserControl that instantiates a reference to my WCF service and the control in in my GUI Form Class.
Could not find default endpoint element that references contract '' 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.
This is in my app.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMotionUpdater" messageEncoding="Mtom" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://a url/MotionUpdater.svc/MotionUpdater.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IMotionUpdater"
contract="wsCloudFeeder.IMotionUpdater" name="BasicHttpBinding_IMotionUpdater" />
</client>
</system.serviceModel>
</configuration>
And this is in my web.config file:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBindingEndPoint" maxReceivedMessageSize="10485760" messageEncoding="Mtom" closeTimeout="00:00:10" openTimeout="00:00:10" >
<readerQuotas maxArrayLength="32768"/>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="MotionUpdater" behaviorConfiguration="ThrottledBehavior">
<endpoint address="MotionUpdater.svc" binding="basicHttpBinding" bindingConfiguration="basicHttpBindingEndPoint" contract="IMotionUpdater"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ThrottledBehavior">
<serviceTimeouts transactionTimeout="1"/>
<serviceThrottling maxConcurrentCalls="64" maxConcurrentInstances="1" maxConcurrentSessions="50"
></serviceThrottling>/>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
If I invoke this reference from a browser window it displays all OK.
It is only where I have a variable in my form class I get the error:
UserControl.Class:
private static wsCloudFeeder.MotionUpdaterClient wsFeeder = new wsCloudFeeder.MotionUpdaterClient();
Server Class:
[ServiceContract]
public interface IMotionUpdater
{
[OperationContract]
void UploadMotion(byte[] jpegStream, string alias, Int16 camIndex);
}
The extra weird thing is that when I run my application it all works no problem.
Also, I have tried just doing this in my control Class but still cannot open up my GUI form..
private static wsCloudFeeder.MotionUpdaterClient wsFeeder = null;
Thanks...
New Error:
I've got a WebService with ASP.NET sites and WCF services in the same web.config. Until now, I was able to use the ASP.NET impersionation in the WCF services by setting
<system.web>
<compilation targetFramework="4.0" debug="false"/>
<!-- switch custom errors of-->
<identity impersonate="true"/>
<customErrors mode="Off"/>
</system.web>
However, now (for other reasons-> Cookieless Session state for the ASP.NET part) I have to set the
aspNetCompatibilityEnabled="true"
option to false. With this I loose the ASP.NET impersionation for the WCF services.
One of my WCF services needs impersionation for IO operations on the server...
I would like to know how to get the same impersionation I had before by directly defining it on the WCF service configuration.
What I have tried (unsucessfully) is to set
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
on the implementation of the methods in the WCF service and then specifying
<endpoint address="" binding="wsHttpBinding" contract="IService">
<identity>
<servicePrincipalName value="HOST/YourMachineName" />
<dns value="" />
</identity>
</endpoint>
in the web.config (obviously with the correct values for my service), as described in http://msdn.microsoft.com/en-us/library/ff650591.aspx.
However, the WCF service can not be called anymore after this... It tells me that the WsHttpBinding does not offer an identity for the contract.
Am I missing something important?
Edit: Translation of the error message:
: The contract operation '{0}' requires Windows identity for automatic impersonation. A Windows identity that represents the caller is not provided by binding ('{1}','{2}') for contract ('{3}','{4}'.
(The original error message was german...)
Try adding someting similar to this
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="DelegationBehaviour">
<clientCredentials>
<windows allowNtlm="false" allowedImpersonationLevel="Delegation"></windows>
</clientCredentials>
<dataContractSerializer maxItemsInObjectGraph="4194304"></dataContractSerializer>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_SampleWebService" >
<readerQuotas maxArrayLength="16384" maxBytesPerRead="4096" maxDepth="32" maxNameTableCharCount="16384" maxStringContentLength="8192"></readerQuotas>
<security mode="TransportCredentialOnly">
<message algorithmSuite="Default" clientCredentialType="UserName"></message>
<transport clientCredentialType="Windows" proxyCredentialType="None" realm=""></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://server/WebServices/Service/Service.svc" behaviorConfiguration="DelegationBehaviour" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_SampleWebService" contract="SampleWS" name="BasicHttpBinding_SampleEndpoint"></endpoint>
</client>
</system.serviceModel>
This is the server side code
<system.serviceModel>
<services>
<service behaviorConfiguration="CustomBehavior" name="CustomWebService">
<endpoint address="" behaviorConfiguration="" binding="basicHttpBinding" bindingConfiguration="basicHttpBinding_Service" contract="WebService"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBinding_Service" maxReceivedMessageSize="4194304" receiveTimeout="00:30:00">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CustomBehavior">
<dataContractSerializer maxItemsInObjectGraph="4194304" ignoreExtensionDataObject="True"/>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true"/>
<serviceAuthorization impersonateCallerForAllOperations="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
As well as having these over our WebMethods
<WebMethod(), OperationContract(), OperationBehavior(Impersonation:=ImpersonationOption.Required)> _
Works for us
Well, in the end I just made the binding use Windows authentication:
<security mode="TransportWithMessageCredential">
<message negotiateServiceCredential="false" clientCredentialType="Windows" algorithmSuite="Default"/>
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
</security>
and passed a specific Windows user/pwd combination in the client:
channelFactory.Credentials.Windows.ClientCredential = new NetworkCredential(#"", "", "");
channelFactory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
Additionally I had to specifically use the newly impersonated user in the code of the web service:
using (var imp = ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
{
// do IO here
}
Well, the actual (underlying) question still remains:
How is it possible to emulate the ASP.NET functionality correctly...
For the moment I'm ok with the solution, however I've got the feeling that I've missed an important point about the ASP.NET impersonation.
Thanks a lot to Iain, although it wasn't exactly the correct answer, it at least got me on the right track!
I've created a simple WCF Service which is hosted in IIS. Now i want to use my own userName authentication.
My web.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MyBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="WcfIIsBasicAuthTest.Service1" behaviorConfiguration="MyBehavior">
<endpoint address=""
binding="basicHttpBinding"
contract="WcfIIsBasicAuthTest.IService1"
bindingConfiguration="MyBinding"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfIIsBasicAuthTest.MyValidator, WcfIIsBasicAuthTest"/>
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
The Validator
namespace WcfIIsBasicAuthTest
{
public class MyValidator :UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if(!(userName == "test" && password == "test"))
{
throw new SecurityTokenException("Validation Failed!");
}
}
}
}
If i start this WCF Service from within visual studio, i get the following error: The authentication schemes configured on the host ('Ntlm, Anonymous') do not allow those configured on the binding 'BasicHttpBinding' ('Basic').
If i try to connect to the service if it is hosted in IIS, i get error messages depending on which authentication type is set, but it doesn't work at all.
Error if only Anonymous authentication is enabled: The authentication schemes configured on the host ('Anonymous') do not allow those configured on the binding 'BasicHttpBinding' ('Basic').
If i set Basic Authentication in IIS, it demands a valid local user which i don't want to provide(since i want to write my own userprovider).
Any hints/links how to setup such a basic auth userprovider with wcf and iis?
Can you set the below configuration for using your own UserNameValidator:
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
For that to work with basicHttpBinding you would need to have HTTPS setup as WCF doesnt allow username password being passed over the channel in clear text. The other alternative is to use wsHttpBinding.