WCF : Client > Endpoint > Error : Invalid URI on working URL - c#

I am setting up a WCF Selfhosted solution to use as a WCF Router and am having a little trouble in getting the service started.
The application code is
public class Program
{
static void Main(string[] args)
{
ServiceHost routingHost = new ServiceHost(typeof(RoutingService));
routingHost.Open();
Console.WriteLine("Routing Service is running");
Console.WriteLine("Press [Enter] to exit");
Console.ReadLine();
routingHost.Close();
}
}
and the App.Config Services Section is
<system.serviceModel>
<services>
<service name="System.ServiceModel.Routing.RoutingService">
<endpoint address="net.tcp://localhost:8009/proposalRouter"
binding="netTcpBinding"
contract="System.ServiceModel.Routing.IRequestReplyRouter"
name="proposalRouter" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDebug includeExceptionDetailInFaults="true" />
<routing filterTableName="proposalRoutingTable" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding sendTimeout="00:45:00" maxReceivedMessageSize="2000000" />
</netTcpBinding>
</bindings>
<routing>
<filters>
<filter name="proposalFilter" filterType="EndpointAddress" filterData="proposalRouter"/>
</filters>
<filterTables>
<filterTable name="proposalRoutingTable">
<add filterName="proposalFilter" endpointName="defaultProposalService"/>
</filterTable>
</filterTables>
</routing>
<client>
<endpoint address="http://localhost:64434/ProposalService.svc"
binding="basicHttpBinding"
contract="*"
name="defaultProposalService"/>
</client>
The error given is :
Invalid URI: The format of the URI could not be determined.
The issue I have narrowed down to client > endpoint but that is the uri of the svc do not sure what the issue is
I would be grateful if someone could show me where I have gone wrong.

The filter in your configuration file is wrong. When the value of filtertype is address, the filterdata should be a URI.
So your filter should look like this:
<filters>
<filter name="proposalFilter" filterType="EndpointAddress" filterData="net.tcp://localhost:8009/proposalRouter"/>
</filters>
For more information about FilterData Property,Please refer to the following link:
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.routing.configuration.filterelement.filterdata?view=netframework-4.8

Related

WCF UserName & Password validation using wshttpbinding notworking

