in my application I am referencing a WSDL service by "Add Service Reference"
then a service reference is created. with this entry in web.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IExternalOrder" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://xx.xxx.com/ExternalOrder.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IExternalOrder"
contract="WebReference.IExternalOrder" name="BasicHttpBinding_IExternalOrder" />
</client>
</system.serviceModel>
at this point I am trying to call this WSDL functions, in order to get the data that I need:
var GetOrderDetails_answer = ServiceHelper.GetOrderDetails(creds, this.OrderId);
inside ServiceHelper class:
public static GetAdminOrderDetailResponse GetOrderDetails(Request creds, string orderId)
{
////////////////////////////////////////////////////
ExternalOrderClient EOC = new ExternalOrderClient();
////////////////////////////////////////////////////
var GAOD = new GetAdminOrderDetailRequest
{
OrderID = orderId,
Password = creds.Password,
SiteID = creds.SiteID,
UserName = creds.UserName
};
try
{
return EOC.GetAdminOrderDetail(GAOD);
}
catch (Exception e)
{
/// TODO: log the error
return null;
}
}
The creation of the object ExternalOrderClient between "/////////////" lines
is throwing an exception:
Could not find default endpoint element that references contract
'WebReference.IExternalOrder' in the ServiceModel client configuration
section.
I tried every solution I could find (most of them are about calling the WSDL from other project, but i have only 1 project)
What is the fix for that?
Related
I have construct a simple secured wcf with wsHttpBinding in .Net C# (framework 4.5) and consume it from .Net C# (also) client and every thing work fine. But when I try to consume It from php (5.5) client by calling a method from the wcs service, the client not work and it has entered in an infinite loop and not showing any error message, just looping.
a. The following is my wcf ServiceContract and OperationContract's:
namespace CenteralServices
{
[ServiceContract]
public interface IAdminServices
{
[OperationContract]
int Add(int x, int y);
}
}
b. The following is the configueration file Web.config for the wcf:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<services>
<service name= "CentralTicketServicesSystem.AdminSystem"
behaviorConfiguration="customBehaviour">
<endpoint address="AdminServices"
binding="wsHttpBinding"
contract="CentralTicketServicesSystem.IAdminServices"
bindingConfiguration="ServiceBinding"
behaviorConfiguration="MyEndPointBehavior">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/AdminServicesSystem" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="ServiceBinding"
openTimeout="00:10:00"
closeTimeout="00:10:00"
receiveTimeout="00:10:00"
sendTimeout="00:10:00">
<security mode="Message" >
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="MyEndPointBehavior">
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="customBehaviour">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="CentralServicesHost.AuthorizationPolicy, CentralServicesHost" />
</authorizationPolicies>
</serviceAuthorization>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="CentralServicesHost.UserAuthentication, CentralServicesHost"/>
<serviceCertificate findValue="15 63 10 5e b6 4b 4d 85 4b 2e 4d 5b ec 85 02 ec"
storeLocation="LocalMachine"
x509FindType="FindBySerialNumber"
storeName="My"/>
</serviceCredentials>
</behavior>
<behavior name="mexBehaviour" >
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
c. The following is UserAuthentication class:
namespace CentralServicesHost
{
public class UserAuthentication : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (string.IsNullOrEmpty(userName))
throw new ArgumentNullException("userName");
if (string.IsNullOrEmpty(password))
throw new ArgumentNullException("password");
if (userName != "test" && password != "test")
throw new FaultException("Unknown Username or Incorrect Password.");
}
}
}
d. The following is AuthorizationPolicy class:
namespace CentralServicesHost
{
public class AuthorizationPolicy : IAuthorizationPolicy
{
Guid _id = Guid.NewGuid();
// this method gets called after the authentication stage
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
// get the authenticated client identity
IIdentity client = GetClientIdentity(evaluationContext);
// set the custom principal
evaluationContext.Properties["Principal"] = new CustomPrincipal(client);
return true;
}
private IIdentity GetClientIdentity(EvaluationContext ec)
{
object obj;
if (!ec.Properties.TryGetValue("Identities", out obj))
throw new Exception("No Identity found");
IList<IIdentity> identities = obj as IList<IIdentity>;
if (identities == null || identities.Count <= 0)
throw new Exception("No Identity found");
return identities[0];
}
public System.IdentityModel.Claims.ClaimSet Issuer
{
get { return ClaimSet.System; }
}
public string Id
{
get { return _id.ToString(); }
}
}
}
e. The following is CustomPrincipal class:
namespace CentralServicesHost
{
class CustomPrincipal : IPrincipal
{
IIdentity _identity;
string[] _roles;
public CustomPrincipal(IIdentity identity)
{
_identity = identity;
}
// helper method for easy access (without casting)
public static CustomPrincipal Current
{
get
{
return Thread.CurrentPrincipal as CustomPrincipal;
}
}
public IIdentity Identity
{
get { return _identity; }
}
// return all roles
public string[] Roles
{
get
{
EnsureRoles();
return _roles;
}
}
// IPrincipal role check
public bool IsInRole(string role)
{
EnsureRoles();
return (_roles != null) ? _roles.Contains(role) : false;
}
// read Role of user from database
protected virtual void EnsureRoles()
{
using (var s = new SupportedMaterialsSystemEntities())
{
_roles = new string[1] { "admin" };
}
}
}
}
f. The following is my php client code:
<?php
$options = array('soap_version' => SOAP_1_2,
'login' => 'test',
'password' => 'test');
$wsdl = "http://localhost:8080/AdminServicesSystem";
$client = new SoapClient($wsdl, $options);
$obj = new stdClass;
$obj->x = 3;
$obj->y = 3;
$retval = $client->Add($obj);//here the browser loops for infinite without any response.
//var_dump($exc);//THIS POINT NOT REACHED
//die();
$result = $retval->AddResult;
echo $result;
NOTES:
1. My OS is Win. 8.1, and I'm using visual studio 2013 (as adminstrator) and php Wamp Server.
2. I tried both, hosting the wcf service in IIS 6.2 and console application but non of them changes my php client looping.
3. I have Created the self-signed certificate usin the IIS manager that stores it in my local machine.
4. When I change the soap_version in the php code from SOAP_1_2 to SOAP_1_1 I had Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'..
Last Note:
My .Net C# Client code is the following:
using (var svcProxy = new AdminServiceProxy.AdminServicesSystemClient())
{
svcProxy.ClientCredentials.UserName.UserName = "test";
svcProxy.ClientCredentials.UserName.Password = "test";
Console.WriteLine(svcProxy.Add(1, 1));//the service works fine and print 2
}
}
So agin, What is the right way to call a secured wcf (with wsHttpBinding) service from php.
I believe you need a default WSDL metadata published to use PHP soap client (see abilities here http://php.net/manual/en/intro.soap.php).
Try to add endpoint with basicHttpBinding binding, which can provide WSDL for your client and then use this endpoint.
On the address http://localhost:8080/AdminServicesSystem you have endpoint with mexHttpBinding, which provides metadata int other format (http://www.w3.org/TR/2009/WD-ws-metadata-exchange-20090317/).
Try to see here form more details: https://abhishekdv.wordpress.com/2013/05/24/mexhttpbinding-vs-wsdl/
I have a Windows Service which represents the WCF-Host and a WPF-Client-Application wich represents the WCF-Client.
The communication should be duplex so I went with WSDualHttpBinding.
At first I install and start my Service which opens a WCF connection after that I start my WPF app and I get the following error (I translated it):
No default endpoint was found to the contract
\ " WCFCloudManagerFolderWatcherService.Interfaces.IFilesDuplex \ " in the service model client configuration section
refers. This may be caused by: For the purposes of no configuration file was found
or in the client element no endpoint element was found , which corresponded to this contract .
Contracts:
IFilesDuplex-Contract:
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode = SessionMode.Required,
CallbackContract = typeof(IFilesDuplexCallback))]
public interface IFilesDuplex
{
[OperationContract(IsOneWay = true)]
void Update();
}
IFilesDuplexCallback:
interface IFilesDuplexCallback
{
[OperationContract(IsOneWay = true)]
void Equals(string[] result);
}
ClientSide
CallbackHandler:
class CallbackHandler : IFilesDuplexCallback
{
public event Action<string[]> ReceivedList = delegate { };
public void Equals(string[] result)
{
this.ReceivedList(result);
}
}
The Client itself:
class FilesDuplexClient : DuplexClientBase<IFilesDuplex>, IFilesDuplex
{
public FilesDuplexClient(InstanceContext callbackCntx)
: base(callbackCntx)
{
}
public void Update()
{
base.Channel.Update();
}
}
And the Code from the Main Window, where the error is thrown:
CallbackHandler ch = new CallbackHandler();
ch.ReceivedList += ch_ReceivedList;
// Construct InstanceContext to handle messages on callback interface
InstanceContext instanceContext = new InstanceContext(ch);
// Create a client
FilesDuplexClient client = new FilesDuplexClient(instanceContext);
client.Update();
Serverside (Windows Service)
FileProtocoll-Class (Server code)
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class FileProtocoll : IFilesDuplex
{
IFilesDuplexCallback Callback
{ get { return OperationContext.Current.GetCallbackChannel<IFilesDuplexCallback>(); } }
void IFilesDuplex.Update()
{
//....
Callback.Equals(null);// just a dummy
//...
}
}
Code in the OnStart-Method (in a Thread):
// Step 1 Create a URI to serve as the base address.
Uri baseAddress = new Uri("http://localhost:8899/CloudManager/CommunicationChannel1");
// Step 2 Create a ServiceHost instance
if (selfHost != null)
{
selfHost.Close();
}
selfHost = new ServiceHost(typeof(FileProtocoll), baseAddress);
try
{
// Step 5 Start the service.
selfHost.Open();
}
catch (CommunicationException ce)
{
selfHost.Abort();
}
Code in the OnStop-Method (in a Thread):
if (selfHost != null)
{
if (selfHost.State != CommunicationState.Closed)
{
selfHost.Close();
}
selfHost = null;
}
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<system.serviceModel>
<services >
<service behaviorConfiguration="ServiceBehavior"
name="WCFCloudManagerFolderWatcherService.Communication.FileProtocoll">
<endpoint address="http://localhost:8899/CloudManager /CommunicationChannel1"
binding="wsDualHttpBinding" contract="WCFCloudManagerFolderWatcherService.Interfaces.IFilesDuplex">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true "/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I finally got it.
Had to make a few changes to my Client app.config and had to turn off security.
app.config(client):
<!-- WCF Client information-->
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_IFilesDuplex">
<security mode="None"/>
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint
address="http://localhost:8899/CloudManager/CommunicationChannel1"
binding="wsDualHttpBinding"
bindingConfiguration="WSDualHttpBinding_IFilesDuplex"
contract="WCFCloudManagerFolderWatcherService.Interfaces.IFilesDuplex"
name="WSDualHttpBinding_IFilesDuplex">
<identity>
<userPrincipalName value="localhost"/>
</identity>
</endpoint>
</client>
and in the app.config for the serverside I also hat to set
<security mode="None"/>
Now the connection works.
I'm busy writing a file server/client tool that basically uses a hosted Service to send and receive data to and from the server. Since this solution will be used by many different people, its not really advisable to have them go and edit the App.Config file for their setup. What I would like to do is change this at runtime so that the user(s) have full control over the settings to use. So, this is my App.Config file:
<system.serviceModel>
<services>
<service name="FI.ProBooks.FileSystem.FileRepositoryService">
<endpoint name="" binding="netTcpBinding"
address="net.tcp://localhost:5000"
contract="FI.ProBooks.FileSystem.IFileRepositoryService"
bindingConfiguration="customTcpBinding" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="customTcpBinding" transferMode="Streamed" maxReceivedMessageSize="20480000" />
</netTcpBinding>
</bindings>
</system.serviceModel>
What I would like to do is to change only the address (in this example, net.tcp://localhost:5000) when the application is executed. So I must be able to read the current value and display that to the user, and then take their input and save it back into that field.
The test below may help you. Essentially the steps are
Instantiate an instance of the host that reads the configuration from the .config file;
Create a new instance of EndpointAddress using the same configuration as the old one, but changing the uri and assign it to the Address property of your ServiceEndpoint.
[TestMethod]
public void ChangeEndpointAddressAtRuntime()
{
var host = new ServiceHost(typeof(FileRepositoryService));
var serviceEndpoint = host.Description.Endpoints.First(e => e.Contract.ContractType == typeof (IFileRepositoryService));
var oldAddress = serviceEndpoint.Address;
Console.WriteLine("Curent Address: {0}", oldAddress.Uri);
var newAddress = "net.tcp://localhost:5001";
Console.WriteLine("New Address: {0}", newAddress);
serviceEndpoint.Address = new EndpointAddress(new Uri(newAddress), oldAddress.Identity, oldAddress.Headers);
Task.Factory.StartNew(() => host.Open());
var channelFactory = new ChannelFactory<IFileRepositoryService>(new NetTcpBinding("customTcpBinding"), new EndpointAddress(newAddress));
var channel = channelFactory.CreateChannel();
channel.Method();
(channel as ICommunicationObject).Close();
channelFactory = new ChannelFactory<IFileRepositoryService>(new NetTcpBinding("customTcpBinding"), oldAddress);
channel = channelFactory.CreateChannel();
bool failedWithOldAddress = false;
try
{
channel.Method();
}
catch (Exception e)
{
failedWithOldAddress = true;
}
(channel as ICommunicationObject).Close();
Assert.IsTrue(failedWithOldAddress);
}
you can create the service instance providing a configuration name and endpoint. So you can use;
EndpointAddress endpoint = new EndpointAddress(serviceUri);
var client= new MyServiceClient(endpointConfigurationName,endpoint )
look at msdn article.
I have a problem connecting to my WCF service with clientCredentialType="UserName".
When I run the code below I get an error
FaultException: An error occurred when verifying security for the message.
When playing around with some of the binding values I also get Access is denied..
Fiddler says there is no authorization header and I cannot find the username or password in the request either.
Here are excerpts from my config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<services>
<service name="InventoryServices.MobileAPI" behaviorConfiguration="customBehaviour">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="InventoryServices.IMobileAPI"/>
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="customBehaviour">
<serviceSecurityAudit auditLogLocation="Application" serviceAuthorizationAuditLevel="Failure" messageAuthenticationAuditLevel="Failure" suppressAuditFailure="true" />
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpsGetEnabled="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"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="InventoryLibrary.Helpers.UserAuthentication,InventoryLibrary"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Basic" proxyCredentialType="Basic" realm="MyRealm"/>
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
My username/password validator looks like so:
public class UserAuthentication : UserNamePasswordValidator {
public override void Validate(string userName, string password) {
EntitiesContext db = new EntitiesContext();
db.Logs.Add(new DomainModels.Log() {
DateLogged = DateTime.Now,
Message = "hit auth",
Type = DomainModels.LogType.Info
});
db.SaveChanges();
try {
if (userName == "test" && password == "test123") {
Console.WriteLine("Authentic User");
}
}
catch (Exception ex) {
throw new FaultException("Unknown Username or Incorrect Password");
}
}
}
I have this as a simple test on my service:
[OperationContract]
[XmlSerializerFormat]
void Test();
[PrincipalPermission(SecurityAction.Demand, Name = "test")]
public void Test() {
}
I have a self signed SSL certificate on my server and I can access my service/metadata.
Then I have added a service reference in a console application, and attempt to connect to the service with this code below:
class Program {
static void Main(string[] args) {
Stuff.InitiateSSLTrust();
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.Realm = "MyRealm";
ServiceReference1.MobileAPIClient serviceProxy = new ServiceReference1.MobileAPIClient(binding, new EndpointAddress("https://xx.xx.xx.xx/InventoryServices.MobileApi.svc"));
serviceProxy.ClientCredentials.UserName.UserName = "test";
serviceProxy.ClientCredentials.UserName.Password = "test123";
try {
var a = serviceProxy.Login("a", "b");
}
catch (Exception ex) {
var ex2 = ex;
}
}
}
public class Stuff {
public static void InitiateSSLTrust() {
try {
//Change SSL checks so that all checks pass
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(
delegate { return true; }
);
}
catch (Exception ex) {
}
}
}
I've checked the event viewer on the server and this error appears with each request:
MessageSecurityException: Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security.
You are specifying the client side to use BasicHttpSecurityMode.Transport whereas the service is expecting BasicHttpSecurityMode.TransportWithMessageCredential. This is a problem because the service is looking for the client credentials in the SOAP Message Header and the client will not send them with the binding configured this way.
Hence, this is why the username/password pair is not present in the Message Header as you are witnessing. So the event viewer was correct that there was a binding mismatch between the communicating parties.
Also set the ClientCredentialType on the client to BasicHttpMessageCredentialType.UserName for Message level security. By default BasicHttpBinding uses None which are anonymous clients.
Here's a code snippet describing the above changes:
var basicHttpBinding = new BasicHttpBinding(
BasicHttpSecurityMode.TransportWithMessageCredential);
basicHttpBinding.Security.Message.ClientCredentialType =
BasicHttpMessageCredentialType.UserName;
This can also be caused by the time being out of sync between client and server. If a certificate or signed token is invalid based off of time, the same An error occurred when verifying security for the message. message may be returned.
Just edit the .csproj file after adding the service reference and point these dependencies from 4.4.* to 4.6.*
<ItemGroup> <PackageReference Include="System.ServiceModel.Duplex" Version="4.6.*" />
<PackageReference Include="System.ServiceModel.Http" Version="4.6.*" />
<PackageReference Include="System.ServiceModel.NetTcp" Version="4.6.*" />
<PackageReference Include="System.ServiceModel.Security" Version="4.6.*" />
</ItemGroup>
and add this
binding.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
Here I am trying to read my service endpoint address by name from web.config
ClientSection clientSection = (ClientSection)ConfigurationManager.GetSection("system.serviceModel/client");
var el = clientSection.Endpoints("SecService"); // I don't want to use index here as more endpoints may get added and its order may change
string addr = el.Address.ToString();
Is there a way I can read end point address based on name?
Here is my web.config file
<system.serviceModel>
<client>
<endpoint address="https://....................../FirstService.svc" binding="wsHttpBinding" bindingConfiguration="1ServiceBinding" contract="abc.firstContractName" behaviorConfiguration="FirstServiceBehavior" name="FirstService" />
<endpoint address="https://....................../SecService.svc" binding="wsHttpBinding" bindingConfiguration="2ServiceBinding" contract="abc.secContractName" behaviorConfiguration="SecServiceBehavior" name="SecService" />
<endpoint address="https://....................../ThirdService.svc" binding="wsHttpBinding" bindingConfiguration="3ServiceBinding" contract="abc.3rdContractName" behaviorConfiguration="ThirdServiceBehavior" name="ThirdService" />
</client>
</system.serviceModel>
This will work clientSection.Endpoints[0];, but I am looking for a way to retrieve by name.
I.e. something like clientSection.Endpoints["SecService"], but it's not working.
This is how I did it using Linq and C# 6.
First get the client section:
var client = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;
Then get the endpoint that's equal to endpointName:
var qasEndpoint = client.Endpoints.Cast<ChannelEndpointElement>()
.SingleOrDefault(endpoint => endpoint.Name == endpointName);
Then get the url from the endpoint:
var endpointUrl = qasEndpoint?.Address.AbsoluteUri;
You can also get the endpoint name from the endpoint interface by using:
var endpointName = typeof (EndpointInterface).ToString();
I guess you have to actually iterate through the endpoints:
string address;
for (int i = 0; i < clientSection.Endpoints.Count; i++)
{
if (clientSection.Endpoints[i].Name == "SecService")
address = clientSection.Endpoints[i].Address.ToString();
}
Well, each client-side endpoint has a name - just instantiate your client proxy using that name:
ThirdServiceClient client = new ThirdServiceClient("ThirdService");
Doing this will read the right information from the config file automatically.