I have the need to add to my app.config file this section while my program is running
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="InvioTelematicoSS730pMtomPortBinding" messageEncoding="Mtom">
<security mode="Transport" />
</binding>
<binding name="RicevutaPdf730PortBinding">
<security mode="Transport" />
</binding>
<binding name="RicevutaPdf730PortBinding1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:9080/InvioTelematicoSS730pMtomWeb/InvioTelematicoSS730pMtomPort"
binding="basicHttpBinding" bindingConfiguration="InvioTelematicoSS730pMtomPortBinding"
contract="InvioFlussi730.InvioTelematicoSS730pMtom" name="InvioTelematicoSS730pMtomPort" />
<endpoint address="https://invioSS730pTest.sanita.finanze.it/Ricevute730ServiceWeb/ricevutePdf"
binding="basicHttpBinding" bindingConfiguration="RicevutaPdf730PortBinding"
contract="ServiceReference1.RicevutaPdf730" name="RicevutaPdf730Port" />
</client>
is there any way possible? Thanks in advance
.NET exposes configuration element classes for WCF services to manage them at runtime. Wrote a simple method to construct and generate the sections for you.
private static void WriteWCFConfig()
{
//standard method from System.Configuration
Configuration appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//the main section in the app.config file for WCF
ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(appConfig);
var httpBindings = serviceModel.Bindings.BasicHttpBinding;
if (!httpBindings.ContainsKey("InvioTelematicoSS730pMtomPortBinding"))
{
BasicHttpBindingElement newHttpBindng = new BasicHttpBindingElement("InvioTelematicoSS730pMtomPortBinding");
newHttpBindng.MessageEncoding = WSMessageEncoding.Mtom;
newHttpBindng.Security.Mode = BasicHttpSecurityMode.Transport;
httpBindings.Bindings.Add(newHttpBindng);
}
if (!httpBindings.ContainsKey("RicevutaPdf730PortBinding"))
{
BasicHttpBindingElement newHttpBindng = new BasicHttpBindingElement("RicevutaPdf730PortBinding");
newHttpBindng.MessageEncoding = WSMessageEncoding.Mtom;
newHttpBindng.Security.Mode = BasicHttpSecurityMode.Transport;
httpBindings.Bindings.Add(newHttpBindng);
}
//the section
ChannelEndpointElementCollection endPoints = serviceModel.Client.Endpoints;
//Get endpoint names
List<string> endpointNames = new List<string>();
foreach (ChannelEndpointElement endpointElement in endPoints)
{
endpointNames.Add(endpointElement.Name);
}
if (!endpointNames.Contains("InvioTelematicoSS730pMtomPort"))
{
ChannelEndpointElement endPoint = new ChannelEndpointElement(new EndpointAddress("http://localhost:9080/InvioTelematicoSS730pMtomWeb/InvioTelematicoSS730pMtomPort"), "InvioFlussi730.InvioTelematicoSS730pMtom");
endPoint.Name = "InvioTelematicoSS730pMtomPort";
endPoint.Binding = "basicHttpBinding";
endPoint.BindingConfiguration = "InvioTelematicoSS730pMtomPortBinding";
endPoints.Add(endPoint);
}
if (!endpointNames.Contains("RicevutaPdf730Port"))
{
ChannelEndpointElement endPoint = new ChannelEndpointElement(new EndpointAddress("https://invioSS730pTest.sanita.finanze.it/Ricevute730ServiceWeb/ricevutePdf"), "ServiceReference1.RicevutaPdf730");
endPoint.Name = "RicevutaPdf730Port";
endPoint.Binding = "basicHttpBinding";
endPoint.BindingConfiguration = "RicevutaPdf730PortBinding";
endPoints.Add(endPoint);
}
appConfig.Save();
}
You can take it and modify it according to your needs.
Hope this helps.
Related
I have an app.config to call this service from .Net framework but now I have to do the same from core app. Here's the WCF client config:
<bindings>
<ws2007FederationHttpBinding>
<binding name="WS2007FederationHttpBinding_certificate" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="128" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
<security mode="TransportWithMessageCredential">
<message establishSecurityContext="false" negotiateServiceCredential="true">
<claimTypeRequirements>
<add claimType="http://docs.oasis-open.org/wsfed/authorization/200706/claims/action" isOptional="true"/>
<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" isOptional="false"/>
<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/role"/>
</claimTypeRequirements>
<issuer address="https://some.url.com/STS/Issue.svc/trust/13/certificatemixed" binding="ws2007HttpBinding"
bindingConfiguration="certificateMixed"/>
<issuerMetadata address="https://some.url.com/STS/Issue.svc/mex"/>
<!-- THIS IS THE PROBLEM PART -->
<tokenRequestParameters>
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<EndpointReference xmlns="http://www.w3.org/2005/08/addressing">
<Address>URN:MY.TEST.SERVICE</Address>
</EndpointReference>
</wsp:AppliesTo>
</tokenRequestParameters>
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
<ws2007HttpBinding>
<binding name="certificateMixed">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" establishSecurityContext="false"/>
</security>
</binding>
</ws2007HttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="behaviorSECertificate">
<clientCredentials>
<clientCertificate findValue="ab cd .. b4" storeLocation="LocalMachine" storeName="My"
x509FindType="FindByThumbprint"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
Pretty basic stuff. So now I do the same in .Net core code:
var issuerBinding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential);
issuerBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
issuerBinding.Security.Message.EstablishSecurityContext = false;
issuerBinding.Name = "certificateMixed";
var prm = new WsTrustTokenParameters
{
IssuerBinding = issuerBinding,
IssuerAddress = new EndpointAddress(_seOptions.STSEndpoint),
MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10,
EstablishSecurityContext = false,
};
prm.ClaimTypes.Add(new ClaimType() { Uri = "http://docs.oasis-open.org/wsfed/authorization/200706/claims/action", IsOptional = true });
prm.ClaimTypes.Add(new ClaimType() { Uri = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier", IsOptional = false });
prm.ClaimTypes.Add(new ClaimType() { Uri = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role", IsOptional = true });
var binding = new WsFederationHttpBinding(prm);
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = true;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
ChannelFactory<IMyService> factory = new ChannelFactory<IMyService>(binding, new EndpointAddress(_seOptions.MyServiceUrl));
var cert = GetClientCertificate(); //X509Certificate2
var x = factory.Endpoint.EndpointBehaviors[typeof(ClientCredentials)];
((ClientCredentials)x).ClientCertificate.Certificate = cert;
IMyService client = factory.CreateChannel(new EndpointAddress(_seOptions.MyServiceUrl));
So the main question is- how do I add the tokenRequestParameters/AppliesTo section in code? I assume it would be something like this:
RequestSecurityToken tk = new RequestSecurityToken() { AppliesTo = new EndpointAddress("URN:MY.TEST.SERVICE") };
But I have no idea what to assign this object to.
RequestSecurityToken class is not applicable to .net core, you can see its support on this page: RequestSecurityToken Class. So you need to find a replacement for it in .net core. You can refer to Overview of porting from .NET Framework to .NET Core to consider how to migrate from .net framework to .net core. Hope my answer will help you.
I am trying to read service configuration in Class Library from the app.config file of the library. but getting below exception
Could not find endpoint element with name 'WSHttpBinding_IUsers' and contract 'ISGP.Plugins.SolveService.IUsers'
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 tried ti implement the below code to read the config and create the client
public class ServiceManager
{
public static T CreateServiceClient<T>(string configName)
{
// string _assemblyLocation = Assembly.GetExecutingAssembly().Location;
var configuration = ConfigurationManager.OpenMappedExeConfiguration(
new ExeConfigurationFileMap
{
ExeConfigFilename = "app.config"
}, ConfigurationUserLevel.None);
ConfigurationChannelFactory<T> channelFactory = new ConfigurationChannelFactory<T>(configName, configuration, null);
var client = channelFactory.CreateChannel();
return client;
}
}
Call this method as below
usersClient= (UsersClient)ServiceManager.CreateServiceClient<IUsersChannel>("WSHttpBinding_IUsers");
usersClient.ClientCredentials.UserName.UserName = userName;
usersClient.ClientCredentials.UserName.Password = password;
But it throws the above exception the app.config file is as below
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IUsers">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://xxxxxx16.prod.xxxxx.local/WebServices/v3/Users.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IUsers"
contract="ISGP.Plugins.SolveService.IUsers" name="WSHttpBinding_IUsers" />
</client>
</system.serviceModel>
Please pass the endpoint parameter in the channel factory constructor.
ConfigurationChannelFactory channelFactory = new
ConfigurationChannelFactory(configName, configuration, null);
You can refer to the following code.
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = "app.config";
Configuration newConfiguration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
ConfigurationChannelFactory<IService> factory = new ConfigurationChannelFactory<IService>("endpoint1", newConfiguration, new EndpointAddress("http://localhost:8000/servicemodelsamples/service"));
factory.Credentials.UserName.UserName = "jack";
factory.Credentials.UserName.Password = "123456";
IService client1 = factory.CreateChannel();
https://learn.microsoft.com/en-us/dotnet/framework/wcf/samples/configuration-channel-factory
Feel free to let me know if there is anything I can help with.
I m trying to create end point configuration Programmatically, below is the config file generated, I want to create same configuration using c# programmatically.I want to set bindingConfiguration,contract,name,binding,address through programatically.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IFakeService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:55536/FakeService.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IFakeService" contract="ChannelAdam.Wcf.BehaviourSpecs.TestDoubles.IFakeService" name="BasicHttpBinding_IFakeService" />
</client>
</system.serviceModel>
var binding = new BasicHttpBinding() {
Name = "BasicHttpBinding_IFakeService",
MaxBufferSize = 2147483647,
MaxReceivedMessageSize = 2147483647
};
var endpoint = new EndpointAddress("http://localhost:55536/FakeService.svc");
MyInterfaceClient client = new MyInterfaceClient(binding, endpoint);
I have my first WCF example working. I have the host on a website which have many bindings. Because of this, I have added this to my web.config.
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
This is my default binding http://id.web, which works with the following code.
EchoServiceClient client = new EchoServiceClient();
litResponse.Text = client.SendEcho("Hello World");
client.Close();
I am now trying to set the endpoint address at runtime. Even though it is the same address of the above code.
EchoServiceClient client = new EchoServiceClient();
client.Endpoint.Address = new EndpointAddress("http://id.web/Services/EchoService.svc");
litResponse.Text = client.SendEcho("Hello World");
client.Close();
The error I get is:
The request for security token could not be satisfied because authentication failed.
Please suggest how I may change the endpoint address at runtime?
Additional here is my client config, requested by Ladislav Mrnka
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IEchoService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://id.web/Services/EchoService.svc" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IEchoService" contract="IEchoService"
name="WSHttpBinding_IEchoService">
<identity>
<servicePrincipalName value="host/mikev-ws" />
</identity>
</endpoint>
</client>
</system.serviceModel>
So your endpoint address defined in your first example is incomplete. You must also define endpoint identity as shown in client configuration. In code you can try this:
EndpointIdentity spn = EndpointIdentity.CreateSpnIdentity("host/mikev-ws");
var address = new EndpointAddress("http://id.web/Services/EchoService.svc", spn);
var client = new EchoServiceClient(address);
litResponse.Text = client.SendEcho("Hello World");
client.Close();
Actual working final version by valamas
EndpointIdentity spn = EndpointIdentity.CreateSpnIdentity("host/mikev-ws");
Uri uri = new Uri("http://id.web/Services/EchoService.svc");
var address = new EndpointAddress(uri, spn);
var client = new EchoServiceClient("WSHttpBinding_IEchoService", address);
client.SendEcho("Hello World");
client.Close();
This is a simple example of what I used for a recent test.
You need to make sure that your security settings are the same on the server and client.
var myBinding = new BasicHttpBinding();
myBinding.Security.Mode = BasicHttpSecurityMode.None;
var myEndpointAddress = new EndpointAddress("http://servername:8732/TestService/");
client = new ClientTest(myBinding, myEndpointAddress);
client.someCall();
app.config
<client>
<endpoint address="" binding="basicHttpBinding"
bindingConfiguration="LisansSoap"
contract="Lisans.LisansSoap"
name="LisansSoap" />
</client>
program
Lisans.LisansSoapClient test = new LisansSoapClient("LisansSoap",
"http://webservis.uzmanevi.com/Lisans/Lisans.asmx");
MessageBox.Show(test.LisansKontrol("","",""));
We store our URLs in a database and load them at runtime.
public class ServiceClientFactory<TChannel> : ClientBase<TChannel> where TChannel : class
{
public TChannel Create(string url)
{
this.Endpoint.Address = new EndpointAddress(new Uri(url));
return this.Channel;
}
}
Implementation
var client = new ServiceClientFactory<yourServiceChannelInterface>().Create(newUrl);
I have a WCF service reference which I use with the following client side app.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ManagerService">
<security>
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://myadress:8080/ManagerService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ManagerService"
contract="Service.ManagerService" name="WSHttpBinding_ManagerService">
<identity>
<certificate encodedValue="AwAAAAEAAAAUAAAAaJ8gJ+2BbDC//Nw76gp1Rx4Ii1AgAAAAAQAAACQDAAAwggMgMIICDKADAgECAhB4jlXUsVcUkE45Bq9sj6cdMAkGBSsOAwIdBQAwIzEhMB8GA1UEAxMYc2tpbGxjb25vbXkuY2xvdWRhcHAubmV0MB4XDTA2MTIzMTIyMDAwMFoXDTE5MTIzMTIyMDAwMFowIzEhMB8GA1UEAxMYc2tpbkjsahdjhdjsdhsjhdsjhdjhdsjhdFAAOCAQ8AMIIBCgKCAQEAwHjDPi/A7+4PfvYt40eySE2I6FgVO2Ewco8gJO21TUqHpKbinmsaNTO6wFJy+l3adMRB0dcmAvH938BPgdwbqbVaaG4mRCDpnekEserWmz5ii+ET1xhm0atIg6xW3sgnDOA+41Y0vB8m8AXTfHQYunILQjn/6xGM/RffK32vbR9WGJKEd/okOJ2/vV5dm2UsejlANwK2kCMe9wNRbjaKsH6PIqv26KeHAXxa0tSzoHfrn/lr46+54WzEXFHRzub1JbZk+IsdsdlakasjdksjdjdksjddjskdZZ0Oj0iG0GjvEVbmHWpBM/WhHrqIfGdqiMtXjOtwIDAQAsdsdsdsdsdsdsdaZtgIq+y6hm91EfPUToJ1ZUhWR8z/RG+IVZrs0O93FCMk6WU8OhYxubIgcVSTx0FDCakyOmfu1gnYeEZv53kVPZSmY4KUAUZz+MCQf/OXN2OGv9cRmsWg4iDlHjzDQwucO+rWkclvQo=" />
</identity>
</endpoint>
</client>
</system.serviceModel>
I now need to refactor the instantiation to work with a blank app.config:
Here is what I've tried:
var binding = new WSHttpBinding();
binding.Security = new WSHttpSecurity { Mode = SecurityMode.Message };
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var cers = store.Certificates.Find(X509FindType.FindByThumbprint, "123THUMBPRINTOFCERT", false);
var cer = cers[0];
var identity = new X509CertificateEndpointIdentity(cer);
var endpoint = new EndpointAddress(new Uri("http://myservice:8080/ManagerService.svc"), identity);
var client = new ManagerServiceClient(binding, endpoint);
client.ClientCredentials.UserName.UserName = EMail;
client.ClientCredentials.UserName.Password = Password;
var resultBuilder = new StringBuilder();
var categories = client.Categorize(Text);
This throws an exception:
System.ServiceModel.Security.MessageSecurityException: Client cannot
determine the Service Principal Name based on the identity in the
target address 'http://myservice:8080/ManagerService.svc' for
the purpose of SspiNegotiation/Kerberos. The target address identity
must be a UPN identity (like acmedomain\alice) or SPN identity (like
host/bobs-machine).
I have checked, that the correct certificate is found in the store. I would be very glad to get a hint on what I am missing here and whether the way I'm going here is ok in general...?
you lost row clientCredentialType="UserName"
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;