For a IIS hosted service I have to get the full address of the local machine.
In the Web.config that value is perfectly configured
<services>
<service name="MyService.Service.MyService">
<endpoint address="" behaviorConfiguration="MexFlatWsdlBehavior"
binding="basicHttpBinding" bindingConfiguration="secureHttpBinding"
name="TpsNotification" bindingNamespace="http://org.com/MyService/2014/11"
contract="MyService.Service.ISomeEndpoint">
<identity>
<dns value="THESERVER.myorg.net" />
</identity>
</endpoint>
<endpoint address="" behaviorConfiguration="MexFlatWsdlBehavior"
binding="basicHttpBinding" bindingConfiguration="secureHttpBinding"
name="TpsPluginFramework" bindingNamespace="http://org.com/MyService/2014/11"
contract="MyService.Service.IOtherEndpoint">
<identity>
<dns value="THESERVER.myorg.net" />
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="https://THESERVER.myorg.net:443/MyService.svc" />
</baseAddresses>
</host>
</service>
</services>
Any of dns value or baseAddress would be perfectly fine.
But I see no way to get to that value from IIS.
I tried ConfigurationManager and WebConfiguration and HostingEnvironment.
Furthermore I tried
var hostName = System.Net.Dns.GetHostName();
which works for some cases, but not for this server, because the configured address is not the primary dns address, which is returned here.
Any options?
Try loading the config file in to a linq to xml doc, then you can query it all you want ...
var config = XDocument.Load("Web.Config");
var baseAddress = config.Elements("baseAddresses")
.Elements()
.First()
.Attribute("baseAddress")
.Value;
If all else fails, use the brute force approach :)
Another option might be ...
Since you are in the context of a request to a server why not use the request object ...
var host = Request.Url.Host;
That was simpler!
Related
I'm trying to develop a service with WCF but I can't find the certificate that I created, this certificate is located under TrustedPeple folder. So far this is my chunk of code that I wrote:
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(
StoreLocation.CurrentUser,
StoreName.My,
X509FindType.FindBySubjectName,
"WCfClient");
As you can see from the above code, I also tried to manually set the certificate characteristics but I still can't find it.
Also I'll post a portion of my conif xml file for a better understanding:
<services>
<service
name="XMLServices.CriDecServices.CriDecService"
behaviorConfiguration="wsHttpCertificateBehavior">
<endpoint name="CriDecPoint"
address=""
binding="wsHttpBinding"
bindingConfiguration="wsHttpEndpointBinding"
contract="XMLContracts.ServiceContracts.ICriDecService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/XMLServices/CriDecServices/CriDecService" />
</baseAddresses>
</host>
</service>
<service
name="XMLServices.UtenteServices.UtenteService"
behaviorConfiguration="wsHttpCertificateBehavior">
<endpoint
name="UserPoint"
address=""
binding="wsHttpBinding"
bindingConfiguration="wsHttpEndpointBinding"
contract="XMLContracts.ServiceContracts.IUtenteService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8766/XMLServices/UtenteServices/UtenteService" />
</baseAddresses>
</host>
</service>
</services>
This is the exception that I get:
"Client certificate not given. Specify a client certificate in ClientCredentials."
Can anyone help me out to understand why I can't seem to find my certificate? Thanks
If you look here you'll see that the store you are trying to use isn't the one from the trusted people folder but the one from the personal folder
you should use
StoreName.TrustedPeople
look here for more details https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.storename(v=vs.110).asp
also most likely you need StoreLocation.LocalMachine.
I have client endpoints as below in my web.config, we have production server located geographically for e.g. America, Europe, Asia etc and all have their own base uri.
e.g. web.config is as below
<client>
<endpoint address="http://localhost:9000/ServiceA.svc" binding="wsHttpBinding" contract="IServiceA" name="ServiceA"></endpoint>
<endpoint address="http://localhost:9000/ServiceB.svc" binding="wsHttpBinding" contract="IServiceA" name="ServiceB"></endpoint>
<endpoint address="http://localhost:9000/ServiceC.svc" binding="wsHttpBinding" contract="IServiceA" name="ServiceC"></endpoint>
<endpoint address="http://localhost:9000/ServiceD.svc" binding="wsHttpBinding" contract="IServiceA" name="ServiceD"></endpoint>
<endpoint address="http://localhost:9000/ServiceE.svc" binding="wsHttpBinding" contract="IServiceA" name="ServiceE"></endpoint>
For Ameria region I have Web.America.config but it should be transformed as below
<client>
<endpoint xdt:Transform="SetAttributes(address)" xdt:Locator="Match(name)" address="http://localhost:9000/america/ServiceA.svc" name="ServiceA"></endpoint>
<endpoint xdt:Transform="SetAttributes(address)" xdt:Locator="Match(name)" address="http://localhost:9000/america/ServiceB.svc" name="ServiceB"></endpoint>
...
...
But I don't want this duplication as I only need to change base address. Is there any better way of doing this?
This is my server-side app.config:
<services>
<service name="PokerService.PlayerService" behaviorConfiguration="ServiceBehaviorPlayer">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:5054" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<endpoint address="player" binding="netTcpBinding" bindingConfiguration="PlayerBinding" contract="PokerService.IPlayerService" />
<endpoint address="player/mex" binding="mexTcpBinding" name="ServiceBehaviorPlayer" contract="IMetadataExchange" />
</service>
</services>
And I am generating dynamic endpoint in client-side code:
ServiceHost host = new ServiceHost(typeof(PokerService.PlayerService));
NetTcpBinding binding = new NetTcpBinding(SecurityMode.Message);
binding.Name = "NetTcpBinding_IPlayerService";
binding.Security.Message.ClientCredentialType = MessageCredentialType.IssuedToken;
ServiceEndpoint ep = host.AddServiceEndpoint(
typeof(PokerService.IPlayerService),
binding,
"net.tcp://localhost:5054");
EndpointAddress myEndpointAdd = new EndpointAddress(new Uri("net.tcp://localhost:5054/player1"),
EndpointIdentity.CreateDnsIdentity("pident.cloudapp.net"));
ep.Address = myEndpointAdd;
For service testing code:
var PlayerChannelFactory = new DuplexChannelFactory<ClientApplication.PlayerService.IPlayerService>(new PlayerHandler(handler, this), binding, ep.Address);
PlayerChannelFactory.Credentials.SupportInteractive = false;
PlayerChannelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
PlayerServiceProxy = PlayerChannelFactory.CreateChannelWithIssuedToken(User.Instance.userToken);
Now I am getting this error
Any idea?
Client config file looks as below:
<client>
<endpoint address="net.tcp://localhost:5054/player" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IPlayerService" contract="PlayerService.IPlayerService" name="NetTcpBinding_IPlayerService">
<identity>
<dns value="pident.cloudapp.net"/>
</identity>
</endpoint>
</client>
Since you can host several services on same address (using port sharing,...) - your service endpoint address is define "which of the services you are looking for".
So, as #Backlash also mentioned, your client's uri should point to right server address.
I also think that your have a endpoint mismatch between service and client. Try:
new EndpointAddress(new Uri("net.tcp://localhost:5054/player")
How does the client config file look like?
Every time my program runs vs adds the default configuration to my app.config file. At that run it works fine, but at the next run it actually tries to read the config.
The problem is that the default configuration has errors, it adds the attribute "Address", but attritbutes are not allowed to have capitals so it throws an exception.
This means I have to remove the bad section every run!
I've tried to configure the .config but it gives errors.
Here is the code that I use to host the server:
private static System.Threading.AutoResetEvent stopFlag = new System.Threading.AutoResetEvent(false);
ServiceHost host = new ServiceHost(typeof(Service), new Uri("http://localhost:8000"));
host.AddServiceEndpoint(typeof(IService), new BasicHttpBinding(), "ChessServer");
host.Open();
stopFlag.WaitOne();
host.Close();
Here is the client code that calls the server:
ChannelFactory<IChessServer> scf;
scf = new ChannelFactory<IService>
(new BasicHttpBinding(), "http://localhost:8000");
IService service = scf.CreateChannel();
Thanks for any help.
Edit: Sorry it took me so long, I've been trying to use DualWSHttpBinding instead (since I actually need the server to call client methods to anyway) but still generates the config file. Here's the entire auto-generated config file:
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup><system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Chess.ChessService">
<endpoint Address="" binding="wsHttpBinding" contract="Chess.IChessServer">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint Address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<Add baseAddress="http://localhost:8732/Design_Time_Addresses/Chess/ChessService/" />
</baseAddresses>
</host>
</service>
<service name="Chess.ChessClient">
<endpoint Address="" binding="wsHttpBinding" contract="Chess.IChessClient">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint Address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<Add baseAddress="http://localhost:8732/Design_Time_Addresses/Chess/ChessClient/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
Visual Studio does not re-create the WCF configuration on every run. It will re-create the WCF configuration every time you do an Update Service Reference on your service reference in the project - but it definitely doesn't automatically do that before every run - there must be something else causing you grief here.
Furthermore, you're not connecting to the correct address - your server defines it here:
ServiceHost host = new ServiceHost(..., new Uri("http://localhost:8000"));
host.AddServiceEndpoint(..., .., "ChessServer");
and this results in your endpoint address on the server being
http://localhost:8000/ChessServer
However, you're client appears to attempt to connect to
http://localhost:8000/
and there's no service there.
A last point: if you set up all your things like endpoints, bindings etc. in code, any changes to the config shouldn't even bother you at all - there must be something else causing your problems.
You're quite mistaken. Attribute and element names may be upper or lower case.
What makes you think that the case of the attribute is the problem? And what makes you think that the app.config is changed on every run?
In the following config file excerpt, the WCF service has two endpoints.
<service behaviorConfiguration="AtomTcpHub.Behavior"
name="AtomTcpHub.HubTcp">
<endpoint address="" binding="netTcpBinding"
name="AtomHubEndpoint" contract="AtomLib.IAtomPublisher">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding"
name="" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8731/AtomTcpHub/" />
<add baseAddress="net.tcp://dv-pw/AtomTcpHub/" />
</baseAddresses>
</host>
</service>
In my code there is discovery logic, which responds to a UDP request by replying with the connection Uri for the WCF service. Obtaining a collection of endpoints is straightforward.
System.Configuration.Configuration config = System.Configuration
.ConfigurationManager
.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None);
ServicesSection section = config.SectionGroups["system.serviceModel"]
.Sections["services"] as ServicesSection;
ServiceEndpointElementCollection seec =
section.Services["AtomTcpHub.HubTcp"].Endpoints;
The problem is extracting the ServiceEndpointElement. We can have it by index:
ServiceEndpointElement see = seec[0];
but this is brittle; if the order of nodes changes it will break. Visual Studio tells me there is another indexer permitting an object value, but there is no further indication. Experimentation tells me that it isn't the value of the name attribute.
The following code works, but it's just hideous.
string serviceEndpointUri;
foreach(ServiceEndpointElement serviceEndpointElement in seec)
if (serviceEndpointElement.Name == "AtomHubEndpoint")
{
_serviceEndpointUri = serviceEndpointElement.Address.AbsoluteUri;
break;
}
Is there a more direct or more elegant way to do this?
You could always use some Linq to accomplish this, to simply shorten things a bit.
ServiceEndpointElement element =
seec.OfType<ServiceEndpointElement>()
.FirstOrDefault(s => s.Name == "AtomHubEndpoint");