I am new to WCF Service authentication, I was trying to achieve wcfauthentication using wshttpbinding. but i am getting below exception.
Could not find a base address that matches scheme https for the endpoint with binding WSHttpBinding. Registered base address schemes are [http].
Web.Config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttp">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="WCFAuth.Service1" behaviorConfiguration="wsHttpBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttp" contract="WCFAuth.IService1">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:64765/"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="wsHttpBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCFAuth.ServiceAuthanticator, WCFAuth"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Service Authentication class:
using System;
using System.Collections.Generic;
using System.IdentityModel.Selectors;
using System.Linq;
using System.ServiceModel;
using System.Web;
namespace WCFAuth
{
public class ServiceAuthanticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
string AppUserName = "ABC";
string AppPwd = "abc";
try
{
if (userName.ToLower() != AppUserName.ToLower() && password != AppPwd)
{
throw new FaultException("Unknown Username or Incorrect Password");
}
}
catch (Exception ex)
{
throw new FaultException("Unknown Username or Incorrect Password");
}
}
}
}
Client Side config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<!--<binding name="base" />-->
<binding name="base">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:64765/Service1.svc" binding="basicHttpBinding"
bindingConfiguration="base" contract="WCFAuth.IService1" name="base" />
</client>
</system.serviceModel>
</configuration>
Consumer:
class Program
{
static void Main(string[] args)
{
try
{
WCFAuth.Service1Client client = new WCFAuth.Service1Client();
client.ClientCredentials.UserName.UserName = "test";
client.ClientCredentials.UserName.Password = "test";
var temp = client.GetData(1);
Console.WriteLine(temp);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}
}
I am getting attached exception when i try to browser svc file.
Can someone correct me, where i am committing mistake, thanks in advance.
The problem here is that you are using a WSHttpBinding with Transport Security, but the base address you set is http. It is not possible to work with http here, because you are sending credentials over the wire.
Either change it to https, or create a second binding configuration for development purposes. One with Transport Security (https), and a second without (http).
Also make sure that your clients binding matches the binding from your server.
As Marc mentioned, we are supposed to provide a certificate when hosting the service. there might be something amiss during the process of hosting the service.
Here is a reference configuration, wish it is useful to you.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttp">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="WCFAuth.Service1" behaviorConfiguration="wsHttpBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttp" contract="WCFAuth.IService1">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="wsHttpBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WCFAuth.ServiceAuthanticator, WCFAuth"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Then we should add a https binding in IIS Site Bindings module.
The service address would be https://x.x.x.x:8865/Service1.svc
One thing must be noted that we should trust the service certificate when we call the service by adding service reference.
ServicePointManager.ServerCertificateValidationCallback += delegate
{
return true;
};
ServiceReference2.Service1Client client = new ServiceReference2.Service1Client();
client.ClientCredentials.UserName.UserName = "jack";
client.ClientCredentials.UserName.Password = "123456";
Besides, if we use SecurityMode.Message, we are supposed to provide a certificate in code snippets.
<serviceCredentials>
<serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="869f82bd848519ff8f35cbb6b667b34274c8dcfe"/>
<userNameAuthentication customUserNamePasswordValidatorType="WcfService1.CustUserNamePasswordVal,WcfService1" userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
Feel free to let me know if there is anything I can help with.

WCF service endpoint not accessible in self-hosting

I have created a IDummyService contract implemented by DummyService. I am trying to self-host this service using the following configuration:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<system.serviceModel>
<services>
<service name="DummyService.DummyService" behaviorConfiguration="MEX">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/" />
</baseAddresses>
</host>
<endpoint address="DummyService"
binding="basicHttpBinding"
contract="DummyService.IDummyService"/>
<endpoint address="net.tcp://localhost:8734/DummyService/"
binding="netTcpBinding"
bindingConfiguration = "TransactionalTCP"
contract="DummyService.IDummyService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name = "TransactionalTCP" transactionFlow = "true"/>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name = "MEX">
<serviceMetadata/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
The Service Host code that runs fine and starts these endpoints. However, when I try to access the following endpoints I get error as Page isn't working in Chrome browser.
http://localhost:8733/DummyService/
http://localhost:8733/mex/
However, I can access the page http://localhost:8733/
I don't understand why is that.
I thought the endpoint address is address entry for that endpoint appended to host's baseaddress
Any ideas what I am doing wrong ?
Thanks.
You have applied the attribute behaviorConfiguration="MEX" but didnt make use of it,you need to enable the metadata discovery which is false by default in WCF for security reasons.
<serviceBehaviors>
<behavior name = "MEX">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
Now when you browse the http://localhost:8733/DummyService/ and http://localhost:8733/mex/ ,a blank page will be displayed in the browser,instead of default error page.
And also if you want to test the net.tcp endpoint you can use WCFtestclient.exe.

Https wcf webservice Error

<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<endpointBehaviors>
<behavior name="webHttp">
<webHttp />
</behavior>
<behavior name="webHttpBehavior">
<webHttp />
</behavior></endpointBehaviors>
</behaviors>
<services>
<service name="Implementation.Service" behaviorConfiguration="serviceBehavior">
<endpoint address="" binding="basicHttpBinding" contract="Contract.IService" behaviorConfiguration="web" bindingConfiguration="basicHttpBinding"></endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="CodeItSoap" closeTimeout="00:01:00">
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType ="Basic" realm =" "/>
<message clientCredentialType= "username" algorithm ="default">
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://******.****-***/*****_*****?SOAP"
binding="basicHttpBinding" bindingConfiguration="CodeItSoap"
contract="Service.CodeItSoap" name="CodeItSoap" />
</client>
</system.serviceModel>
</configuration>
This is just a sample of my web.config file. When I run the service in the local host it runs fine and with the help of wcf test client I am getting the required output.
But when I put the dlls & web.config in the server where I have to host the service it's throwing an error
"Could not find a base address that matches scheme HTTP for the endpoint with binding BasicHttpBinding. Registered base address schemes are [https]"
Could any one tell me what the reason for the above error is?
General Flow of my web service
Application -> Server hosting(calc.svc) -> https://******.****-*/*****_*****?SOAP(authenticated)
when i add the service reference app.config got generated and by default basichttpbinding got added to app.config file.
As per my understanding web.config file is used to host the service in iis & i think my web.config is wrong.
In the client end point what should be the end point to calc.svc or https://*?soap?
Is the basichttpbinding ok for the https://prd36/calc.svc url?
do i need to specify one more binding for the application too?
Please help me understand i am heavily confused as the web.config which i have edited is a existing one which is still running the old service reference.
<serviceMetadata httpsGetEnabled="true"/>
<endpoint address="json" binding="webHttpBinding" contract="Contract.IService" behaviorConfiguration="web"></endpoint>
<endpoint address="mex" binding="mexHttpsinding" contract="IMetadataExchange"/>
above changes i did and the service url is running in web browser.
Use http:// instead of https:// in your endpoint address.
OR
User BasicHttpsBinding instead of BasicHttpBinding in your endpoint.
follow this link if the problem still exist.

Customizing ServiceAuthorizationManager for WCF Issue

I have created custom ServiceAuthorizationManager as "CustomUserNamePasswordValidator" for my WCF project. below is the snippet of my project. I want my wcf to call up this authorication class before it actually start calling on WCF API but this is not happening. My "Login" WCF API is calling paraller to this authorization class. so when there is call by client to Login it calls both
"CustomUserNamePasswordValidator" and Login method simultaneously.
Authorization Class
public class CustomUserNamePasswordValidator : ServiceAuthorizationManager
{
HttpRequestMessageProperty httpProperties;
string operationName;
protected override bool CheckAccessCore(OperationContext operationContext)
{
operationName = GetOperationName(operationContext);
httpProperties = (HttpRequestMessageProperty)operationContext.IncomingMessageProperties["httpRequest"];
string authHeader = httpProperties.Headers[HttpRequestHeader.Authorization];
string subno = string.Empty;
string password = string.Empty;
string version = string.Empty;
string credntialType = string.Empty;
string[] credentials = authHeader.Split(':');
credntialType = credentials[0];
password = credentials[1];
if (!AuthorizeUser(password))
{
throw new ArgumentException("401:Token invalid or expired.(0x000)");
}
}
}
private int AuthenticateUser(string subno, string pin, string version)
{
}
}
WCF Client Service Snippet
public class ClientService : IClientService
{
public wsLoginResult LoginUser()
{
HttpRequestMessageProperty httpReqProps = (HttpRequestMessageProperty)OperationContext.Current.IncomingMessageProperties["httpRequest"];
string res = httpReqProps.Headers[HttpRequestHeader.Authorization];
foreach (var item in res.Split(':'))
ActivityLog("Activity", "Login Steps", item, item);
}
}
Web.Config Snippet
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="wmas_subsConnectionString" connectionString="Data Source=WT;Initial Catalog=wmas;User ID=sa;Password=ra3?" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<compilation targetFramework="4.5" debug="true"/>
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<client>
<endpoint address="http://192.168.1.12:7002/MobileApplicationWS/MobileApplicationApiWSImplService"
binding="basicHttpBinding" bindingConfiguration="MobileApplicationApiWSPortBinding"
contract="VASService.MobileApplicationApiWS"
name="MobileApplicationApiWSPort" />
</client>
<services>
<service name="ClientService.ClientService" behaviorConfiguration="ClientService.ServiceBehavior">
<endpoint address=""
binding="webHttpBinding" bindingConfiguration="webHttpBindingConfiguration"
contract="ClientService.IClientService" behaviorConfiguration="webBehaviour"/>
<endpoint address="stream"
binding="webHttpBinding" bindingConfiguration="webHttpBindingConfigurationStreamed"
contract="ClientService.IClientService" behaviorConfiguration="webBehaviour"/>
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="MobileApplicationApiWSPortBinding" />
</basicHttpBinding>
<webHttpBinding>
<binding name="webHttpBindingConfiguration" />
<binding name="webHttpBindingConfigurationStreamed" transferMode="StreamedResponse" />
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ClientService.ServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization serviceAuthorizationManagerType="ClientService.CustomUserNamePasswordValidator, ClientService" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehaviour">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
The reason why your solution doesn't work is that CustomUserNamePasswordValidator can't be used in a RESTful service. Take a look at: http://msdn.microsoft.com/en-us/library/aa354513(v=vs.110).aspx
The example uses SOAP and defines the behaviour of the endpoint which activates serviceAuthorization tag. If you don't define the security of the endpoint the serviceAuthorization simply won't work.
<bindings>
<wsHttpBinding>
<!-- username binding -->
<binding name="Binding">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
In a RESTful service there is no SecurityMode = Message, there are only 3: None/Transport/TransportCredentialOnly. Read on about it here: http://msdn.microsoft.com/en-us/library/bb924478(v=vs.110).aspx
clientCredentialType="UserName" is only available in Message.
You can try defining the endpoint security mode to: Transport and then the credential type to: Basic/Certificate/Digest/None/Ntlm/Windows, but seeing as your solution is none of these not sure how well that will work.
There is (I think) a better way of doing authentication if you are extracting headers and not using any "approved" way. Try implementing an extension service: http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iparameterinspector(v=vs.110).aspx
Good Luck!

Error in Web Service when Deployed to DMZ

I have a webservice which I can get to run on my computer, but when deployed to a webserver (in a DMZ) it doesn't work.
When running the service on the web server, it shows a WSDL and singleWSDL that seemingly appear to be correct. Using the singleWSDL in SoapUI to test the service returns the following error message
The message could not be processed. This is most likely because the
action 'http://tempuri.org/IService1/TestStringContract' is incorrect
or because the message contains an invalid or expired security context
token or because there is a mismatch between bindings. The security
context token would be invalid if the service aborted the channel due
to inactivity. To prevent the service from aborting idle sessions
prematurely increase the Receive timeout on the service endpoint's
binding.
From what I gather, the most likely cause, is an issue in the App.Config file, which I have detailed herein
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="MyService.Service1" behaviorConfiguration="MyService.Service1Behavior">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:{port}/MyService.Service1.svc" />
</baseAddresses>
</host>
<endpoint address="http://{external_ip}:{port}/MyService.Service1.svc" binding="wsHttpBinding" contract="MyService.IService1">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="EquitaWcfCbl.Service1Behavior">
<serviceThrottling maxConcurrentCalls="10"/>
<serviceMetadata httpGetEnabled="True" httpGetUrl="http://{external_ip}:{port}/EquitaWcfCblMyService.Service1.svc/mex"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
[update # 2014-02-19 1400hrs]
With further research continually pointing that the setup of the App.Config; I decided to pull out the current App.Config file and start it again, from scratch, using the WCF Service Configuration Editor, which is built into Visual Studio (tools menu) adding in the information a piece at a time and testing progress, which resulted in a working service with the following App.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior1">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata
httpGetEnabled="true"
httpGetUrl=" http://{externalip}:{port}/MyService.Service1.svc/mex"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding>
<security mode="None"></security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service
behaviorConfiguration="ServiceBehavior1"
name="EquitaWcfCbl.TabletService">
<endpoint
address="http://{externalip}:{port}/MyService.Service1.svc/mex"
binding="basicHttpBinding"
bindingConfiguration=""
name="ServiceEndpoint1"
contract=" MyService.Service1" />
</service>
</services>
</system.serviceModel>
</configuration>
I'm not (yet) entirely convinced that this is exactly what we need, but with a working service ... I can at least progress.

Categories